<commit_before>#![stable(feature = "core_hint", since = "1.27.0")]

//! Hints to compiler that affects how code should be emitted or optimized.
//! Hints may be compile time or runtime.

use crate::intrinsics;

/// Informs the compiler that this point in the code is not reachable, enabling
/// further optimizations.
///
/// # Safety
///
/// Reaching this function is completely *undefined behavior* (UB). In
/// particular, the compiler assumes that all UB must never happen, and
/// therefore will eliminate all branches that reach to a call to
/// `unreachable_unchecked()`.
///
/// Like all instances of UB, if this assumption turns out to be wrong, i.e., the
/// `unreachable_unchecked()` call is actually reachable among all possible
/// control flow, the compiler will apply the wrong optimization strategy, and
/// may sometimes even corrupt seemingly unrelated code, causing
/// difficult-to-debug problems.
///
/// Use this function only when you can prove that the code will never call it.
/// Otherwise, consider using the [`unreachable!`] macro, which does not allow
/// optimizations but will panic when executed.
///
/// # Example
///
/// ```
/// fn div_1(a: u32, b: u32) -> u32 {
///     use std::hint::unreachable_unchecked;
///
///     // `b.saturating_add(1)` is always positive (not zero),
///     // hence `checked_div` will never return `None`.
///     // Therefore, the else branch is unreachable.
///     a.checked_div(b.saturating_add(1))
///         .unwrap_or_else(|| unsafe { unreachable_unchecked() })
/// }
///
/// assert_eq!(div_1(7, 0), 7);
/// assert_eq!(div_1(9, 1), 4);
/// assert_eq!(div_1(11, u32::MAX), 0);
/// ```
#[inline]
#[stable(feature = "unreachable", since = "1.27.0")]
#[rustc_const_unstable(feature = "const_unreachable_unchecked", issue = "53188")]
pub const unsafe fn unreachable_unchecked() -> ! {
    // SAFETY: the safety contract for `intrinsics::unreachable` must
    // be upheld by the caller.
    unsafe { intrinsics::unreachable() }
}

/// Emits a machine instruction to signal the processor that it is running in
/// a busy-wait spin-loop ("spin lock").
///
/// Upon receiving the spin-loop signal the processor can optimize its behavior by,
/// for example, saving power or switching hyper-threads.
///
/// This function is different from [`thread::yield_now`] which directly
/// yields to the system's scheduler, whereas `spin_loop` does not interact
/// with the operating system.
///
/// A common use case for `spin_loop` is implementing bounded optimistic
/// spinning in a CAS loop in synchronization primitives. To avoid problems
/// like priority inversion, it is strongly recommended that the spin loop is
/// terminated after a finite amount of iterations and an appropriate blocking
/// syscall is made.
///
/// **Note**: On platforms that do not support receiving spin-loop hints this
/// function does not do anything at all.
///
/// # Examples
///
/// ```
/// use std::sync::atomic::{AtomicBool, Ordering};
/// use std::sync::Arc;
/// use std::{hint, thread};
///
/// // A shared atomic value that threads will use to coordinate
/// let live = Arc::new(AtomicBool::new(false));
///
/// // In a background thread we'll eventually set the value
/// let bg_work = {
///     let live = live.clone();
///     thread::spawn(move || {
///         // Do some work, then make the value live
///         do_some_work();
///         live.store(true, Ordering::Release);
///     })
/// };
///
/// // Back on our current thread, we wait for the value to be set
/// while live.load(Ordering::Acquire) {
///     // The spin loop is a hint to the CPU that we're waiting, but probably
///     // not for very long
///     hint::spin_loop();
/// }
///
/// // The value is now set
/// # fn do_some_work() {}
/// do_some_work();
/// bg_work.join()?;
/// # Ok::<(), Box<dyn core::any::Any + Send + 'static>>(())
/// ```
///
/// [`thread::yield_now`]: ../../std/thread/fn.yield_now.html
#[inline]
#[stable(feature = "renamed_spin_loop", since = "1.49.0")]
pub fn spin_loop() {
    #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "sse2"))]
    {
        #[cfg(target_arch = "x86")]
        {
            // SAFETY: the `cfg` attr ensures that we only execute this on x86 targets.
            unsafe { crate::arch::x86::_mm_pause() };
        }

        #[cfg(target_arch = "x86_64")]
        {
            // SAFETY: the `cfg` attr ensures that we only execute this on x86_64 targets.
            unsafe { crate::arch::x86_64::_mm_pause() };
        }
    }

    #[cfg(any(target_arch = "aarch64", all(target_arch = "arm", target_feature = "v6")))]
    {
        #[cfg(target_arch = "aarch64")]
        {
            // SAFETY: the `cfg` attr ensures that we only execute this on aarch64 targets.
            unsafe { crate::arch::aarch64::__yield() };
        }
        #[cfg(target_arch = "arm")]
        {
            // SAFETY: the `cfg` attr ensures that we only execute this on arm targets
            // with support for the v6 feature.
            unsafe { crate::arch::arm::__yield() };
        }
    }
}

/// An identity function that *__hints__* to the compiler to be maximally pessimistic about what
/// `black_box` could do.
///
/// Unlike [`std::convert::identity`], a Rust compiler is encouraged to assume that `black_box` can
/// use `dummy` in any possible valid way that Rust code is allowed to without introducing undefined
/// behavior in the calling code. This property makes `black_box` useful for writing code in which
/// certain optimizations are not desired, such as benchmarks.
///
/// Note however, that `black_box` is only (and can only be) provided on a "best-effort" basis. The
/// extent to which it can block optimisations may vary depending upon the platform and code-gen
/// backend used. Programs cannot rely on `black_box` for *correctness* in any way.
///
/// [`std::convert::identity`]: crate::convert::identity
#[cfg_attr(not(miri), inline)]
#[cfg_attr(miri, inline(never))]
#[unstable(feature = "test", issue = "50297")]
#[cfg_attr(miri, allow(unused_mut))]
pub fn black_box<T>(mut dummy: T) -> T {
    // We need to "use" the argument in some way LLVM can't introspect, and on
    // targets that support it we can typically leverage inline assembly to do
    // this. LLVM's interpretation of inline assembly is that it's, well, a black
    // box. This isn't the greatest implementation since it probably deoptimizes
    // more than we want, but it's so far good enough.

    #[cfg(not(miri))] // This is just a hint, so it is fine to skip in Miri.
    // SAFETY: the inline assembly is a no-op.
    unsafe {
        // FIXME: Cannot use `asm!` because it doesn't support MIPS and other architectures.
        llvm_asm!("" : : "r"(&mut dummy) : "memory" : "volatile");
    }

    dummy
}
<commit_msg>Fixed documentation error<commit_after>#![stable(feature = "core_hint", since = "1.27.0")]

//! Hints to compiler that affects how code should be emitted or optimized.
//! Hints may be compile time or runtime.

use crate::intrinsics;

/// Informs the compiler that this point in the code is not reachable, enabling
/// further optimizations.
///
/// # Safety
///
/// Reaching this function is completely *undefined behavior* (UB). In
/// particular, the compiler assumes that all UB must never happen, and
/// therefore will eliminate all branches that reach to a call to
/// `unreachable_unchecked()`.
///
/// Like all instances of UB, if this assumption turns out to be wrong, i.e., the
/// `unreachable_unchecked()` call is actually reachable among all possible
/// control flow, the compiler will apply the wrong optimization strategy, and
/// may sometimes even corrupt seemingly unrelated code, causing
/// difficult-to-debug problems.
///
/// Use this function only when you can prove that the code will never call it.
/// Otherwise, consider using the [`unreachable!`] macro, which does not allow
/// optimizations but will panic when executed.
///
/// # Example
///
/// ```
/// fn div_1(a: u32, b: u32) -> u32 {
///     use std::hint::unreachable_unchecked;
///
///     // `b.saturating_add(1)` is always positive (not zero),
///     // hence `checked_div` will never return `None`.
///     // Therefore, the else branch is unreachable.
///     a.checked_div(b.saturating_add(1))
///         .unwrap_or_else(|| unsafe { unreachable_unchecked() })
/// }
///
/// assert_eq!(div_1(7, 0), 7);
/// assert_eq!(div_1(9, 1), 4);
/// assert_eq!(div_1(11, u32::MAX), 0);
/// ```
#[inline]
#[stable(feature = "unreachable", since = "1.27.0")]
#[rustc_const_unstable(feature = "const_unreachable_unchecked", issue = "53188")]
pub const unsafe fn unreachable_unchecked() -> ! {
    // SAFETY: the safety contract for `intrinsics::unreachable` must
    // be upheld by the caller.
    unsafe { intrinsics::unreachable() }
}

/// Emits a machine instruction to signal the processor that it is running in
/// a busy-wait spin-loop ("spin lock").
///
/// Upon receiving the spin-loop signal the processor can optimize its behavior by,
/// for example, saving power or switching hyper-threads.
///
/// This function is different from [`thread::yield_now`] which directly
/// yields to the system's scheduler, whereas `spin_loop` does not interact
/// with the operating system.
///
/// A common use case for `spin_loop` is implementing bounded optimistic
/// spinning in a CAS loop in synchronization primitives. To avoid problems
/// like priority inversion, it is strongly recommended that the spin loop is
/// terminated after a finite amount of iterations and an appropriate blocking
/// syscall is made.
///
/// **Note**: On platforms that do not support receiving spin-loop hints this
/// function does not do anything at all.
///
/// # Examples
///
/// ```
/// use std::sync::atomic::{AtomicBool, Ordering};
/// use std::sync::Arc;
/// use std::{hint, thread};
///
/// // A shared atomic value that threads will use to coordinate
/// let live = Arc::new(AtomicBool::new(false));
///
/// // In a background thread we'll eventually set the value
/// let bg_work = {
///     let live = live.clone();
///     thread::spawn(move || {
///         // Do some work, then make the value live
///         do_some_work();
///         live.store(true, Ordering::Release);
///     })
/// };
///
/// // Back on our current thread, we wait for the value to be set
/// while !live.load(Ordering::Acquire) {
///     // The spin loop is a hint to the CPU that we're waiting, but probably
///     // not for very long
///     hint::spin_loop();
/// }
///
/// // The value is now set
/// # fn do_some_work() {}
/// do_some_work();
/// bg_work.join()?;
/// # Ok::<(), Box<dyn core::any::Any + Send + 'static>>(())
/// ```
///
/// [`thread::yield_now`]: ../../std/thread/fn.yield_now.html
#[inline]
#[stable(feature = "renamed_spin_loop", since = "1.49.0")]
pub fn spin_loop() {
    #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "sse2"))]
    {
        #[cfg(target_arch = "x86")]
        {
            // SAFETY: the `cfg` attr ensures that we only execute this on x86 targets.
            unsafe { crate::arch::x86::_mm_pause() };
        }

        #[cfg(target_arch = "x86_64")]
        {
            // SAFETY: the `cfg` attr ensures that we only execute this on x86_64 targets.
            unsafe { crate::arch::x86_64::_mm_pause() };
        }
    }

    #[cfg(any(target_arch = "aarch64", all(target_arch = "arm", target_feature = "v6")))]
    {
        #[cfg(target_arch = "aarch64")]
        {
            // SAFETY: the `cfg` attr ensures that we only execute this on aarch64 targets.
            unsafe { crate::arch::aarch64::__yield() };
        }
        #[cfg(target_arch = "arm")]
        {
            // SAFETY: the `cfg` attr ensures that we only execute this on arm targets
            // with support for the v6 feature.
            unsafe { crate::arch::arm::__yield() };
        }
    }
}

/// An identity function that *__hints__* to the compiler to be maximally pessimistic about what
/// `black_box` could do.
///
/// Unlike [`std::convert::identity`], a Rust compiler is encouraged to assume that `black_box` can
/// use `dummy` in any possible valid way that Rust code is allowed to without introducing undefined
/// behavior in the calling code. This property makes `black_box` useful for writing code in which
/// certain optimizations are not desired, such as benchmarks.
///
/// Note however, that `black_box` is only (and can only be) provided on a "best-effort" basis. The
/// extent to which it can block optimisations may vary depending upon the platform and code-gen
/// backend used. Programs cannot rely on `black_box` for *correctness* in any way.
///
/// [`std::convert::identity`]: crate::convert::identity
#[cfg_attr(not(miri), inline)]
#[cfg_attr(miri, inline(never))]
#[unstable(feature = "test", issue = "50297")]
#[cfg_attr(miri, allow(unused_mut))]
pub fn black_box<T>(mut dummy: T) -> T {
    // We need to "use" the argument in some way LLVM can't introspect, and on
    // targets that support it we can typically leverage inline assembly to do
    // this. LLVM's interpretation of inline assembly is that it's, well, a black
    // box. This isn't the greatest implementation since it probably deoptimizes
    // more than we want, but it's so far good enough.

    #[cfg(not(miri))] // This is just a hint, so it is fine to skip in Miri.
    // SAFETY: the inline assembly is a no-op.
    unsafe {
        // FIXME: Cannot use `asm!` because it doesn't support MIPS and other architectures.
        llvm_asm!("" : : "r"(&mut dummy) : "memory" : "volatile");
    }

    dummy
}
<|endoftext|>


<commit_before><commit_msg>Added support for ctrl-click.<commit_after><|endoftext|>


<commit_before><commit_msg>Simplify printing expressions<commit_after><|endoftext|>


<commit_before>extern crate bindgen;
extern crate clap;
extern crate diff;
#[cfg(feature = "logging")]
extern crate env_logger;
extern crate shlex;

use bindgen::{clang_version, Builder};
use std::env;
use std::fs;
use std::io::{self, BufRead, BufReader, Error, ErrorKind, Read, Write};
use std::path::PathBuf;
use std::process;
use std::sync::Once;

#[path = "../src/options.rs"]
mod options;
use options::builder_from_flags;

/// The environment variable that determines if test expectations are overwritten.
static OVERWRITE_ENV_VAR: &str = "BINDGEN_OVERWRITE_EXPECTED";

// Run `rustfmt` on the given source string and return a tuple of the formatted
// bindings, and rustfmt's stderr.
fn rustfmt(source: String) -> (String, String) {
    static CHECK_RUSTFMT: Once = Once::new();

    CHECK_RUSTFMT.call_once(|| {
        let have_working_rustfmt = process::Command::new("rustup")
            .args(&["run", "nightly", "rustfmt", "--version"])
            .stdout(process::Stdio::null())
            .stderr(process::Stdio::null())
            .status()
            .ok()
            .map_or(false, |status| status.success());

        if !have_working_rustfmt {
            panic!(
                "
The latest `rustfmt` is required to run the `bindgen` test suite. Install
`rustfmt` with:

    $ rustup update nightly
    $ rustup run nightly cargo install -f rustfmt-nightly
"
            );
        }
    });

    let mut child = process::Command::new("rustup")
        .args(&[
            "run",
            "nightly",
            "rustfmt",
            "--config-path",
            concat!(env!("CARGO_MANIFEST_DIR"), "/tests/rustfmt.toml"),
        ])
        .stdin(process::Stdio::piped())
        .stdout(process::Stdio::piped())
        .stderr(process::Stdio::piped())
        .spawn()
        .expect("should spawn `rustup run nightly rustfmt`");

    let mut stdin = child.stdin.take().unwrap();
    let mut stdout = child.stdout.take().unwrap();
    let mut stderr = child.stderr.take().unwrap();

    // Write to stdin in a new thread, so that we can read from stdout on this
    // thread. This keeps the child from blocking on writing to its stdout which
    // might block us from writing to its stdin.
    let stdin_handle =
        ::std::thread::spawn(move || stdin.write_all(source.as_bytes()));

    // Read stderr on a new thread for similar reasons.
    let stderr_handle = ::std::thread::spawn(move || {
        let mut output = vec![];
        io::copy(&mut stderr, &mut output)
            .map(|_| String::from_utf8_lossy(&output).to_string())
    });

    let mut output = vec![];
    io::copy(&mut stdout, &mut output).expect("Should copy stdout into vec OK");

    // Ignore actual rustfmt status because it is often non-zero for trivial
    // things.
    let _ = child.wait().expect("should wait on rustfmt child OK");

    stdin_handle
        .join()
        .expect("writer thread should not have panicked")
        .expect("should have written to child rustfmt's stdin OK");

    let bindings = String::from_utf8(output)
        .expect("rustfmt should only emit valid utf-8");

    let stderr = stderr_handle
        .join()
        .expect("stderr reader thread should not have panicked")
        .expect("should have read child rustfmt's stderr OK");

    (bindings, stderr)
}

fn compare_generated_header(
    header: &PathBuf,
    builder: Builder,
) -> Result<(), Error> {
    let file_name = header.file_name().ok_or(Error::new(
        ErrorKind::Other,
        "compare_generated_header expects a file",
    ))?;

    let mut expectation = PathBuf::from(header);
    expectation.pop();
    expectation.pop();
    expectation.push("expectations");
    expectation.push("tests");

    let mut looked_at = vec![];
    let mut expectation_file;

    // Try more specific expectations first.
    {
        let mut expectation = expectation.clone();

        if cfg!(feature = "testing_only_libclang_9") {
            expectation.push("libclang-9");
        } else if cfg!(feature = "testing_only_libclang_5") {
            expectation.push("libclang-5");
        } else if cfg!(feature = "testing_only_libclang_4") {
            expectation.push("libclang-4");
        } else if cfg!(feature = "testing_only_libclang_3_9") {
            expectation.push("libclang-3.9");
        } else if cfg!(feature = "testing_only_libclang_3_8") {
            expectation.push("libclang-3.8");
        } else {
            match clang_version().parsed {
                None => {}
                Some(version) => {
                    let (maj, min) = version;
                    let version_str = if maj >= 9 {
                        "9".to_owned()
                    } else if maj >= 5 {
                        "5".to_owned()
                    } else if maj >= 4 {
                        "4".to_owned()
                    } else {
                        format!("{}.{}", maj, min)
                    };
                    expectation.push(format!("libclang-{}", version_str));
                }
            }
        }

        expectation.push(file_name);
        expectation.set_extension("rs");
        expectation_file = fs::File::open(&expectation).ok();
        looked_at.push(expectation);
    }

    // Try the default path otherwise.
    if expectation_file.is_none() {
        expectation.push(file_name);
        expectation.set_extension("rs");
        expectation_file = fs::File::open(&expectation).ok();
        looked_at.push(expectation);
    }

    let mut expected = String::new();
    match expectation_file {
        Some(f) => {
            BufReader::new(f).read_to_string(&mut expected)?;
        }
        None => panic!(
            "missing test expectation file and/or 'testing_only_libclang_$VERSION' \
             feature for header '{}'; looking for expectation file at '{:?}'",
            header.display(),
            looked_at,
        ),
    };

    // We skip the generate() error here so we get a full diff below
    let (actual, rustfmt_stderr) = match builder.generate() {
        Ok(bindings) => {
            let actual = bindings.to_string();
            rustfmt(actual)
        }
        Err(()) => ("<error generating bindings>".to_string(), "".to_string()),
    };
    println!("{}", rustfmt_stderr);

    let (expected, rustfmt_stderr) = rustfmt(expected);
    println!("{}", rustfmt_stderr);

    if actual == expected {
        if !actual.is_empty() {
            return Ok(());
        }
        return Err(Error::new(
            ErrorKind::Other,
            "Something's gone really wrong!",
        ));
    }

    println!("{}", rustfmt_stderr);

    println!("diff expected generated");
    println!("--- expected: {:?}", looked_at.last().unwrap());
    println!("+++ generated from: {:?}", header);

    for diff in diff::lines(&expected, &actual) {
        match diff {
            diff::Result::Left(l) => println!("-{}", l),
            diff::Result::Both(l, _) => println!(" {}", l),
            diff::Result::Right(r) => println!("+{}", r),
        }
    }

    // Overwrite the expectation with actual output.
    if env::var_os(OVERWRITE_ENV_VAR).is_some() {
        let mut expectation_file = fs::File::create(looked_at.last().unwrap())?;
        expectation_file.write_all(actual.as_bytes())?;
    }

    Err(Error::new(ErrorKind::Other, "Header and binding differ! Run with BINDGEN_OVERWRITE_EXPECTED=1 in the environment to automatically overwrite the expectation."))
}

fn builder() -> Builder {
    #[cfg(feature = "logging")]
    let _ = env_logger::try_init();

    bindgen::builder()
}

fn create_bindgen_builder(header: &PathBuf) -> Result<Option<Builder>, Error> {
    #[cfg(feature = "logging")]
    let _ = env_logger::try_init();

    let source = fs::File::open(header)?;
    let reader = BufReader::new(source);

    // Scoop up bindgen-flags from test header
    let mut flags = Vec::with_capacity(2);

    for line in reader.lines() {
        let line = line?;
        if !line.starts_with("// bindgen") {
            continue;
        }

        if line.contains("bindgen-flags: ") {
            let extra_flags = line
                .split("bindgen-flags: ")
                .last()
                .and_then(shlex::split)
                .unwrap();
            flags.extend(extra_flags.into_iter());
        } else if line.contains("bindgen-osx-only") {
            let prepend_flags = ["--raw-line", "#![cfg(target_os=\"macos\")]"];
            flags = prepend_flags
                .into_iter()
                .map(ToString::to_string)
                .chain(flags)
                .collect();
        }
    }

    // Different platforms have various different conventions like struct padding, mangling, etc.
    // We make the default target as x86_64-unknown-linux
    if flags.iter().all(|flag| !flag.starts_with("--target=")) {
        if !flags.iter().any(|flag| flag == "--") {
            flags.push("--".into());
        }
        flags.push("--target=x86_64-unknown-linux".into());
    }

    // Fool builder_from_flags() into believing it has real env::args_os...
    // - add "bindgen" as executable name 0th element
    // - add header filename as 1st element
    // - prepend raw lines so they're in the right order for expected output
    // - append the test header's bindgen flags
    let header_str = header
        .to_str()
        .ok_or(Error::new(ErrorKind::Other, "Invalid header file name"))?;

    let prepend = [
        "bindgen",
        // We format in `compare_generated_header` ourselves to have a little
        // more control.
        "--no-rustfmt-bindings",
        "--with-derive-default",
        header_str,
        "--raw-line",
        "",
        "--raw-line",
        "#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]",
        "--raw-line",
        "",
    ];

    let args = prepend
        .into_iter()
        .map(ToString::to_string)
        .chain(flags.into_iter());

    builder_from_flags(args).map(|(builder, _, _)| Some(builder))
}

macro_rules! test_header {
    ($function:ident, $header:expr) => {
        #[test]
        fn $function() {
            let header = PathBuf::from($header);
            let result = create_bindgen_builder(&header).and_then(|builder| {
                if let Some(builder) = builder {
                    compare_generated_header(&header, builder)
                } else {
                    Ok(())
                }
            });

            if let Err(err) = result {
                panic!("{}", err);
            }
        }
    };
}

// This file is generated by build.rs
include!(concat!(env!("OUT_DIR"), "/tests.rs"));

#[test]
fn test_clang_env_args() {
    std::env::set_var(
        "BINDGEN_EXTRA_CLANG_ARGS",
        "-D_ENV_ONE=1 -D_ENV_TWO=\"2 -DNOT_THREE=1\"",
    );
    let actual = builder()
        .header_contents(
            "test.hpp",
            "#ifdef _ENV_ONE\nextern const int x[] = { 42 };\n#endif\n\
             #ifdef _ENV_TWO\nextern const int y[] = { 42 };\n#endif\n\
             #ifdef NOT_THREE\nextern const int z[] = { 42 };\n#endif\n",
        )
        .generate()
        .unwrap()
        .to_string();

    let (actual, stderr) = rustfmt(actual);
    println!("{}", stderr);

    let (expected, _) = rustfmt(
        "/* automatically generated by rust-bindgen */

extern \"C\" {
    pub static mut x: [::std::os::raw::c_int; 1usize];
}
extern \"C\" {
    pub static mut y: [::std::os::raw::c_int; 1usize];
}
"
        .to_string(),
    );

    assert_eq!(expected, actual);
}

#[test]
fn test_header_contents() {
    let actual = builder()
        .header_contents("test.h", "int foo(const char* a);")
        .clang_arg("--target=x86_64-unknown-linux")
        .generate()
        .unwrap()
        .to_string();

    let (actual, stderr) = rustfmt(actual);
    println!("{}", stderr);

    let (expected, _) = rustfmt(
        "/* automatically generated by rust-bindgen */

extern \"C\" {
    pub fn foo(a: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int;
}
"
        .to_string(),
    );

    assert_eq!(expected, actual);
}

#[test]
fn test_multiple_header_calls_in_builder() {
    let actual = builder()
        .header(concat!(
            env!("CARGO_MANIFEST_DIR"),
            "/tests/headers/func_ptr.h"
        ))
        .header(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/headers/char.h"))
        .clang_arg("--target=x86_64-unknown-linux")
        .generate()
        .unwrap()
        .to_string();

    let (actual, stderr) = rustfmt(actual);
    println!("{}", stderr);

    let expected = include_str!(concat!(
        env!("CARGO_MANIFEST_DIR"),
        "/tests/expectations/tests/test_multiple_header_calls_in_builder.rs"
    ));
    let (expected, _) = rustfmt(expected.to_string());

    if actual != expected {
        println!("Generated bindings differ from expected!");

        for diff in diff::lines(&actual, &expected) {
            match diff {
                diff::Result::Left(l) => println!("-{}", l),
                diff::Result::Both(l, _) => println!(" {}", l),
                diff::Result::Right(r) => println!("+{}", r),
            }
        }

        panic!();
    }
}

#[test]
// Doesn't support executing sh file on Windows.
// We may want to implement it in Rust so that we support all systems.
#[cfg(not(target_os = "windows"))]
fn no_system_header_includes() {
    use std::process::Command;
    assert!(Command::new("./ci/no-includes.sh")
        .current_dir(env!("CARGO_MANIFEST_DIR"))
        .spawn()
        .expect("should spawn ./ci/no-includes.sh OK")
        .wait()
        .expect("should wait for ./ci/no-includes OK")
        .success());
}

#[test]
fn dump_preprocessed_input() {
    let arg_keyword =
        concat!(env!("CARGO_MANIFEST_DIR"), "/tests/headers/arg_keyword.hpp");
    let empty_layout = concat!(
        env!("CARGO_MANIFEST_DIR"),
        "/tests/headers/cpp-empty-layout.hpp"
    );

    builder()
        .header(arg_keyword)
        .header(empty_layout)
        .dump_preprocessed_input()
        .expect("should dump preprocessed input");

    fn slurp(p: &str) -> String {
        let mut contents = String::new();
        let mut file = fs::File::open(p).unwrap();
        file.read_to_string(&mut contents).unwrap();
        contents
    }

    let bindgen_ii = slurp("__bindgen.ii");
    let arg_keyword = slurp(arg_keyword);
    let empty_layout = slurp(empty_layout);

    assert!(
        bindgen_ii.find(&arg_keyword).is_some(),
        "arg_keyword.hpp is in the preprocessed file"
    );
    assert!(
        bindgen_ii.find(&empty_layout).is_some(),
        "cpp-empty-layout.hpp is in the preprocessed file"
    );
}
<commit_msg>tests: Minor rustc warning fixes.<commit_after>extern crate bindgen;
extern crate clap;
extern crate diff;
#[cfg(feature = "logging")]
extern crate env_logger;
extern crate shlex;

use bindgen::{clang_version, Builder};
use std::env;
use std::fs;
use std::io::{self, BufRead, BufReader, Error, ErrorKind, Read, Write};
use std::path::PathBuf;
use std::process;
use std::sync::Once;

#[path = "../src/options.rs"]
mod options;
use options::builder_from_flags;

/// The environment variable that determines if test expectations are overwritten.
static OVERWRITE_ENV_VAR: &str = "BINDGEN_OVERWRITE_EXPECTED";

// Run `rustfmt` on the given source string and return a tuple of the formatted
// bindings, and rustfmt's stderr.
fn rustfmt(source: String) -> (String, String) {
    static CHECK_RUSTFMT: Once = Once::new();

    CHECK_RUSTFMT.call_once(|| {
        let have_working_rustfmt = process::Command::new("rustup")
            .args(&["run", "nightly", "rustfmt", "--version"])
            .stdout(process::Stdio::null())
            .stderr(process::Stdio::null())
            .status()
            .ok()
            .map_or(false, |status| status.success());

        if !have_working_rustfmt {
            panic!(
                "
The latest `rustfmt` is required to run the `bindgen` test suite. Install
`rustfmt` with:

    $ rustup update nightly
    $ rustup run nightly cargo install -f rustfmt-nightly
"
            );
        }
    });

    let mut child = process::Command::new("rustup")
        .args(&[
            "run",
            "nightly",
            "rustfmt",
            "--config-path",
            concat!(env!("CARGO_MANIFEST_DIR"), "/tests/rustfmt.toml"),
        ])
        .stdin(process::Stdio::piped())
        .stdout(process::Stdio::piped())
        .stderr(process::Stdio::piped())
        .spawn()
        .expect("should spawn `rustup run nightly rustfmt`");

    let mut stdin = child.stdin.take().unwrap();
    let mut stdout = child.stdout.take().unwrap();
    let mut stderr = child.stderr.take().unwrap();

    // Write to stdin in a new thread, so that we can read from stdout on this
    // thread. This keeps the child from blocking on writing to its stdout which
    // might block us from writing to its stdin.
    let stdin_handle =
        ::std::thread::spawn(move || stdin.write_all(source.as_bytes()));

    // Read stderr on a new thread for similar reasons.
    let stderr_handle = ::std::thread::spawn(move || {
        let mut output = vec![];
        io::copy(&mut stderr, &mut output)
            .map(|_| String::from_utf8_lossy(&output).to_string())
    });

    let mut output = vec![];
    io::copy(&mut stdout, &mut output).expect("Should copy stdout into vec OK");

    // Ignore actual rustfmt status because it is often non-zero for trivial
    // things.
    let _ = child.wait().expect("should wait on rustfmt child OK");

    stdin_handle
        .join()
        .expect("writer thread should not have panicked")
        .expect("should have written to child rustfmt's stdin OK");

    let bindings = String::from_utf8(output)
        .expect("rustfmt should only emit valid utf-8");

    let stderr = stderr_handle
        .join()
        .expect("stderr reader thread should not have panicked")
        .expect("should have read child rustfmt's stderr OK");

    (bindings, stderr)
}

fn compare_generated_header(
    header: &PathBuf,
    builder: Builder,
) -> Result<(), Error> {
    let file_name = header.file_name().ok_or(Error::new(
        ErrorKind::Other,
        "compare_generated_header expects a file",
    ))?;

    let mut expectation = PathBuf::from(header);
    expectation.pop();
    expectation.pop();
    expectation.push("expectations");
    expectation.push("tests");

    let mut looked_at = vec![];
    let mut expectation_file;

    // Try more specific expectations first.
    {
        let mut expectation = expectation.clone();

        if cfg!(feature = "testing_only_libclang_9") {
            expectation.push("libclang-9");
        } else if cfg!(feature = "testing_only_libclang_5") {
            expectation.push("libclang-5");
        } else if cfg!(feature = "testing_only_libclang_4") {
            expectation.push("libclang-4");
        } else if cfg!(feature = "testing_only_libclang_3_9") {
            expectation.push("libclang-3.9");
        } else if cfg!(feature = "testing_only_libclang_3_8") {
            expectation.push("libclang-3.8");
        } else {
            match clang_version().parsed {
                None => {}
                Some(version) => {
                    let (maj, min) = version;
                    let version_str = if maj >= 9 {
                        "9".to_owned()
                    } else if maj >= 5 {
                        "5".to_owned()
                    } else if maj >= 4 {
                        "4".to_owned()
                    } else {
                        format!("{}.{}", maj, min)
                    };
                    expectation.push(format!("libclang-{}", version_str));
                }
            }
        }

        expectation.push(file_name);
        expectation.set_extension("rs");
        expectation_file = fs::File::open(&expectation).ok();
        looked_at.push(expectation);
    }

    // Try the default path otherwise.
    if expectation_file.is_none() {
        expectation.push(file_name);
        expectation.set_extension("rs");
        expectation_file = fs::File::open(&expectation).ok();
        looked_at.push(expectation);
    }

    let mut expected = String::new();
    match expectation_file {
        Some(f) => {
            BufReader::new(f).read_to_string(&mut expected)?;
        }
        None => panic!(
            "missing test expectation file and/or 'testing_only_libclang_$VERSION' \
             feature for header '{}'; looking for expectation file at '{:?}'",
            header.display(),
            looked_at,
        ),
    };

    // We skip the generate() error here so we get a full diff below
    let (actual, rustfmt_stderr) = match builder.generate() {
        Ok(bindings) => {
            let actual = bindings.to_string();
            rustfmt(actual)
        }
        Err(()) => ("<error generating bindings>".to_string(), "".to_string()),
    };
    println!("{}", rustfmt_stderr);

    let (expected, rustfmt_stderr) = rustfmt(expected);
    println!("{}", rustfmt_stderr);

    if actual == expected {
        if !actual.is_empty() {
            return Ok(());
        }
        return Err(Error::new(
            ErrorKind::Other,
            "Something's gone really wrong!",
        ));
    }

    println!("{}", rustfmt_stderr);

    println!("diff expected generated");
    println!("--- expected: {:?}", looked_at.last().unwrap());
    println!("+++ generated from: {:?}", header);

    for diff in diff::lines(&expected, &actual) {
        match diff {
            diff::Result::Left(l) => println!("-{}", l),
            diff::Result::Both(l, _) => println!(" {}", l),
            diff::Result::Right(r) => println!("+{}", r),
        }
    }

    // Overwrite the expectation with actual output.
    if env::var_os(OVERWRITE_ENV_VAR).is_some() {
        let mut expectation_file = fs::File::create(looked_at.last().unwrap())?;
        expectation_file.write_all(actual.as_bytes())?;
    }

    Err(Error::new(ErrorKind::Other, "Header and binding differ! Run with BINDGEN_OVERWRITE_EXPECTED=1 in the environment to automatically overwrite the expectation."))
}

fn builder() -> Builder {
    #[cfg(feature = "logging")]
    let _ = env_logger::try_init();

    bindgen::builder()
}

fn create_bindgen_builder(header: &PathBuf) -> Result<Option<Builder>, Error> {
    #[cfg(feature = "logging")]
    let _ = env_logger::try_init();

    let source = fs::File::open(header)?;
    let reader = BufReader::new(source);

    // Scoop up bindgen-flags from test header
    let mut flags = Vec::with_capacity(2);

    for line in reader.lines() {
        let line = line?;
        if !line.starts_with("// bindgen") {
            continue;
        }

        if line.contains("bindgen-flags: ") {
            let extra_flags = line
                .split("bindgen-flags: ")
                .last()
                .and_then(shlex::split)
                .unwrap();
            flags.extend(extra_flags.into_iter());
        } else if line.contains("bindgen-osx-only") {
            let prepend_flags = ["--raw-line", "#![cfg(target_os=\"macos\")]"];
            flags = prepend_flags
                .iter()
                .map(ToString::to_string)
                .chain(flags)
                .collect();
        }
    }

    // Different platforms have various different conventions like struct padding, mangling, etc.
    // We make the default target as x86_64-unknown-linux
    if flags.iter().all(|flag| !flag.starts_with("--target=")) {
        if !flags.iter().any(|flag| flag == "--") {
            flags.push("--".into());
        }
        flags.push("--target=x86_64-unknown-linux".into());
    }

    // Fool builder_from_flags() into believing it has real env::args_os...
    // - add "bindgen" as executable name 0th element
    // - add header filename as 1st element
    // - prepend raw lines so they're in the right order for expected output
    // - append the test header's bindgen flags
    let header_str = header
        .to_str()
        .ok_or(Error::new(ErrorKind::Other, "Invalid header file name"))?;

    let prepend = [
        "bindgen",
        // We format in `compare_generated_header` ourselves to have a little
        // more control.
        "--no-rustfmt-bindings",
        "--with-derive-default",
        header_str,
        "--raw-line",
        "",
        "--raw-line",
        "#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]",
        "--raw-line",
        "",
    ];

    let args = prepend
        .iter()
        .map(ToString::to_string)
        .chain(flags.into_iter());

    builder_from_flags(args).map(|(builder, _, _)| Some(builder))
}

macro_rules! test_header {
    ($function:ident, $header:expr) => {
        #[test]
        fn $function() {
            let header = PathBuf::from($header);
            let result = create_bindgen_builder(&header).and_then(|builder| {
                if let Some(builder) = builder {
                    compare_generated_header(&header, builder)
                } else {
                    Ok(())
                }
            });

            if let Err(err) = result {
                panic!("{}", err);
            }
        }
    };
}

// This file is generated by build.rs
include!(concat!(env!("OUT_DIR"), "/tests.rs"));

#[test]
fn test_clang_env_args() {
    std::env::set_var(
        "BINDGEN_EXTRA_CLANG_ARGS",
        "-D_ENV_ONE=1 -D_ENV_TWO=\"2 -DNOT_THREE=1\"",
    );
    let actual = builder()
        .header_contents(
            "test.hpp",
            "#ifdef _ENV_ONE\nextern const int x[] = { 42 };\n#endif\n\
             #ifdef _ENV_TWO\nextern const int y[] = { 42 };\n#endif\n\
             #ifdef NOT_THREE\nextern const int z[] = { 42 };\n#endif\n",
        )
        .generate()
        .unwrap()
        .to_string();

    let (actual, stderr) = rustfmt(actual);
    println!("{}", stderr);

    let (expected, _) = rustfmt(
        "/* automatically generated by rust-bindgen */

extern \"C\" {
    pub static mut x: [::std::os::raw::c_int; 1usize];
}
extern \"C\" {
    pub static mut y: [::std::os::raw::c_int; 1usize];
}
"
        .to_string(),
    );

    assert_eq!(expected, actual);
}

#[test]
fn test_header_contents() {
    let actual = builder()
        .header_contents("test.h", "int foo(const char* a);")
        .clang_arg("--target=x86_64-unknown-linux")
        .generate()
        .unwrap()
        .to_string();

    let (actual, stderr) = rustfmt(actual);
    println!("{}", stderr);

    let (expected, _) = rustfmt(
        "/* automatically generated by rust-bindgen */

extern \"C\" {
    pub fn foo(a: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int;
}
"
        .to_string(),
    );

    assert_eq!(expected, actual);
}

#[test]
fn test_multiple_header_calls_in_builder() {
    let actual = builder()
        .header(concat!(
            env!("CARGO_MANIFEST_DIR"),
            "/tests/headers/func_ptr.h"
        ))
        .header(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/headers/char.h"))
        .clang_arg("--target=x86_64-unknown-linux")
        .generate()
        .unwrap()
        .to_string();

    let (actual, stderr) = rustfmt(actual);
    println!("{}", stderr);

    let expected = include_str!(concat!(
        env!("CARGO_MANIFEST_DIR"),
        "/tests/expectations/tests/test_multiple_header_calls_in_builder.rs"
    ));
    let (expected, _) = rustfmt(expected.to_string());

    if actual != expected {
        println!("Generated bindings differ from expected!");

        for diff in diff::lines(&actual, &expected) {
            match diff {
                diff::Result::Left(l) => println!("-{}", l),
                diff::Result::Both(l, _) => println!(" {}", l),
                diff::Result::Right(r) => println!("+{}", r),
            }
        }

        panic!();
    }
}

#[test]
// Doesn't support executing sh file on Windows.
// We may want to implement it in Rust so that we support all systems.
#[cfg(not(target_os = "windows"))]
fn no_system_header_includes() {
    use std::process::Command;
    assert!(Command::new("./ci/no-includes.sh")
        .current_dir(env!("CARGO_MANIFEST_DIR"))
        .spawn()
        .expect("should spawn ./ci/no-includes.sh OK")
        .wait()
        .expect("should wait for ./ci/no-includes OK")
        .success());
}

#[test]
fn dump_preprocessed_input() {
    let arg_keyword =
        concat!(env!("CARGO_MANIFEST_DIR"), "/tests/headers/arg_keyword.hpp");
    let empty_layout = concat!(
        env!("CARGO_MANIFEST_DIR"),
        "/tests/headers/cpp-empty-layout.hpp"
    );

    builder()
        .header(arg_keyword)
        .header(empty_layout)
        .dump_preprocessed_input()
        .expect("should dump preprocessed input");

    fn slurp(p: &str) -> String {
        let mut contents = String::new();
        let mut file = fs::File::open(p).unwrap();
        file.read_to_string(&mut contents).unwrap();
        contents
    }

    let bindgen_ii = slurp("__bindgen.ii");
    let arg_keyword = slurp(arg_keyword);
    let empty_layout = slurp(empty_layout);

    assert!(
        bindgen_ii.find(&arg_keyword).is_some(),
        "arg_keyword.hpp is in the preprocessed file"
    );
    assert!(
        bindgen_ii.find(&empty_layout).is_some(),
        "cpp-empty-layout.hpp is in the preprocessed file"
    );
}
<|endoftext|>


<commit_before><commit_msg>eliminate unneded clamp in narrow deblocking filters<commit_after><|endoftext|>


<commit_before><commit_msg>Default to the name of the variant for Display-like derives<commit_after><|endoftext|>


<commit_before>use ndarray::*;
use numpy::*;

#[test]
fn to_pyarray_vec() {
    let gil = pyo3::Python::acquire_gil();

    let a = vec![1, 2, 3];
    let arr = a.to_pyarray(gil.python());
    println!("arr.shape = {:?}", arr.shape());
    assert_eq!(arr.shape(), [3]);
    assert_eq!(arr.as_slice().unwrap(), &[1, 2, 3])
}

#[test]
fn to_pyarray_array() {
    let gil = pyo3::Python::acquire_gil();

    let a = Array3::<f64>::zeros((3, 4, 2));
    let shape = a.shape().iter().cloned().collect::<Vec<_>>();
    let strides = a.strides().iter().map(|d| d * 8).collect::<Vec<_>>();
    println!("a.shape   = {:?}", a.shape());
    println!("a.strides = {:?}", a.strides());
    let pa = a.to_pyarray(gil.python());
    println!("pa.shape   = {:?}", pa.shape());
    println!("pa.strides = {:?}", pa.strides());
    assert_eq!(pa.shape(), shape.as_slice());
    assert_eq!(pa.strides(), strides.as_slice());
}

#[test]
fn iter_to_pyarray() {
    let gil = pyo3::Python::acquire_gil();
    let arr = PyArray::from_iter(gil.python(), (0..10).map(|x| x * x));
    assert_eq!(
        arr.as_slice().unwrap(),
        &[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    );
}

#[test]
fn long_iter_to_pyarray() {
    let gil = pyo3::Python::acquire_gil();
    let arr = PyArray::from_iter(gil.python(), (0u32..512).map(|x| x));
    let slice = arr.as_slice().unwrap();
    for (i, &elem) in slice.iter().enumerate() {
        assert_eq!(i as u32, elem);
    }
}

macro_rules! small_array_test {
    ($($t: ident)+) => {
        #[test]
        fn from_small_array() {
            let gil = pyo3::Python::acquire_gil();
            $({
                let array: [$t; 2] = [$t::min_value(), $t::max_value()];
                let pyarray = array.to_pyarray(gil.python());
                assert_eq!(
                    pyarray.as_slice().unwrap(),
                    &[$t::min_value(), $t::max_value()]
                );
            })+
        }
    };
}

small_array_test!(i8 u8 i16 u16 i32 u32 i64 u64 usize);

#[test]
fn usize_dtype() {
    let gil = pyo3::Python::acquire_gil();
    let py = gil.python();

    let a: Vec<usize> = vec![1, 2, 3];
    let x = a.into_pyarray(py);
    let x_repr = format!("{:?}", x);

    let x_repr_expected = if cfg!(target_pointer_width = "64") {
        "array([1, 2, 3], dtype=uint64)"
    } else {
        "array([1, 2, 3], dtype=uint32)"
    };
    assert_eq!(x_repr, x_repr_expected);
}

#[test]
fn into_pyarray_vec() {
    let gil = pyo3::Python::acquire_gil();
    let a = vec![1, 2, 3];
    let arr = a.into_pyarray(gil.python());
    assert_eq!(arr.as_slice().unwrap(), &[1, 2, 3])
}

#[test]
fn into_pyarray_array() {
    let gil = pyo3::Python::acquire_gil();
    let arr = Array3::<f64>::zeros((3, 4, 2));
    let shape = arr.shape().iter().cloned().collect::<Vec<_>>();
    let strides = arr.strides().iter().map(|d| d * 8).collect::<Vec<_>>();
    let py_arr = arr.into_pyarray(gil.python());
    assert_eq!(py_arr.shape(), shape.as_slice());
    assert_eq!(py_arr.strides(), strides.as_slice());
}

#[test]
fn into_pyarray_cant_resize() {
    let gil = pyo3::Python::acquire_gil();
    let a = vec![1, 2, 3];
    let arr = a.into_pyarray(gil.python());
    assert!(arr.resize(100).is_err())
}
<commit_msg>Make usize_dtype test simpler<commit_after>use ndarray::*;
use numpy::*;

#[test]
fn to_pyarray_vec() {
    let gil = pyo3::Python::acquire_gil();

    let a = vec![1, 2, 3];
    let arr = a.to_pyarray(gil.python());
    println!("arr.shape = {:?}", arr.shape());
    assert_eq!(arr.shape(), [3]);
    assert_eq!(arr.as_slice().unwrap(), &[1, 2, 3])
}

#[test]
fn to_pyarray_array() {
    let gil = pyo3::Python::acquire_gil();

    let a = Array3::<f64>::zeros((3, 4, 2));
    let shape = a.shape().iter().cloned().collect::<Vec<_>>();
    let strides = a.strides().iter().map(|d| d * 8).collect::<Vec<_>>();
    println!("a.shape   = {:?}", a.shape());
    println!("a.strides = {:?}", a.strides());
    let pa = a.to_pyarray(gil.python());
    println!("pa.shape   = {:?}", pa.shape());
    println!("pa.strides = {:?}", pa.strides());
    assert_eq!(pa.shape(), shape.as_slice());
    assert_eq!(pa.strides(), strides.as_slice());
}

#[test]
fn iter_to_pyarray() {
    let gil = pyo3::Python::acquire_gil();
    let arr = PyArray::from_iter(gil.python(), (0..10).map(|x| x * x));
    assert_eq!(
        arr.as_slice().unwrap(),
        &[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    );
}

#[test]
fn long_iter_to_pyarray() {
    let gil = pyo3::Python::acquire_gil();
    let arr = PyArray::from_iter(gil.python(), (0u32..512).map(|x| x));
    let slice = arr.as_slice().unwrap();
    for (i, &elem) in slice.iter().enumerate() {
        assert_eq!(i as u32, elem);
    }
}

macro_rules! small_array_test {
    ($($t: ident)+) => {
        #[test]
        fn from_small_array() {
            let gil = pyo3::Python::acquire_gil();
            $({
                let array: [$t; 2] = [$t::min_value(), $t::max_value()];
                let pyarray = array.to_pyarray(gil.python());
                assert_eq!(
                    pyarray.as_slice().unwrap(),
                    &[$t::min_value(), $t::max_value()]
                );
            })+
        }
    };
}

small_array_test!(i8 u8 i16 u16 i32 u32 i64 u64 usize);

#[test]
fn usize_dtype() {
    let gil = pyo3::Python::acquire_gil();
    let py = gil.python();

    let a: Vec<usize> = vec![1, 2, 3];
    let x = a.into_pyarray(py);

    if cfg!(target_pointer_width = "64") {
        pyo3::py_run!(py, x, "assert str(x.dtype) == 'uint64'")
    } else {
        pyo3::py_run!(py, x, "assert str(x.dtype) == 'uint32'")
    };
}

#[test]
fn into_pyarray_vec() {
    let gil = pyo3::Python::acquire_gil();
    let a = vec![1, 2, 3];
    let arr = a.into_pyarray(gil.python());
    assert_eq!(arr.as_slice().unwrap(), &[1, 2, 3])
}

#[test]
fn into_pyarray_array() {
    let gil = pyo3::Python::acquire_gil();
    let arr = Array3::<f64>::zeros((3, 4, 2));
    let shape = arr.shape().iter().cloned().collect::<Vec<_>>();
    let strides = arr.strides().iter().map(|d| d * 8).collect::<Vec<_>>();
    let py_arr = arr.into_pyarray(gil.python());
    assert_eq!(py_arr.shape(), shape.as_slice());
    assert_eq!(py_arr.strides(), strides.as_slice());
}

#[test]
fn into_pyarray_cant_resize() {
    let gil = pyo3::Python::acquire_gil();
    let a = vec![1, 2, 3];
    let arr = a.into_pyarray(gil.python());
    assert!(arr.resize(100).is_err())
}
<|endoftext|>


<commit_before><commit_msg>Replace fail! with panic!<commit_after><|endoftext|>


<commit_before>use token::Token;
use error::Result;

use std::str::CharIndices;
use std::iter::Peekable;

pub struct Tokenizer<'a> {
    text: &'a str,
    chars: Peekable<CharIndices<'a>>,
}

impl<'a> Iterator for Tokenizer<'a> {
    type Item = Result<Token>;

    fn next(&mut self) -> Option<Result<Token>> {
        match self.parse() {
            Ok(Some(t)) => Some(Ok(t)),
            Ok(None) => None,
            Err(e) => Some(Err(e)),
        }
    }
}

impl<'a> Tokenizer<'a> {
    pub fn new(text: &str) -> Tokenizer {
        Tokenizer {
            text: text,
            chars: text.char_indices().peekable(),
        }
    }

    pub fn parse(&mut self) -> Result<Option<Token>> {
        let mut value = String::new();
        let mut start;

        while let Some((char_offset, curr_char)) = self.chars.next() {
            // Skip leading whitespace
            if curr_char.is_whitespace() {
                continue;
            } else {
                if is_single_char_token(curr_char) {
                    return Ok(Some(Token {
                        value: curr_char.to_string(),
                        offset: Some(char_offset),
                    }))
                } else if curr_char == '-' {
                    value.push(curr_char);
                    start = char_offset;

                    if let Some(&(_, peek_char)) = self.chars.peek() {
                        if peek_char.is_numeric() {
                            while let Some(&(next_char_offset, next_char)) = self.chars.peek() {
                                // Stop when we reach a non-numeric char
                                if !next_char.is_numeric() && next_char != '.' {
                                    break;
                                } else {
                                    value.push(next_char);
                                    self.chars.next();
                                }
                            }
                        } else {
                            while let Some(&(next_char_offset, next_char)) = self.chars.peek() {
                                // Stop when we reach a non-word char
                                if next_char.is_whitespace() || is_single_char_token(next_char) {
                                    break;
                                } else {
                                    value.push(next_char);
                                    self.chars.next();
                                }
                            }
                        }
                    }

                    return Ok(Some(Token { value: value, offset: Some(start) }))
                } else if curr_char.is_numeric() {
                    // Start of a multi-char numeric token
                    value.push(curr_char);
                    start = char_offset;

                    while let Some(&(next_char_offset, next_char)) = self.chars.peek() {
                        // Stop when we reach a non-numeric char
                        if !next_char.is_numeric() && next_char != '.' {
                            break;
                        } else {
                            value.push(next_char);
                            self.chars.next();
                        }
                    }
                    return Ok(Some(Token { value: value, offset: Some(start) }))
                } else {
                    // Start of a multi-char non-numeric token
                    value.push(curr_char);
                    start = char_offset;
                    while let Some(&(next_char_offset, next_char)) = self.chars.peek() {
                        // Stop when we reach a non-word char
                        if next_char.is_whitespace() || is_single_char_token(next_char) {
                            break;
                        } else {
                            value.push(next_char);
                            self.chars.next();
                        }
                    }
                    return Ok(Some(Token { value: value, offset: Some(start) }))
                }
            }
        }
        return Ok(None)
    }
}

fn is_single_char_token(ch: char) -> bool {
    "{}:;".chars().any(|c| c == ch)
}

#[cfg(test)]
mod tests {
    use super::*;
    use token::Token;
    use error::Result;

    fn assert_expected_token(
        actual: Option<Result<Token>>,
        expected_value: &str,
        expected_offset: usize) {
        let actual = actual.unwrap().unwrap();
        assert_eq!(actual.value, expected_value);
        assert_eq!(actual.offset, Some(expected_offset));
    }

    #[test]
    fn it_returns_none_for_empty_string() {
        let mut tokenizer = Tokenizer::new("");
        assert_eq!(tokenizer.next(), None);
    }

    #[test]
    fn it_returns_none_for_only_whitespace() {
        let mut tokenizer = Tokenizer::new("     ");
        assert_eq!(tokenizer.next(), None);
    }

    #[test]
    fn it_returns_words() {
        // Without regard to Sass word validity
        let mut tokenizer = Tokenizer::new(" \n  div   aoeu  ");
        assert_expected_token(tokenizer.next(), "div", 4);
        assert_expected_token(tokenizer.next(), "aoeu", 10);
        assert_eq!(tokenizer.next(), None);
    }

    #[test]
    fn it_separates_curly_braces() {
        // Without regard to matching
        let mut tokenizer = Tokenizer::new("{}}a{ blue}");
        assert_expected_token(tokenizer.next(), "{", 0);
        assert_expected_token(tokenizer.next(), "}", 1);
        assert_expected_token(tokenizer.next(), "}", 2);
        assert_expected_token(tokenizer.next(), "a", 3);
        assert_expected_token(tokenizer.next(), "{", 4);
        assert_expected_token(tokenizer.next(), "blue", 6);
        assert_expected_token(tokenizer.next(), "}", 10);
        assert_eq!(tokenizer.next(), None);
    }

    #[test]
    fn it_separates_colon() {
        let mut tokenizer = Tokenizer::new(":invalid: property::");
        assert_expected_token(tokenizer.next(), ":", 0);
        assert_expected_token(tokenizer.next(), "invalid", 1);
        assert_expected_token(tokenizer.next(), ":", 8);
        assert_expected_token(tokenizer.next(), "property", 10);
        assert_expected_token(tokenizer.next(), ":", 18);
        assert_expected_token(tokenizer.next(), ":", 19);
        assert_eq!(tokenizer.next(), None);
    }

    #[test]
    fn it_separates_semicolon() {
        let mut tokenizer = Tokenizer::new(";;\na;\nb\n;");
        assert_expected_token(tokenizer.next(), ";", 0);
        assert_expected_token(tokenizer.next(), ";", 1);
        assert_expected_token(tokenizer.next(), "a", 3);
        assert_expected_token(tokenizer.next(), ";", 4);
        assert_expected_token(tokenizer.next(), "b", 6);
        assert_expected_token(tokenizer.next(), ";", 8);
        assert_eq!(tokenizer.next(), None);
    }

    #[test]
    fn it_separates_numbers() {
        let mut tokenizer = Tokenizer::new("border: 0px 1.5 11em;");
        assert_expected_token(tokenizer.next(), "border", 0);
        assert_expected_token(tokenizer.next(), ":", 6);
        assert_expected_token(tokenizer.next(), "0", 8);
        assert_expected_token(tokenizer.next(), "px", 9);
        assert_expected_token(tokenizer.next(), "1.5", 12);
        assert_expected_token(tokenizer.next(), "11", 16);
        assert_expected_token(tokenizer.next(), "em", 18);
        assert_expected_token(tokenizer.next(), ";", 20);
        assert_eq!(tokenizer.next(), None);
    }

    #[test]
    fn it_separates_hyphen() {
        let mut tokenizer = Tokenizer::new("font-weight -webkit -3 - 4-5 a-1");
        assert_expected_token(tokenizer.next(), "font-weight", 0);
        assert_expected_token(tokenizer.next(), "-webkit", 12);
        assert_expected_token(tokenizer.next(), "-3", 20);
        assert_expected_token(tokenizer.next(), "-", 23);
        assert_expected_token(tokenizer.next(), "4", 25);
        assert_expected_token(tokenizer.next(), "-5", 26);
        assert_expected_token(tokenizer.next(), "a-1", 29);
        assert_eq!(tokenizer.next(), None);
    }
}
<commit_msg>Tokenize parens<commit_after>use token::Token;
use error::Result;

use std::str::CharIndices;
use std::iter::Peekable;

pub struct Tokenizer<'a> {
    text: &'a str,
    chars: Peekable<CharIndices<'a>>,
}

impl<'a> Iterator for Tokenizer<'a> {
    type Item = Result<Token>;

    fn next(&mut self) -> Option<Result<Token>> {
        match self.parse() {
            Ok(Some(t)) => Some(Ok(t)),
            Ok(None) => None,
            Err(e) => Some(Err(e)),
        }
    }
}

impl<'a> Tokenizer<'a> {
    pub fn new(text: &str) -> Tokenizer {
        Tokenizer {
            text: text,
            chars: text.char_indices().peekable(),
        }
    }

    pub fn parse(&mut self) -> Result<Option<Token>> {
        let mut value = String::new();
        let mut start;

        while let Some((char_offset, curr_char)) = self.chars.next() {
            // Skip leading whitespace
            if curr_char.is_whitespace() {
                continue;
            } else {
                if is_single_char_token(curr_char) {
                    return Ok(Some(Token {
                        value: curr_char.to_string(),
                        offset: Some(char_offset),
                    }))
                } else if curr_char == '-' {
                    value.push(curr_char);
                    start = char_offset;

                    if let Some(&(_, peek_char)) = self.chars.peek() {
                        if peek_char.is_numeric() {
                            while let Some(&(next_char_offset, next_char)) = self.chars.peek() {
                                // Stop when we reach a non-numeric char
                                if !next_char.is_numeric() && next_char != '.' {
                                    break;
                                } else {
                                    value.push(next_char);
                                    self.chars.next();
                                }
                            }
                        } else {
                            while let Some(&(next_char_offset, next_char)) = self.chars.peek() {
                                // Stop when we reach a non-word char
                                if next_char.is_whitespace() || is_single_char_token(next_char) {
                                    break;
                                } else {
                                    value.push(next_char);
                                    self.chars.next();
                                }
                            }
                        }
                    }

                    return Ok(Some(Token { value: value, offset: Some(start) }))
                } else if curr_char.is_numeric() {
                    // Start of a multi-char numeric token
                    value.push(curr_char);
                    start = char_offset;

                    while let Some(&(next_char_offset, next_char)) = self.chars.peek() {
                        // Stop when we reach a non-numeric char
                        if !next_char.is_numeric() && next_char != '.' {
                            break;
                        } else {
                            value.push(next_char);
                            self.chars.next();
                        }
                    }
                    return Ok(Some(Token { value: value, offset: Some(start) }))
                } else {
                    // Start of a multi-char non-numeric token
                    value.push(curr_char);
                    start = char_offset;
                    while let Some(&(next_char_offset, next_char)) = self.chars.peek() {
                        // Stop when we reach a non-word char
                        if next_char.is_whitespace() || is_single_char_token(next_char) {
                            break;
                        } else {
                            value.push(next_char);
                            self.chars.next();
                        }
                    }
                    return Ok(Some(Token { value: value, offset: Some(start) }))
                }
            }
        }
        return Ok(None)
    }
}

fn is_single_char_token(ch: char) -> bool {
    "{}():;".chars().any(|c| c == ch)
}

#[cfg(test)]
mod tests {
    use super::*;
    use token::Token;
    use error::Result;

    fn assert_expected_token(
        actual: Option<Result<Token>>,
        expected_value: &str,
        expected_offset: usize) {
        let actual = actual.unwrap().unwrap();
        assert_eq!(actual.value, expected_value);
        assert_eq!(actual.offset, Some(expected_offset));
    }

    #[test]
    fn it_returns_none_for_empty_string() {
        let mut tokenizer = Tokenizer::new("");
        assert_eq!(tokenizer.next(), None);
    }

    #[test]
    fn it_returns_none_for_only_whitespace() {
        let mut tokenizer = Tokenizer::new("     ");
        assert_eq!(tokenizer.next(), None);
    }

    #[test]
    fn it_returns_words() {
        // Without regard to Sass word validity
        let mut tokenizer = Tokenizer::new(" \n  div   aoeu  ");
        assert_expected_token(tokenizer.next(), "div", 4);
        assert_expected_token(tokenizer.next(), "aoeu", 10);
        assert_eq!(tokenizer.next(), None);
    }

    #[test]
    fn it_separates_curly_braces() {
        // Without regard to matching
        let mut tokenizer = Tokenizer::new("{}}a{ blue}");
        assert_expected_token(tokenizer.next(), "{", 0);
        assert_expected_token(tokenizer.next(), "}", 1);
        assert_expected_token(tokenizer.next(), "}", 2);
        assert_expected_token(tokenizer.next(), "a", 3);
        assert_expected_token(tokenizer.next(), "{", 4);
        assert_expected_token(tokenizer.next(), "blue", 6);
        assert_expected_token(tokenizer.next(), "}", 10);
        assert_eq!(tokenizer.next(), None);
    }

    #[test]
    fn it_separates_colon() {
        let mut tokenizer = Tokenizer::new(":invalid: property::");
        assert_expected_token(tokenizer.next(), ":", 0);
        assert_expected_token(tokenizer.next(), "invalid", 1);
        assert_expected_token(tokenizer.next(), ":", 8);
        assert_expected_token(tokenizer.next(), "property", 10);
        assert_expected_token(tokenizer.next(), ":", 18);
        assert_expected_token(tokenizer.next(), ":", 19);
        assert_eq!(tokenizer.next(), None);
    }

    #[test]
    fn it_separates_semicolon() {
        let mut tokenizer = Tokenizer::new(";;\na;\nb\n;");
        assert_expected_token(tokenizer.next(), ";", 0);
        assert_expected_token(tokenizer.next(), ";", 1);
        assert_expected_token(tokenizer.next(), "a", 3);
        assert_expected_token(tokenizer.next(), ";", 4);
        assert_expected_token(tokenizer.next(), "b", 6);
        assert_expected_token(tokenizer.next(), ";", 8);
        assert_eq!(tokenizer.next(), None);
    }

    #[test]
    fn it_separates_numbers() {
        let mut tokenizer = Tokenizer::new("border: 0px 1.5 11em;");
        assert_expected_token(tokenizer.next(), "border", 0);
        assert_expected_token(tokenizer.next(), ":", 6);
        assert_expected_token(tokenizer.next(), "0", 8);
        assert_expected_token(tokenizer.next(), "px", 9);
        assert_expected_token(tokenizer.next(), "1.5", 12);
        assert_expected_token(tokenizer.next(), "11", 16);
        assert_expected_token(tokenizer.next(), "em", 18);
        assert_expected_token(tokenizer.next(), ";", 20);
        assert_eq!(tokenizer.next(), None);
    }

    #[test]
    fn it_separates_hyphen() {
        let mut tokenizer = Tokenizer::new("font-weight -webkit -3 - 4-5 a-1");
        assert_expected_token(tokenizer.next(), "font-weight", 0);
        assert_expected_token(tokenizer.next(), "-webkit", 12);
        assert_expected_token(tokenizer.next(), "-3", 20);
        assert_expected_token(tokenizer.next(), "-", 23);
        assert_expected_token(tokenizer.next(), "4", 25);
        assert_expected_token(tokenizer.next(), "-5", 26);
        assert_expected_token(tokenizer.next(), "a-1", 29);
        assert_eq!(tokenizer.next(), None);
    }

    #[test]
    fn it_separates_parens() {
        let mut tokenizer = Tokenizer::new("() rgb)()(");
        assert_expected_token(tokenizer.next(), "(", 0);
        assert_expected_token(tokenizer.next(), ")", 1);
        assert_expected_token(tokenizer.next(), "rgb", 3);
        assert_expected_token(tokenizer.next(), ")", 6);
        assert_expected_token(tokenizer.next(), "(", 7);
        assert_expected_token(tokenizer.next(), ")", 8);
        assert_expected_token(tokenizer.next(), "(", 9);
        assert_eq!(tokenizer.next(), None);
    }
}
<|endoftext|>


<commit_before><commit_msg>Renaming<commit_after><|endoftext|>


<commit_before>//! Provides an efficient Fast Fourier transform.
//!
//! A `Transformer` must first be created that stores precomputed information to
//! speed up the transform. This `Transformer` can then be used only to perform
//! FFTs of the chosen size.

use std::f32::consts::PI;
use std::vec::Vec;

use utils::complex::Complex;

/// A container for precomputed values to perform FFTs of a fixed size.
pub struct Transformer {
    size: usize,
    bit_reverses: Vec<usize>,
    twiddles: Vec<Complex>,
}

impl Transformer {
    /// Returns a set precomputed information used to perform FFTs of the
    /// provided size. The size is rounded up to the nearest power of two.
    pub fn new(size: usize) -> Transformer {
        // Only operate in powers of two
        let bufsize = size.next_power_of_two();

        // Populate the bit reverses
        // We only use the lower log2(size) bits to express the index
        let mut bit_reverses = Vec::with_capacity(bufsize);
        for i in (0 .. size) {
            let br = bit_reverse(i as u32, int_log(bufsize as u32));
            bit_reverses.push(br as usize);
        }

        // Populate the twiddle factors w_n^i
        // w_n = exp(-j*2*pi*n/N)
        let mut twiddles = Vec::with_capacity(bufsize);
        let exponent = Complex::new(0.0, -2.0*PI/(bufsize as f32));
        for i in (0 .. bufsize) {
            twiddles.push(exponent.scale(i as f32).exp());
        }

        Transformer { size: bufsize, bit_reverses: bit_reverses,
            twiddles: twiddles }
    }

    /// Returns the size FFTs this Transformer performs
    pub fn get_size(&self) -> usize {
        self.size
    }

    /// Performs an FFT on `input`, and places the result in `output`.
    ///
    /// The input is zero padded if less than `size` samples are provided, and
    /// truncated if more than `size` samples are provided.
    pub fn fft(&self, input: &Vec<Complex>, output: &mut Vec<Complex>) {
        self.transform(input, output, false);
    }

    /// Performs an inverse FFT on `input`, and places the result in `output`.
    ///
    /// The input is zero padded if less than `size` samples are provided, and
    /// truncated if more than `size` samples are provided.
    pub fn ifft(&self, input: &Vec<Complex>, output: &mut Vec<Complex>) {
        self.transform(input, output, true);
    }

    /// Performs the actual transform on `input`, placing the result in
    /// `output`.
    ///
    /// This function performs both forward and backwards transforms, since
    /// there are only minor algorithmic differences in the beginning and end
    /// of transformation.
    ///
    /// The input is zero padded if less than `size` samples are provided, and
    /// truncated if more than `size` samples are provided.
    fn transform(&self, input: &Vec<Complex>, output: &mut Vec<Complex>,
                 inverse: bool) {
        // Copy the input into bit reverse order, zero padding if necessary,
        // conjugating if we are inverse transforming
        for i in (0 .. input.len()) {
            output[self.bit_reverses[i]] =
                if inverse {
                    input[i].conj()
                } else {
                    input[i]
                }
        }
        for i in self.bit_reverses[input.len() .. self.size].iter() {
            output[*i] = Complex::from_real(0.0);
        }

        // Iteratively perform FFT, starting at 2 points
        let mut n = 2;
        while n <= self.size {
            // For each of the small FFTs
            for set in (0 .. self.size/n) {
                // For each pair of n
                for i in (0 .. n/2) {
                    let ilo = n*set + i;
                    let ihi = ilo + n/2;

                    // Grab out the lower and upper n
                    let lower = output[ilo];
                    let upper = output[ihi] * self.twiddles[self.size/n * i];

                    // Assign them back using a butterfly
                    output[ilo] = lower + upper;
                    output[ihi] = lower - upper;
                }
            }

            // Double the number of points per FFT
            n *= 2;
        }

        // If we are inverse transforming, conjugate and normalize the output
        if inverse {
            for i in (0 .. self.size) {
                output[i] = output[i].conj().scale(1.0/(self.size as f32));
            }
        }
    }
}

/// Returns the bit reverse of `n`, for the lower `bits` bits.
///
/// For small examples, the bit reverse of 0b00011010 is 0b01011000, but the bit
/// reverse of just the lower 5 bits is 0b00001011.
fn bit_reverse(n: u32, bits: u32) -> u32 {
    let mut i = n;
    i = (i >> 16) | (i << 16);
    i = ((i & 0xFF00FF00) >> 8) | ((i & 0x00FF00FF) << 8);
    i = ((i & 0xF0F0F0F0) >> 4) | ((i & 0x0F0F0F0F) << 4);
    i = ((i & 0xCCCCCCCC) >> 2) | ((i & 0x33333333) << 2);
    i = ((i & 0xAAAAAAAA) >> 1) | ((i & 0x55555555) << 1);
    i >> ((32 - bits) as u32)
}

/// Returns the log base 2 of n, rounded up.
fn int_log(n: u32) -> u32 {
    let mut i = n-1; // correct for exact powers of 2
    let mut res = 0;
    while i > 0 {
        i = i >> 1;
        res += 1;
    }
    res
}

// Unit tests...
#[cfg(test)]
mod test {
    use std::vec::Vec;

    use utils::complex::Complex;
    use super::{Transformer, int_log, bit_reverse};

    /// Tests int_log with many values
    #[test]
    fn test_int_log() {
        assert_eq!(int_log(1), 0);
        assert_eq!(int_log(2), 1);
        assert_eq!(int_log(3), 2);
        assert_eq!(int_log(4), 2);
        assert_eq!(int_log(7), 3);
        assert_eq!(int_log(8), 3);
        assert_eq!(int_log(31), 5);
        assert_eq!(int_log(32), 5);
    }

    /// Tests bit_reverse.
    #[test]
    fn test_bit_reverse() {
        assert_eq!(bit_reverse(0x00000000, 32), 0x00000000);
        assert_eq!(bit_reverse(0xFFFFFFFF, 32), 0xFFFFFFFF);
        assert_eq!(bit_reverse(0x00000001, 32), 0x80000000);
        assert_eq!(bit_reverse(0x11111111, 32), 0x88888888);
        assert_eq!(bit_reverse(0x234f9e01, 32), 0x8079f2c4); //random
        assert_eq!(bit_reverse(0x00000001, 4), 0x00000008);
        assert_eq!(bit_reverse(0x0000000F, 4), 0x0000000F);
    }

    /// Tests the FFT of an impulse function.
    ///
    /// Analytically, an impulse function has a constant fourier transform.
    #[test]
    fn test_fft_impulse() {
        let zero = Complex::zero();
        let one = Complex::from_real(1.0);

        let mut impulse = Vec::with_capacity(8);
        let mut out = Vec::with_capacity(8);
        for i in (0 .. 8) {
            impulse.push(if i == 0 { one } else { zero });
            out.push(Complex::zero());
        }

        let t = Transformer::new(8);
        t.fft(&impulse, &mut out);

        for c in out.iter() {
            assert!(c.eq(one))
        }
    }

    /// Tests the IFFT of an impulse function.
    ///
    /// Analytically, a constant frequency domain results in an impulse
    /// function.
    #[test]
    fn test_ifft_impulse() {
        let zero = Complex::zero();
        let one = Complex::from_real(1.0);

        let mut impulse = Vec::with_capacity(8);
        let mut out = Vec::with_capacity(8);
        for _i in (0 .. 8) {
            impulse.push(one);
            out.push(zero);
        }

        let t = Transformer::new(8);
        t.ifft(&impulse, &mut out);

        assert!(out[0].eq(one));
        for c in out[1 .. 8].iter() {
            assert!(c.eq(zero));
        }
    }

    /// Tests that the identify property, i.e. IFFT(FTT(f)) == f
    #[test]
    fn test_fft_identity() {
        let zero = Complex::zero();
        let epsilon = 1e-6;

        let mut input = Vec::with_capacity(8);
        let mut fft = Vec::with_capacity(8);
        let mut out = Vec::with_capacity(8);
        for i in (0 .. 8) {
            input.push(Complex::from_real((i+1) as f32));
            fft.push(zero);
            out.push(zero);
        }

        let t = Transformer::new(8);
        t.fft(&input, &mut fft);
        t.ifft(&fft, &mut out);

        for i in (0 .. 7) {
            println!("{}",out[i].real() - ((i+1) as f32));
            assert!(out[i].real() - ((i+1) as f32) < epsilon);
            assert!(out[i].imag() < epsilon);
        }
    }

    /// Tests that the Transformer properly handles input buffers that are too
    /// short by zero padding them.
    #[test]
    fn test_fft_zero_pad() {
        let zero = Complex::zero();
        let epsilon = 1e-6;

        let mut input = Vec::with_capacity(7);
        let mut fft = Vec::with_capacity(8);
        let mut out = Vec::with_capacity(8);
        for i in (0 .. 8) {
            if i < 7 {
                input.push(Complex::from_real((i+1) as f32));
            }
            fft.push(zero);
            out.push(zero);
        }

        let t = Transformer::new(8);
        t.fft(&input, &mut fft);
        t.ifft(&fft, &mut out);

        for i in (0 .. 7) {
            println!("{}",out[i].real() - ((i+1) as f32));
            assert!(out[i].real() - ((i+1) as f32) < epsilon);
            assert!(out[i].imag() < epsilon);
        }
    }
}
<commit_msg>Convert FFT to use slices rather than &Vec<commit_after>//! Provides an efficient Fast Fourier transform.
//!
//! A `Transformer` must first be created that stores precomputed information to
//! speed up the transform. This `Transformer` can then be used only to perform
//! FFTs of the chosen size.

use std::f32::consts::PI;
use std::vec::Vec;

use utils::complex::Complex;

/// A container for precomputed values to perform FFTs of a fixed size.
pub struct Transformer {
    size: usize,
    bit_reverses: Vec<usize>,
    twiddles: Vec<Complex>,
}

impl Transformer {
    /// Returns a set precomputed information used to perform FFTs of the
    /// provided size. The size is rounded up to the nearest power of two.
    pub fn new(size: usize) -> Transformer {
        // Only operate in powers of two
        let bufsize = size.next_power_of_two();

        // Populate the bit reverses
        // We only use the lower log2(size) bits to express the index
        let mut bit_reverses = Vec::with_capacity(bufsize);
        for i in (0 .. size) {
            let br = bit_reverse(i as u32, int_log(bufsize as u32));
            bit_reverses.push(br as usize);
        }

        // Populate the twiddle factors w_n^i
        // w_n = exp(-j*2*pi*n/N)
        let mut twiddles = Vec::with_capacity(bufsize);
        let exponent = Complex::new(0.0, -2.0*PI/(bufsize as f32));
        for i in (0 .. bufsize) {
            twiddles.push(exponent.scale(i as f32).exp());
        }

        Transformer { size: bufsize, bit_reverses: bit_reverses,
            twiddles: twiddles }
    }

    /// Returns the size FFTs this Transformer performs
    pub fn get_size(&self) -> usize {
        self.size
    }

    /// Performs an FFT on `input`, and places the result in `output`.
    ///
    /// The input is zero padded if less than `size` samples are provided, and
    /// truncated if more than `size` samples are provided.
    pub fn fft(&self, input: &[Complex], output: &mut[Complex]) {
        self.transform(input, output, false);
    }

    /// Performs an inverse FFT on `input`, and places the result in `output`.
    ///
    /// The input is zero padded if less than `size` samples are provided, and
    /// truncated if more than `size` samples are provided.
    pub fn ifft(&self, input: &[Complex], output: &mut[Complex]) {
        self.transform(input, output, true);
    }

    /// Performs the actual transform on `input`, placing the result in
    /// `output`.
    ///
    /// This function performs both forward and backwards transforms, since
    /// there are only minor algorithmic differences in the beginning and end
    /// of transformation.
    ///
    /// The input is zero padded if less than `size` samples are provided, and
    /// truncated if more than `size` samples are provided.
    fn transform(&self, input: &[Complex], output: &mut[Complex],
                 inverse: bool) {
        // Copy the input into bit reverse order, zero padding if necessary,
        // conjugating if we are inverse transforming
        for i in (0 .. input.len()) {
            output[self.bit_reverses[i]] =
                if inverse {
                    input[i].conj()
                } else {
                    input[i]
                }
        }
        for i in self.bit_reverses[input.len() .. self.size].iter() {
            output[*i] = Complex::from_real(0.0);
        }

        // Iteratively perform FFT, starting at 2 points
        let mut n = 2;
        while n <= self.size {
            // For each of the small FFTs
            for set in (0 .. self.size/n) {
                // For each pair of n
                for i in (0 .. n/2) {
                    let ilo = n*set + i;
                    let ihi = ilo + n/2;

                    // Grab out the lower and upper n
                    let lower = output[ilo];
                    let upper = output[ihi] * self.twiddles[self.size/n * i];

                    // Assign them back using a butterfly
                    output[ilo] = lower + upper;
                    output[ihi] = lower - upper;
                }
            }

            // Double the number of points per FFT
            n *= 2;
        }

        // If we are inverse transforming, conjugate and normalize the output
        if inverse {
            for i in (0 .. self.size) {
                output[i] = output[i].conj().scale(1.0/(self.size as f32));
            }
        }
    }
}

/// Returns the bit reverse of `n`, for the lower `bits` bits.
///
/// For small examples, the bit reverse of 0b00011010 is 0b01011000, but the bit
/// reverse of just the lower 5 bits is 0b00001011.
fn bit_reverse(n: u32, bits: u32) -> u32 {
    let mut i = n;
    i = (i >> 16) | (i << 16);
    i = ((i & 0xFF00FF00) >> 8) | ((i & 0x00FF00FF) << 8);
    i = ((i & 0xF0F0F0F0) >> 4) | ((i & 0x0F0F0F0F) << 4);
    i = ((i & 0xCCCCCCCC) >> 2) | ((i & 0x33333333) << 2);
    i = ((i & 0xAAAAAAAA) >> 1) | ((i & 0x55555555) << 1);
    i >> ((32 - bits) as u32)
}

/// Returns the log base 2 of n, rounded up.
fn int_log(n: u32) -> u32 {
    let mut i = n-1; // correct for exact powers of 2
    let mut res = 0;
    while i > 0 {
        i = i >> 1;
        res += 1;
    }
    res
}

// Unit tests...
#[cfg(test)]
mod test {
    use std::vec::Vec;

    use utils::complex::Complex;
    use super::{Transformer, int_log, bit_reverse};

    /// Tests int_log with many values
    #[test]
    fn test_int_log() {
        assert_eq!(int_log(1), 0);
        assert_eq!(int_log(2), 1);
        assert_eq!(int_log(3), 2);
        assert_eq!(int_log(4), 2);
        assert_eq!(int_log(7), 3);
        assert_eq!(int_log(8), 3);
        assert_eq!(int_log(31), 5);
        assert_eq!(int_log(32), 5);
    }

    /// Tests bit_reverse.
    #[test]
    fn test_bit_reverse() {
        assert_eq!(bit_reverse(0x00000000, 32), 0x00000000);
        assert_eq!(bit_reverse(0xFFFFFFFF, 32), 0xFFFFFFFF);
        assert_eq!(bit_reverse(0x00000001, 32), 0x80000000);
        assert_eq!(bit_reverse(0x11111111, 32), 0x88888888);
        assert_eq!(bit_reverse(0x234f9e01, 32), 0x8079f2c4); //random
        assert_eq!(bit_reverse(0x00000001, 4), 0x00000008);
        assert_eq!(bit_reverse(0x0000000F, 4), 0x0000000F);
    }

    /// Tests the FFT of an impulse function.
    ///
    /// Analytically, an impulse function has a constant fourier transform.
    #[test]
    fn test_fft_impulse() {
        let zero = Complex::zero();
        let one = Complex::from_real(1.0);

        let mut impulse = Vec::with_capacity(8);
        let mut out = Vec::with_capacity(8);
        for i in (0 .. 8) {
            impulse.push(if i == 0 { one } else { zero });
            out.push(Complex::zero());
        }

        let t = Transformer::new(8);
        t.fft(&impulse, &mut out);

        for c in out.iter() {
            assert!(c.eq(one))
        }
    }

    /// Tests the IFFT of an impulse function.
    ///
    /// Analytically, a constant frequency domain results in an impulse
    /// function.
    #[test]
    fn test_ifft_impulse() {
        let zero = Complex::zero();
        let one = Complex::from_real(1.0);

        let mut impulse = Vec::with_capacity(8);
        let mut out = Vec::with_capacity(8);
        for _i in (0 .. 8) {
            impulse.push(one);
            out.push(zero);
        }

        let t = Transformer::new(8);
        t.ifft(&impulse, &mut out);

        assert!(out[0].eq(one));
        for c in out[1 .. 8].iter() {
            assert!(c.eq(zero));
        }
    }

    /// Tests that the identify property, i.e. IFFT(FTT(f)) == f
    #[test]
    fn test_fft_identity() {
        let zero = Complex::zero();
        let epsilon = 1e-6;

        let mut input = Vec::with_capacity(8);
        let mut fft = Vec::with_capacity(8);
        let mut out = Vec::with_capacity(8);
        for i in (0 .. 8) {
            input.push(Complex::from_real((i+1) as f32));
            fft.push(zero);
            out.push(zero);
        }

        let t = Transformer::new(8);
        t.fft(&input, &mut fft);
        t.ifft(&fft, &mut out);

        for i in (0 .. 7) {
            println!("{}",out[i].real() - ((i+1) as f32));
            assert!(out[i].real() - ((i+1) as f32) < epsilon);
            assert!(out[i].imag() < epsilon);
        }
    }

    /// Tests that the Transformer properly handles input buffers that are too
    /// short by zero padding them.
    #[test]
    fn test_fft_zero_pad() {
        let zero = Complex::zero();
        let epsilon = 1e-6;

        let mut input = Vec::with_capacity(7);
        let mut fft = Vec::with_capacity(8);
        let mut out = Vec::with_capacity(8);
        for i in (0 .. 8) {
            if i < 7 {
                input.push(Complex::from_real((i+1) as f32));
            }
            fft.push(zero);
            out.push(zero);
        }

        let t = Transformer::new(8);
        t.fft(&input, &mut fft);
        t.ifft(&fft, &mut out);

        for i in (0 .. 7) {
            println!("{}",out[i].real() - ((i+1) as f32));
            assert!(out[i].real() - ((i+1) as f32) < epsilon);
            assert!(out[i].imag() < epsilon);
        }
    }
}
<|endoftext|>


<commit_before>pub mod data;<commit_msg>rustfmt<commit_after>pub mod data;
<|endoftext|>


<commit_before>// Copyright 2014-2016 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Common utilities.

mod text;
pub use self::text::{Text, TextSlice, TextIterator, IntoTextIterator, trim_newline};

mod nonnanfloat;
pub use self::nonnanfloat::NonNaNFloat;

mod interval;
pub use self::interval::{Interval, IntervalError};

/// Strand information.
#[derive(Debug, Clone, Copy)]
pub enum Strand {
    Forward,
    Reverse,
    Unknown,
}

impl PartialEq for Strand {
    /// Returns true if both are `Forward` or both are `Reverse`, otherwise returns false.
    fn eq(&self, other: &Strand) -> bool {
        match (self, other) {
            (&Strand::Forward, &Strand::Forward) => true,
            (&Strand::Reverse, &Strand::Reverse) => true,
            _ => false
        }
    }
}

impl Strand {

    /// Returns a `Strand` enum representing the given char.
    ///
    /// The mapping is as follows:
    ///     * '+', 'f', or 'F' becomes `Strand::Forward`
    ///     * '-', 'r', or 'R' becomes `Strand::Reverse`
    ///     * '.', '?' becomes `Strand::Unknown`
    ///     * Any other inputs will return an `Err(StrandError::InvalidChar)`
    pub fn from_char(strand_char: &char) -> Result<Strand, StrandError> {
        match *strand_char {
            '+' | 'f' | 'F' => Ok(Strand::Forward),
            '-' | 'r' | 'R' => Ok(Strand::Reverse),
            '.' | '?'  => Ok(Strand::Unknown),
            invalid => Err(StrandError::InvalidChar(invalid)),
        }
    }

    pub fn is_unknown(&self) -> bool {
        if let &Strand::Unknown = self {
            true
        } else {
            false
        }
    }
}

quick_error! {
    #[derive(Debug)]
    pub enum StrandError {
        InvalidChar(invalid_char: char) {
            description("invalid character for strand conversion")
            display("character {:?} can not be converted to a Strand", invalid_char)
        }
    }
}

/// In place implementation of scan over a slice.
pub fn scan<T: Copy, F: Fn(T, T) -> T>(a: &mut [T], op: F) {
    let mut s = a[0];
    for v in a.iter_mut().skip(1) {
        s = op(s, *v);
        *v = s;
    }
}

// Inplace implementation of prescan over a slice.
pub fn prescan<T: Copy, F: Fn(T, T) -> T>(a: &mut [T], neutral: T, op: F) {
    let mut s = neutral;
    for v in a.iter_mut() {
        let t = *v;
        *v = s;
        s = op(s, t);
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_scan() {
        let mut a = vec![1, 0, 0, 1];
        scan(&mut a[..], |a, b| a + b);
        assert_eq!(a, vec![1, 1, 1, 2]);
    }

    #[test]
    fn test_prescan() {
        let mut a = vec![1, 0, 0, 1];
        prescan(&mut a[..], 0, |a, b| a + b);
        assert_eq!(a, vec![0, 1, 1, 1]);
    }

    #[test]
    fn test_strand() {
        assert_eq!(Strand::from_char(&'+').unwrap(), Strand::Forward);
        assert_eq!(Strand::from_char(&'-').unwrap(), Strand::Reverse);
        assert!(Strand::from_char(&'.').unwrap().is_unknown());
        assert!(Strand::from_char(&'o').is_err());
    }
}
<commit_msg>Make it easier to use Strand in hashed structs (#145)<commit_after>// Copyright 2014-2016 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Common utilities.

mod text;
pub use self::text::{Text, TextSlice, TextIterator, IntoTextIterator, trim_newline};

mod nonnanfloat;
pub use self::nonnanfloat::NonNaNFloat;

mod interval;
pub use self::interval::{Interval, IntervalError};

/// Strand information.
#[derive(Debug, Clone, Copy, Hash)]
pub enum Strand {
    Forward,
    Reverse,
    Unknown,
}

impl PartialEq for Strand {
    /// Returns true if both are `Forward` or both are `Reverse`, otherwise returns false.
    fn eq(&self, other: &Strand) -> bool {
        match (self, other) {
            (&Strand::Forward, &Strand::Forward) => true,
            (&Strand::Reverse, &Strand::Reverse) => true,
            _ => false
        }
    }
}

impl Strand {

    /// Returns a `Strand` enum representing the given char.
    ///
    /// The mapping is as follows:
    ///     * '+', 'f', or 'F' becomes `Strand::Forward`
    ///     * '-', 'r', or 'R' becomes `Strand::Reverse`
    ///     * '.', '?' becomes `Strand::Unknown`
    ///     * Any other inputs will return an `Err(StrandError::InvalidChar)`
    pub fn from_char(strand_char: &char) -> Result<Strand, StrandError> {
        match *strand_char {
            '+' | 'f' | 'F' => Ok(Strand::Forward),
            '-' | 'r' | 'R' => Ok(Strand::Reverse),
            '.' | '?'  => Ok(Strand::Unknown),
            invalid => Err(StrandError::InvalidChar(invalid)),
        }
    }

    pub fn is_unknown(&self) -> bool {
        if let &Strand::Unknown = self {
            true
        } else {
            false
        }
    }
}

quick_error! {
    #[derive(Debug)]
    pub enum StrandError {
        InvalidChar(invalid_char: char) {
            description("invalid character for strand conversion")
            display("character {:?} can not be converted to a Strand", invalid_char)
        }
    }
}

/// In place implementation of scan over a slice.
pub fn scan<T: Copy, F: Fn(T, T) -> T>(a: &mut [T], op: F) {
    let mut s = a[0];
    for v in a.iter_mut().skip(1) {
        s = op(s, *v);
        *v = s;
    }
}

// Inplace implementation of prescan over a slice.
pub fn prescan<T: Copy, F: Fn(T, T) -> T>(a: &mut [T], neutral: T, op: F) {
    let mut s = neutral;
    for v in a.iter_mut() {
        let t = *v;
        *v = s;
        s = op(s, t);
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_scan() {
        let mut a = vec![1, 0, 0, 1];
        scan(&mut a[..], |a, b| a + b);
        assert_eq!(a, vec![1, 1, 1, 2]);
    }

    #[test]
    fn test_prescan() {
        let mut a = vec![1, 0, 0, 1];
        prescan(&mut a[..], 0, |a, b| a + b);
        assert_eq!(a, vec![0, 1, 1, 1]);
    }

    #[test]
    fn test_strand() {
        assert_eq!(Strand::from_char(&'+').unwrap(), Strand::Forward);
        assert_eq!(Strand::from_char(&'-').unwrap(), Strand::Reverse);
        assert!(Strand::from_char(&'.').unwrap().is_unknown());
        assert!(Strand::from_char(&'o').is_err());
    }
}
<|endoftext|>