<commit_before>#![feature(inner_deref)]

extern crate cargo_metadata;

use std::path::{PathBuf, Path};
use std::io::{self, Write};
use std::process::Command;
use std::fs::{self, File};

const CARGO_MIRI_HELP: &str = r#"Interprets bin crates

Usage:
    cargo miri [subcommand] [options] [--] [<opts>...]

Subcommands:
    run                      Run binaries (default)
    test                     Run tests
    setup                    Only perform automatic setup, but without asking questions (for getting a proper libstd)

Common options:
    -h, --help               Print this message
    --features               Features to compile for the package
    -V, --version            Print version info and exit

Other options are the same as `cargo rustc`.

The feature `cargo-miri` is automatically defined for convenience. You can use
it to configure the resource limits

    #![cfg_attr(feature = "cargo-miri", memory_size = 42)]

available resource limits are `memory_size`, `step_limit`, `stack_limit`
"#;

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum MiriCommand {
    Run,
    Test,
    Setup,
}

fn show_help() {
    println!("{}", CARGO_MIRI_HELP);
}

fn show_version() {
    println!("miri {} ({} {})",
        env!("CARGO_PKG_VERSION"), env!("VERGEN_SHA_SHORT"), env!("VERGEN_COMMIT_DATE"));
}

fn show_error(msg: String) -> ! {
    eprintln!("fatal error: {}", msg);
    std::process::exit(1)
}

fn get_arg_flag_value(name: &str) -> Option<String> {
    // stop searching at `--`
    let mut args = std::env::args().skip_while(|val| !(val.starts_with(name) || val == "--"));

    match args.next() {
        Some(ref p) if p == "--" => None,
        Some(ref p) if p == name => args.next(),
        Some(p) => {
            // Make sure this really starts with `$name=`, we didn't test for the `=` yet.
            let v = &p[name.len()..]; // strip leading `$name`
            if v.starts_with('=') {
                Some(v[1..].to_owned()) // strip leading `=`
            } else {
                None
            }
        },
        None => None,
    }
}

fn list_targets() -> impl Iterator<Item=cargo_metadata::Target> {
    // We need to get the manifest, and then the metadata, to enumerate targets.
    let manifest_path = get_arg_flag_value("--manifest-path").map(|m|
        Path::new(&m).canonicalize().unwrap()
    );

    let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(
        manifest_path.as_ref().map(AsRef::as_ref),
    )
    {
        metadata
    } else {
        show_error(format!("error: Could not obtain cargo metadata."));
    };

    let current_dir = std::env::current_dir();

    let package_index = metadata
        .packages
        .iter()
        .position(|package| {
            let package_manifest_path = Path::new(&package.manifest_path);
            if let Some(ref manifest_path) = manifest_path {
                package_manifest_path == manifest_path
            } else {
                let current_dir = current_dir.as_ref().expect(
                    "could not read current directory",
                );
                let package_manifest_directory = package_manifest_path.parent().expect(
                    "could not find parent directory of package manifest",
                );
                package_manifest_directory == current_dir
            }
        })
        .expect("could not find matching package");
    let package = metadata.packages.remove(package_index);

    // Finally we got the list of targets to build
    package.targets.into_iter()
}

fn ask(question: &str) {
    let mut buf = String::new();
    print!("{} [Y/n] ", question);
    io::stdout().flush().unwrap();
    io::stdin().read_line(&mut buf).unwrap();
    match buf.trim().to_lowercase().as_ref() {
        "" | "y" | "yes" => {}, // proceed
        "n" | "no" => show_error(format!("Aborting as per your request")),
        a => show_error(format!("I do not understand `{}`", a))
    };
}

/// Perform the setup requires to make `cargo miri` work: Getting a custom-built libstd. Then sets MIRI_SYSROOT.
/// Skipped if MIRI_SYSROOT is already set, in that case we expect the user has done all this already.
fn setup(ask_user: bool) {
    if std::env::var("MIRI_SYSROOT").is_ok() {
        return;
    }

    // First, we need xargo
    if Command::new("xargo").arg("--version").output().is_err()
    {
        if ask_user {
            ask("It seems you do not have xargo installed. I will run `cargo install xargo`. Proceed?");
        } else {
            println!("Installing xargo: `cargo install xargo`");
        }
        if !Command::new("cargo").args(&["install", "xargo"]).status().unwrap().success() {
            show_error(format!("Failed to install xargo"));
        }
    }

    // Then, we also need rust-src.  Let's see if it is already installed.
    let sysroot = Command::new("rustc").args(&["--print", "sysroot"]).output().unwrap().stdout;
    let sysroot = std::str::from_utf8(&sysroot[..]).unwrap();
    let src = Path::new(sysroot.trim_end_matches('\n')).join("lib").join("rustlib").join("src");
    if !src.exists() {
        if ask_user {
            ask("It seems you do not have the rust-src component installed. I will run `rustup component add rust-src`. Proceed?");
        } else {
            println!("Installing rust-src component: `rustup component add rust-src`");
        }
        if !Command::new("rustup").args(&["component", "add", "rust-src"]).status().unwrap().success() {
            show_error(format!("Failed to install rust-src component"));
        }
    }

    // Next, we need our own libstd. We will do this work in whatever is a good cache dir for this platform.
    let dirs = directories::ProjectDirs::from("miri", "miri", "miri").unwrap();
    let dir = dirs.cache_dir();
    if !dir.exists() {
        fs::create_dir_all(&dir).unwrap();
    }
    // The interesting bit: Xargo.toml
    File::create(dir.join("Xargo.toml")).unwrap()
        .write_all(br#"
[dependencies.std]
default_features = false
# We need the `panic_unwind` feature because we use the `unwind` panic strategy.
# Using `abort` works for libstd, but then libtest will not compile.
features = ["panic_unwind"]

[dependencies.test]
stage = 1
        "#).unwrap();
    // The boring bits: A dummy project for xargo
    File::create(dir.join("Cargo.toml")).unwrap()
        .write_all(br#"
[package]
name = "miri-xargo"
description = "A dummy project for building libstd with xargo."
version = "0.0.0"

[lib]
path = "lib.rs"
        "#).unwrap();
    File::create(dir.join("lib.rs")).unwrap();
    // Run xargo
    let target = get_arg_flag_value("--target");
    let mut command = Command::new("xargo");
    command.arg("build").arg("-q")
        .current_dir(&dir)
        .env("RUSTFLAGS", miri::miri_default_args().join(" "))
        .env("XARGO_HOME", dir.to_str().unwrap());
    if let Some(ref target) = target {
        command.arg("--target").arg(&target);
    }
    if !command.status().unwrap().success()
    {
        show_error(format!("Failed to run xargo"));
    }

    // That should be it!  But we need to figure out where xargo built stuff.
    // Unfortunately, it puts things into a different directory when the
    // architecture matches the host.
    let is_host = match target {
        None => true,
        Some(target) => target == rustc_version::version_meta().unwrap().host,
    };
    let sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) };
    std::env::set_var("MIRI_SYSROOT", &sysroot);
    if !ask_user {
        println!("A libstd for miri is now available in `{}`", sysroot.display());
    }
}

fn main() {
    // Check for version and help flags even when invoked as 'cargo-miri'
    if std::env::args().any(|a| a == "--help" || a == "-h") {
        show_help();
        return;
    }
    if std::env::args().any(|a| a == "--version" || a == "-V") {
        show_version();
        return;
    }

    if let Some("miri") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) {
        // this arm is when `cargo miri` is called.  We call `cargo rustc` for
        // each applicable target, but with the RUSTC env var set to the `cargo-miri`
        // binary so that we come back in the other branch, and dispatch
        // the invocations to rustc and miri, respectively.

        let (subcommand, skip) = match std::env::args().nth(2).deref() {
            Some("test") => (MiriCommand::Test, 3),
            Some("run") => (MiriCommand::Run, 3),
            Some("setup") => (MiriCommand::Setup, 3),
            // Default command, if there is an option or nothing
            Some(s) if s.starts_with("-") => (MiriCommand::Run, 2),
            None => (MiriCommand::Run, 2),
            // Unvalid command
            Some(s) => {
                show_error(format!("Unknown command `{}`", s))
            }
        };

        // We always setup
        let ask = subcommand != MiriCommand::Setup;
        setup(ask);
        if subcommand == MiriCommand::Setup {
            // Stop here.
            return;
        }

        // Now run the command.
        for target in list_targets() {
            let args = std::env::args().skip(skip);
            let kind = target.kind.get(0).expect(
                "badly formatted cargo metadata: target::kind is an empty array",
            );
            match (subcommand, &kind[..]) {
                (MiriCommand::Test, "test") => {
                    // For test binaries we call `cargo rustc --test target -- <rustc args>`
                    if let Err(code) = process(
                        vec!["--test".to_string(), target.name].into_iter().chain(
                            args,
                        ),
                    )
                    {
                        std::process::exit(code);
                    }
                }
                (MiriCommand::Test, "lib") => {
                    // For libraries we call `cargo rustc -- --test <rustc args>`
                    // Notice now that `--test` is a rustc arg rather than a cargo arg. This tells
                    // rustc to build a test harness which calls all #[test] functions. We don't
                    // use the harness since we execute each #[test] function's MIR ourselves before
                    // compilation even completes, but this option is necessary to build the library.
                    if let Err(code) = process(
                        vec!["--".to_string(), "--test".to_string()].into_iter().chain(
                            args,
                        ),
                    )
                    {
                        std::process::exit(code);
                    }
                }
                (MiriCommand::Run, "bin") => {
                    // For ordinary binaries we call `cargo rustc --bin target -- <rustc args>`
                    if let Err(code) = process(
                        vec!["--bin".to_string(), target.name].into_iter().chain(
                            args,
                        ),
                    )
                    {
                        std::process::exit(code);
                    }
                }
                _ => {}
            }
        }
    } else {
        // This arm is executed when cargo-miri runs `cargo rustc` with the `RUSTC` env var set to itself:
        // Dependencies get dispatched to rustc, the final test/binary to miri.

        let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
        let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
        let sys_root = if let Ok(sysroot) = ::std::env::var("MIRI_SYSROOT") {
            sysroot
        } else if let (Some(home), Some(toolchain)) = (home, toolchain) {
            format!("{}/toolchains/{}", home, toolchain)
        } else {
            option_env!("RUST_SYSROOT")
                .map(|s| s.to_owned())
                .or_else(|| {
                    Command::new("rustc")
                        .arg("--print")
                        .arg("sysroot")
                        .output()
                        .ok()
                        .and_then(|out| String::from_utf8(out.stdout).ok())
                        .map(|s| s.trim().to_owned())
                })
                .expect("need to specify RUST_SYSROOT env var during miri compilation, or use rustup or multirust")
        };

        // this conditional check for the --sysroot flag is there so users can call `cargo-miri` directly
        // without having to pass --sysroot or anything
        let mut args: Vec<String> = if std::env::args().any(|s| s == "--sysroot") {
            std::env::args().skip(1).collect()
        } else {
            std::env::args()
                .skip(1)
                .chain(Some("--sysroot".to_owned()))
                .chain(Some(sys_root))
                .collect()
        };
        args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string));
        args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-miri""#.to_owned()]);

        // this check ensures that dependencies are built but not interpreted and the final crate is
        // interpreted but not built
        let miri_enabled = std::env::args().any(|s| s == "--emit=dep-info,metadata");
        let mut command = if miri_enabled {
            let mut path = std::env::current_exe().expect("current executable path invalid");
            path.set_file_name("miri");
            Command::new(path)
        } else {
            Command::new("rustc")
        };
        command.args(&args);

        match command.status() {
            Ok(exit) => {
                if !exit.success() {
                    std::process::exit(exit.code().unwrap_or(42));
                }
            }
            Err(ref e) if miri_enabled => panic!("error during miri run: {:?}", e),
            Err(ref e) => panic!("error during rustc call: {:?}", e),
        }
    }
}

fn process<I>(old_args: I) -> Result<(), i32>
where
    I: Iterator<Item = String>,
{
    let mut args = vec!["rustc".to_owned()];

    let mut found_dashes = false;
    for arg in old_args {
        found_dashes |= arg == "--";
        args.push(arg);
    }
    if !found_dashes {
        args.push("--".to_owned());
    }
    args.push("--emit=dep-info,metadata".to_owned());
    args.push("--cfg".to_owned());
    args.push(r#"feature="cargo-miri""#.to_owned());

    let path = std::env::current_exe().expect("current executable path invalid");
    let exit_status = Command::new("cargo")
        .args(&args)
        .env("RUSTC", path)
        .spawn()
        .expect("could not run cargo")
        .wait()
        .expect("failed to wait for cargo?");

    if exit_status.success() {
        Ok(())
    } else {
        Err(exit_status.code().unwrap_or(-1))
    }
}
<commit_msg>use RUSTC_WRAPPER for the cargo hook<commit_after>#![feature(inner_deref)]

extern crate cargo_metadata;

use std::path::{PathBuf, Path};
use std::io::{self, Write};
use std::process::Command;
use std::fs::{self, File};

const CARGO_MIRI_HELP: &str = r#"Interprets bin crates

Usage:
    cargo miri [subcommand] [options] [--] [<opts>...]

Subcommands:
    run                      Run binaries (default)
    test                     Run tests
    setup                    Only perform automatic setup, but without asking questions (for getting a proper libstd)

Common options:
    -h, --help               Print this message
    --features               Features to compile for the package
    -V, --version            Print version info and exit

Other options are the same as `cargo rustc`.

The feature `cargo-miri` is automatically defined for convenience. You can use
it to configure the resource limits

    #![cfg_attr(feature = "cargo-miri", memory_size = 42)]

available resource limits are `memory_size`, `step_limit`, `stack_limit`
"#;

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum MiriCommand {
    Run,
    Test,
    Setup,
}

fn show_help() {
    println!("{}", CARGO_MIRI_HELP);
}

fn show_version() {
    println!("miri {} ({} {})",
        env!("CARGO_PKG_VERSION"), env!("VERGEN_SHA_SHORT"), env!("VERGEN_COMMIT_DATE"));
}

fn show_error(msg: String) -> ! {
    eprintln!("fatal error: {}", msg);
    std::process::exit(1)
}

fn get_arg_flag_value(name: &str) -> Option<String> {
    // stop searching at `--`
    let mut args = std::env::args().skip_while(|val| !(val.starts_with(name) || val == "--"));

    match args.next() {
        Some(ref p) if p == "--" => None,
        Some(ref p) if p == name => args.next(),
        Some(p) => {
            // Make sure this really starts with `$name=`, we didn't test for the `=` yet.
            let v = &p[name.len()..]; // strip leading `$name`
            if v.starts_with('=') {
                Some(v[1..].to_owned()) // strip leading `=`
            } else {
                None
            }
        },
        None => None,
    }
}

fn list_targets() -> impl Iterator<Item=cargo_metadata::Target> {
    // We need to get the manifest, and then the metadata, to enumerate targets.
    let manifest_path = get_arg_flag_value("--manifest-path").map(|m|
        Path::new(&m).canonicalize().unwrap()
    );

    let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(
        manifest_path.as_ref().map(AsRef::as_ref),
    )
    {
        metadata
    } else {
        show_error(format!("error: Could not obtain cargo metadata."));
    };

    let current_dir = std::env::current_dir();

    let package_index = metadata
        .packages
        .iter()
        .position(|package| {
            let package_manifest_path = Path::new(&package.manifest_path);
            if let Some(ref manifest_path) = manifest_path {
                package_manifest_path == manifest_path
            } else {
                let current_dir = current_dir.as_ref().expect(
                    "could not read current directory",
                );
                let package_manifest_directory = package_manifest_path.parent().expect(
                    "could not find parent directory of package manifest",
                );
                package_manifest_directory == current_dir
            }
        })
        .expect("could not find matching package");
    let package = metadata.packages.remove(package_index);

    // Finally we got the list of targets to build
    package.targets.into_iter()
}

fn ask(question: &str) {
    let mut buf = String::new();
    print!("{} [Y/n] ", question);
    io::stdout().flush().unwrap();
    io::stdin().read_line(&mut buf).unwrap();
    match buf.trim().to_lowercase().as_ref() {
        "" | "y" | "yes" => {}, // proceed
        "n" | "no" => show_error(format!("Aborting as per your request")),
        a => show_error(format!("I do not understand `{}`", a))
    };
}

/// Perform the setup requires to make `cargo miri` work: Getting a custom-built libstd. Then sets MIRI_SYSROOT.
/// Skipped if MIRI_SYSROOT is already set, in that case we expect the user has done all this already.
fn setup(ask_user: bool) {
    if std::env::var("MIRI_SYSROOT").is_ok() {
        return;
    }

    // First, we need xargo
    if Command::new("xargo").arg("--version").output().is_err()
    {
        if ask_user {
            ask("It seems you do not have xargo installed. I will run `cargo install xargo`. Proceed?");
        } else {
            println!("Installing xargo: `cargo install xargo`");
        }
        if !Command::new("cargo").args(&["install", "xargo"]).status().unwrap().success() {
            show_error(format!("Failed to install xargo"));
        }
    }

    // Then, we also need rust-src.  Let's see if it is already installed.
    let sysroot = Command::new("rustc").args(&["--print", "sysroot"]).output().unwrap().stdout;
    let sysroot = std::str::from_utf8(&sysroot[..]).unwrap();
    let src = Path::new(sysroot.trim_end_matches('\n')).join("lib").join("rustlib").join("src");
    if !src.exists() {
        if ask_user {
            ask("It seems you do not have the rust-src component installed. I will run `rustup component add rust-src`. Proceed?");
        } else {
            println!("Installing rust-src component: `rustup component add rust-src`");
        }
        if !Command::new("rustup").args(&["component", "add", "rust-src"]).status().unwrap().success() {
            show_error(format!("Failed to install rust-src component"));
        }
    }

    // Next, we need our own libstd. We will do this work in whatever is a good cache dir for this platform.
    let dirs = directories::ProjectDirs::from("miri", "miri", "miri").unwrap();
    let dir = dirs.cache_dir();
    if !dir.exists() {
        fs::create_dir_all(&dir).unwrap();
    }
    // The interesting bit: Xargo.toml
    File::create(dir.join("Xargo.toml")).unwrap()
        .write_all(br#"
[dependencies.std]
default_features = false
# We need the `panic_unwind` feature because we use the `unwind` panic strategy.
# Using `abort` works for libstd, but then libtest will not compile.
features = ["panic_unwind"]

[dependencies.test]
stage = 1
        "#).unwrap();
    // The boring bits: A dummy project for xargo
    File::create(dir.join("Cargo.toml")).unwrap()
        .write_all(br#"
[package]
name = "miri-xargo"
description = "A dummy project for building libstd with xargo."
version = "0.0.0"

[lib]
path = "lib.rs"
        "#).unwrap();
    File::create(dir.join("lib.rs")).unwrap();
    // Run xargo
    let target = get_arg_flag_value("--target");
    let mut command = Command::new("xargo");
    command.arg("build").arg("-q")
        .current_dir(&dir)
        .env("RUSTFLAGS", miri::miri_default_args().join(" "))
        .env("XARGO_HOME", dir.to_str().unwrap());
    if let Some(ref target) = target {
        command.arg("--target").arg(&target);
    }
    if !command.status().unwrap().success()
    {
        show_error(format!("Failed to run xargo"));
    }

    // That should be it!  But we need to figure out where xargo built stuff.
    // Unfortunately, it puts things into a different directory when the
    // architecture matches the host.
    let is_host = match target {
        None => true,
        Some(target) => target == rustc_version::version_meta().unwrap().host,
    };
    let sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) };
    std::env::set_var("MIRI_SYSROOT", &sysroot);
    if !ask_user {
        println!("A libstd for miri is now available in `{}`", sysroot.display());
    }
}

fn main() {
    // Check for version and help flags even when invoked as 'cargo-miri'
    if std::env::args().any(|a| a == "--help" || a == "-h") {
        show_help();
        return;
    }
    if std::env::args().any(|a| a == "--version" || a == "-V") {
        show_version();
        return;
    }

    if let Some("miri") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) {
        // this arm is when `cargo miri` is called.  We call `cargo rustc` for
        // each applicable target, but with the RUSTC env var set to the `cargo-miri`
        // binary so that we come back in the other branch, and dispatch
        // the invocations to rustc and miri, respectively.

        let (subcommand, skip) = match std::env::args().nth(2).deref() {
            Some("test") => (MiriCommand::Test, 3),
            Some("run") => (MiriCommand::Run, 3),
            Some("setup") => (MiriCommand::Setup, 3),
            // Default command, if there is an option or nothing
            Some(s) if s.starts_with("-") => (MiriCommand::Run, 2),
            None => (MiriCommand::Run, 2),
            // Unvalid command
            Some(s) => {
                show_error(format!("Unknown command `{}`", s))
            }
        };

        // We always setup
        let ask = subcommand != MiriCommand::Setup;
        setup(ask);
        if subcommand == MiriCommand::Setup {
            // Stop here.
            return;
        }

        // Now run the command.
        for target in list_targets() {
            let args = std::env::args().skip(skip);
            let kind = target.kind.get(0).expect(
                "badly formatted cargo metadata: target::kind is an empty array",
            );
            match (subcommand, &kind[..]) {
                (MiriCommand::Test, "test") => {
                    // For test binaries we call `cargo rustc --test target -- <rustc args>`
                    if let Err(code) = process(
                        vec!["--test".to_string(), target.name].into_iter().chain(
                            args,
                        ),
                    )
                    {
                        std::process::exit(code);
                    }
                }
                (MiriCommand::Test, "lib") => {
                    // For libraries we call `cargo rustc -- --test <rustc args>`
                    // Notice now that `--test` is a rustc arg rather than a cargo arg. This tells
                    // rustc to build a test harness which calls all #[test] functions. We don't
                    // use the harness since we execute each #[test] function's MIR ourselves before
                    // compilation even completes, but this option is necessary to build the library.
                    if let Err(code) = process(
                        vec!["--".to_string(), "--test".to_string()].into_iter().chain(
                            args,
                        ),
                    )
                    {
                        std::process::exit(code);
                    }
                }
                (MiriCommand::Run, "bin") => {
                    // For ordinary binaries we call `cargo rustc --bin target -- <rustc args>`
                    if let Err(code) = process(
                        vec!["--bin".to_string(), target.name].into_iter().chain(
                            args,
                        ),
                    )
                    {
                        std::process::exit(code);
                    }
                }
                _ => {}
            }
        }
    } else if let Some("rustc") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) {
        // This arm is executed when cargo-miri runs `cargo rustc` with the `RUSTC_WRAPPER` env var set to itself:
        // Dependencies get dispatched to rustc, the final test/binary to miri.

        let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
        let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
        let sys_root = if let Ok(sysroot) = ::std::env::var("MIRI_SYSROOT") {
            sysroot
        } else if let (Some(home), Some(toolchain)) = (home, toolchain) {
            format!("{}/toolchains/{}", home, toolchain)
        } else {
            option_env!("RUST_SYSROOT")
                .map(|s| s.to_owned())
                .or_else(|| {
                    Command::new("rustc")
                        .arg("--print")
                        .arg("sysroot")
                        .output()
                        .ok()
                        .and_then(|out| String::from_utf8(out.stdout).ok())
                        .map(|s| s.trim().to_owned())
                })
                .expect("need to specify RUST_SYSROOT env var during miri compilation, or use rustup or multirust")
        };

        // this conditional check for the --sysroot flag is there so users can call `cargo-miri` directly
        // without having to pass --sysroot or anything
        let rustc_args = std::env::args().skip(2);
        let mut args: Vec<String> = if std::env::args().any(|s| s == "--sysroot") {
            rustc_args.collect()
        } else {
            rustc_args
                .chain(Some("--sysroot".to_owned()))
                .chain(Some(sys_root))
                .collect()
        };
        args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string));
        args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-miri""#.to_owned()]);

        // this check ensures that dependencies are built but not interpreted and the final crate is
        // interpreted but not built
        let miri_enabled = std::env::args().any(|s| s == "--emit=dep-info,metadata");
        let mut command = if miri_enabled {
            let mut path = std::env::current_exe().expect("current executable path invalid");
            path.set_file_name("miri");
            Command::new(path)
        } else {
            Command::new("rustc")
        };
        command.args(&args);

        match command.status() {
            Ok(exit) => {
                if !exit.success() {
                    std::process::exit(exit.code().unwrap_or(42));
                }
            }
            Err(ref e) if miri_enabled => panic!("error during miri run: {:?}", e),
            Err(ref e) => panic!("error during rustc call: {:?}", e),
        }
    } else {
        eprintln!("Unexpected call: Must be called with either `miri` or `rustc` as first argument.")
    }
}

fn process<I>(old_args: I) -> Result<(), i32>
where
    I: Iterator<Item = String>,
{
    let mut args = vec!["rustc".to_owned()];

    let mut found_dashes = false;
    for arg in old_args {
        found_dashes |= arg == "--";
        args.push(arg);
    }
    if !found_dashes {
        args.push("--".to_owned());
    }
    args.push("--emit=dep-info,metadata".to_owned());
    args.push("--cfg".to_owned());
    args.push(r#"feature="cargo-miri""#.to_owned());

    let path = std::env::current_exe().expect("current executable path invalid");
    let exit_status = Command::new("cargo")
        .args(&args)
        .env("RUSTC_WRAPPER", path)
        .spawn()
        .expect("could not run cargo")
        .wait()
        .expect("failed to wait for cargo?");

    if exit_status.success() {
        Ok(())
    } else {
        Err(exit_status.code().unwrap_or(-1))
    }
}
<|endoftext|>


<commit_before><commit_msg>FIX : Correct way to handle multiple write! macros and their result.<commit_after><|endoftext|>


<commit_before>// use std::iter::Iterator;
use std::ops::Index;
use std::collections::LinkedList;
use super::ST;

pub struct LinkedST<K, V> {
    /// Maintain an (unordered) linked list of key-value pairs.
    t: LinkedList<(K,V)>
}

impl<K: Eq, V> ST<K,V> for LinkedST<K, V> {
    fn new() -> Self {
        LinkedST {
            t: LinkedList::new()
        }
    }

    fn put(&mut self, key: K, val: V) {
        self.t.push_front((key,val))
    }

    fn get(&self, key: &K) -> Option<&V> {
        for &(ref k, ref v) in self.t.iter() {
            if k == key {
                return Some(v)
            }
        }
        None
    }

    // FIXME: can't be used to add new pairs
    // fn get_mut(&mut self, key: &K) -> Option<&mut V> {
    //     for pairs in self.t.iter_mut() {
    //         if &pairs.0 == key {
    //             return Some(&mut pairs.1)
    //         }
    //     }
    //     None
    // }

    fn delete(&mut self, key: &K) {
        let mut i = 0;
        let mut found = false;
        for &(ref k, _) in self.t.iter() {
            if k == key {
                found = true;
                break
            } else {
                i += 1;
            }
        }

        if found {
            let mut remains = self.t.split_off(i);
            // delete i-th
            self.t.pop_back();
            self.t.append(&mut remains)
        }
    }

    /// is the table empty?
    fn is_empty(&self) -> bool {
        self.t.len() == 0
    }

    fn size(&self) -> usize {
        self.t.len()
    }

    // fn keys() -> Iterator<Item=K> {
    //     unimplemented!()
    // }
}

impl<K: Eq, V> Index<K> for LinkedST<K, V> {
    type Output = V;

    fn index<'a>(&'a self, index: K) -> &'a Self::Output {
        self.get(&index).unwrap()
    }
}

// impl<K: Eq, V> IndexMut<K> for LinkedST<K, V> {
//     fn index_mut<'a>(&'a mut self, index: K) -> &'a mut Self::Output {
//         self.get_mut(&index).unwrap()
//     }
//  }

#[test]
fn test_linked_symbol_table() {
    let mut st: LinkedST<char,usize> = ST::new();
    assert!(st.is_empty());
    for (i, c) in "SEARCHEXAMPLE".chars().enumerate() {
        st.put(c, i);
    }

    assert_eq!(st.get(&'X'), Some(&7));
    assert_eq!(st.get(&'E'), Some(&12));
    assert_eq!(st['E'], 12);
    assert_eq!(st.size(), 13);
    // st['Z'] = 233;
    assert_eq!(st.is_empty(), false);
}
<commit_msg>symbol_tables/linked_st: fixed bug in LinkedST<commit_after>// use std::iter::Iterator;
use std::ops::Index;
use std::collections::LinkedList;
use super::ST;

pub struct LinkedST<K, V> {
    /// Maintain an (unordered) linked list of key-value pairs.
    t: LinkedList<(K,V)>
}

impl<K: Eq, V> ST<K,V> for LinkedST<K, V> {
    fn new() -> Self {
        LinkedST {
            t: LinkedList::new()
        }
    }

    fn put(&mut self, key: K, val: V) {
        for &mut (ref mut k, ref mut v) in self.t.iter_mut() {
            if k == &key {
                *v = val;
                return;
            }
        }
        self.t.push_front((key,val))
    }

    fn get(&self, key: &K) -> Option<&V> {
        for &(ref k, ref v) in self.t.iter() {
            if k == key {
                return Some(v)
            }
        }
        None
    }

    // FIXME: can't be used to add new pairs
    // fn get_mut(&mut self, key: &K) -> Option<&mut V> {
    //     for pairs in self.t.iter_mut() {
    //         if &pairs.0 == key {
    //             return Some(&mut pairs.1)
    //         }
    //     }
    //     None
    // }

    fn delete(&mut self, key: &K) {
        let mut i = 0;
        let mut found = false;
        for &(ref k, _) in self.t.iter() {
            if k == key {
                found = true;
                break
            } else {
                i += 1;
            }
        }

        if found {
            let mut remains = self.t.split_off(i);
            // delete i-th
            self.t.pop_back();
            self.t.append(&mut remains)
        }
    }

    /// is the table empty?
    fn is_empty(&self) -> bool {
        self.t.len() == 0
    }

    fn size(&self) -> usize {
        self.t.len()
    }

    // fn keys() -> Iterator<Item=K> {
    //     unimplemented!()
    // }
}

impl<K: Eq, V> Index<K> for LinkedST<K, V> {
    type Output = V;

    fn index<'a>(&'a self, index: K) -> &'a Self::Output {
        self.get(&index).unwrap()
    }
}

// impl<K: Eq, V> IndexMut<K> for LinkedST<K, V> {
//     fn index_mut<'a>(&'a mut self, index: K) -> &'a mut Self::Output {
//         self.get_mut(&index).unwrap()
//     }
//  }

#[test]
fn test_linked_symbol_table() {
    let mut st: LinkedST<char,usize> = ST::new();
    assert!(st.is_empty());
    for (i, c) in "SEARCHEXAMPLE".chars().enumerate() {
        st.put(c, i);
    }

    assert_eq!(st.get(&'X'), Some(&7));
    assert_eq!(st.get(&'E'), Some(&12));
    assert_eq!(st['E'], 12);
    println!("got => {:?}", st.t);
    assert_eq!(st.size(), 10);
    // st['Z'] = 233;
    assert_eq!(st.is_empty(), false);
}
<|endoftext|>


<commit_before>tag maybe_pointy {
    no_pointy;
    yes_pointy(@pointy);
}

type pointy = {
    mutable x : maybe_pointy
};

fn main() {
    let m = @{ mutable x : no_pointy };
    m.x = yes_pointy(m);
}
<commit_msg>Try to appease windows by xfail-win32'ing a random test<commit_after>// xfail-win32 - random windows breakage

tag maybe_pointy {
    no_pointy;
    yes_pointy(@pointy);
}

type pointy = {
    mutable x : maybe_pointy
};

fn main() {
    let m = @{ mutable x : no_pointy };
    m.x = yes_pointy(m);
}
<|endoftext|>


<commit_before><commit_msg>cache field norm reader in merge (#1061)<commit_after><|endoftext|>


<commit_before>use webapi::event_target::{IEventTarget, EventTarget};
use webapi::dom_exception::{InvalidAccessError, InvalidStateError};
use webcore::unsafe_typed_array::UnsafeTypedArray;
use webcore::value::{
    Reference,
    Value,
};
use webcore::try_from::{TryFrom, TryInto};
use private::TODO;

/// Use XmlHttpRequest (XHR) objects to interact with servers.
/// You can retrieve data from a URL without having to do a full page refresh.
/// This enables a Web page to update just part of a page without disrupting
/// what the user is doing. XmlHttpRequest is used heavily in Ajax programming.
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XmlHttpRequest)
// https://xhr.spec.whatwg.org/#xmlhttprequest
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "XMLHttpRequest")]
#[reference(subclass_of(EventTarget))]
pub struct XmlHttpRequest( Reference );

/// An enum indicating the state of the `XmlHttpRequest`.
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/readyState)
// https://xhr.spec.whatwg.org/#dom-xmlhttprequest-readystate
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum XhrReadyState {
    /// Client has been created. [open()](struct.XmlHttpRequest.html#method.open) not called yet.
    Unsent,
    /// [open()](struct.XmlHttpRequest.html#method.open) has been called.
    Opened,
    /// [send()](struct.XmlHttpRequest.html#method.send) has been called, and headers and [status()](struct.XmlHttpRequest.html#method.status) are available.
    HeadersReceived,
    /// Downloading; [reponse_text()](struct.XmlHttpRequest.html#method.reponse_text) holds partial data.
    Loading,
    /// The operation is complete.
    Done,
}

/// An enum describing the type of the response to `XmlHttpRequest`
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType)
// https://xhr.spec.whatwg.org/#dom-xmlhttprequest-responsetype
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum XhrResponseType {
    /// A JavaScript ArrayBuffer containing binary data
    ArrayBuffer,
    /// A Blob object container the binary data
    Blob,
    /// An HTML Document or XML XMLDocument
    Document,
    /// A JavaScript object parsed from JSON
    Json,
    /// Text in a String object
    Text
}

impl IEventTarget for XmlHttpRequest {}

error_enum_boilerplate! {
    SetResponseTypeError,
    InvalidStateError, InvalidAccessError
}

impl XmlHttpRequest {
    /// Creates new `XmlHttpRequest`.
    // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest
    pub fn new() -> XmlHttpRequest {
        js!( return new XMLHttpRequest(); ).try_into().unwrap()
    }

    /// Returns the current state of the request as a [XhrReadyState](enum.XhrReadyState.html).
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/readyState)
    // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-readystate
    pub fn ready_state(&self) -> XhrReadyState {
        use self::XhrReadyState::*;
        let state: u16 = js!( return @{self}.readyState; ).try_into().unwrap();
        match state {
            0 => Unsent,
            1 => Opened,
            2 => HeadersReceived,
            3 => Loading,
            4 => Done,
            _ => unreachable!( "Unexpected value of XMLHttpRequest::readyState: {}", state )
        }
    }

    /// Returns the type of the request as a [XhrResponseType](enum.XhrResponseType.html)
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType)
    // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-responsetype
    pub fn response_type(&self) -> XhrResponseType {
        use self::XhrResponseType::*;
        let repsonse_type: String = js! ( return @{self}.responseType; ).try_into().unwrap();
        match repsonse_type.as_str() {
            "arraybuffer" => ArrayBuffer,
            "blob" => Blob,
            "document" => Document,
            "json" => Json,
            "text" | "" => Text,
            x => unreachable!( "Unexpected value of XMLHttpRequest::responseType:: {}", x)
        }
    }

    /// Set the type that the XmlHttpRequest should return
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType)
    // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-responsetype
    pub fn set_response_type(&self, kind: XhrResponseType) -> Result<(), SetResponseTypeError> {
        use self::XhrResponseType::*;
        let response_type = match kind {
            ArrayBuffer => "arraybuffer",
            Blob => "blob",
            Document => "document",
            Json => "json",
            Text => "text"
        };

        js_try!(
            @{self}.responseType = @{response_type};
        ).unwrap()
    }

    /// Returns a string that contains the response to the request as text, or None
    /// if the request was unsuccessful or has not yet been sent.
    ///
    ///[(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseText)
    // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-responsetext
    pub fn response_text(&self) -> Result< Option< String >, TODO > {
        let response = js!(return @{self}.responseText;);
        match response {
            Value::Null => Ok( None ),
            Value::String( resp ) => Ok( Some( resp ) ),
            _ => unreachable!(),
        }
    }

    /// Returns the object representing the response
    ///
    ///[(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/response)
    // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-response
    pub fn raw_response(&self) -> Value {
        js!(return @{self}.response;)
    }

    /// Returns an unsigned short with the status of the response of the request.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/status)
    // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-status
    pub fn status(&self) -> u16 {
        js!(return @{self}.status;).try_into().unwrap()
    }

    /// Open connection with given method (ie GET or POST), and the url to hit.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/open)
    // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-open
    pub fn open(&self, method: &str, url: &str) -> Result< (), TODO > {
        js! { @(no_return)
            @{self}.open(@{method}, @{url}, true);
        };

        Ok(())
    }

    /// Returns the string containing the text of the specified header. If there
    /// are multiple response headers with the same name, then their values are
    /// returned as a single concatenated string.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/getResponseHeader)
    // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-getresponseheader
    pub fn get_response_header(&self, header: &str) -> Option<String> {
        let header = js!( return @{self}.getResponseHeader(@{header}); );
        match header {
            Value::Null => None,
            Value::String(text) => Some(text),
            _ => unreachable!(),
        }
    }

    /// Sets the value of an HTTP request header. Must be called after `open()`,
    /// but before `send()`. If this method is called several times with the same
    /// header, the values are merged into one single request header.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/setRequestHeader)
    // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-setrequestheader
    pub fn set_request_header(&self, header: &str, value: &str) -> Result< (), TODO > {
        js! { @(no_return)
            @{self}.setRequestHeader(@{header}, @{value});
        };

        Ok(())
    }

    /// Send request on an open connection with no data
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/send)
    // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-send
    pub fn send(&self) -> Result< (), TODO > {
        js! { @(no_return)
            @{self}.send();
        };

        Ok(())
    }

    /// Send request on an open connection with string body
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/send)
    // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-send
    pub fn send_with_string(&self, body: &str) -> Result< (), TODO > {
        js! { @(no_return)
            @{self}.send(@{body});
        };

        Ok(())
    }

    /// Send request on an open connection with a byte array body
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/send)
    // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-send
    pub fn send_with_bytes(&self, body: &[u8]) -> Result< (), TODO > {
        js! { @(no_return)
            @{self}.send(@{UnsafeTypedArray(body)});
        };

        Ok(())
    }

    /// Aborts the request if it has already been sent.
    /// When a request is aborted, its [ready_state](struct.XmlHttpRequest.html#method.ready_state) is changed to [Done](enum.XhrReadyState.html#variant.Done)
    /// and the [status](struct.XmlHttpRequest.html#method.status) code is set to
    /// [Unsent](enum.XhrReadyState.html#variant.Unsent).
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/abort)
    // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-abort
    pub fn abort(&self) {
        js! { @(no_return)
            @{self}.abort();
        };
    }
}
<commit_msg>Document `SetResponseTypeError`<commit_after>use webapi::event_target::{IEventTarget, EventTarget};
use webapi::dom_exception::{InvalidAccessError, InvalidStateError};
use webcore::unsafe_typed_array::UnsafeTypedArray;
use webcore::value::{
    Reference,
    Value,
};
use webcore::try_from::{TryFrom, TryInto};
use private::TODO;

/// Use XmlHttpRequest (XHR) objects to interact with servers.
/// You can retrieve data from a URL without having to do a full page refresh.
/// This enables a Web page to update just part of a page without disrupting
/// what the user is doing. XmlHttpRequest is used heavily in Ajax programming.
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XmlHttpRequest)
// https://xhr.spec.whatwg.org/#xmlhttprequest
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "XMLHttpRequest")]
#[reference(subclass_of(EventTarget))]
pub struct XmlHttpRequest( Reference );

/// An enum indicating the state of the `XmlHttpRequest`.
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/readyState)
// https://xhr.spec.whatwg.org/#dom-xmlhttprequest-readystate
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum XhrReadyState {
    /// Client has been created. [open()](struct.XmlHttpRequest.html#method.open) not called yet.
    Unsent,
    /// [open()](struct.XmlHttpRequest.html#method.open) has been called.
    Opened,
    /// [send()](struct.XmlHttpRequest.html#method.send) has been called, and headers and [status()](struct.XmlHttpRequest.html#method.status) are available.
    HeadersReceived,
    /// Downloading; [reponse_text()](struct.XmlHttpRequest.html#method.reponse_text) holds partial data.
    Loading,
    /// The operation is complete.
    Done,
}

/// An enum describing the type of the response to `XmlHttpRequest`
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType)
// https://xhr.spec.whatwg.org/#dom-xmlhttprequest-responsetype
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum XhrResponseType {
    /// A JavaScript ArrayBuffer containing binary data
    ArrayBuffer,
    /// A Blob object container the binary data
    Blob,
    /// An HTML Document or XML XMLDocument
    Document,
    /// A JavaScript object parsed from JSON
    Json,
    /// Text in a String object
    Text
}

impl IEventTarget for XmlHttpRequest {}

error_enum_boilerplate! {
    /// An error returned from `XmlHttpRequest::set_response_type`
    SetResponseTypeError,

    #[allow(missing_docs)]
    InvalidStateError,
    #[allow(missing_docs)]
    InvalidAccessError
}

impl XmlHttpRequest {
    /// Creates new `XmlHttpRequest`.
    // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest
    pub fn new() -> XmlHttpRequest {
        js!( return new XMLHttpRequest(); ).try_into().unwrap()
    }

    /// Returns the current state of the request as a [XhrReadyState](enum.XhrReadyState.html).
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/readyState)
    // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-readystate
    pub fn ready_state(&self) -> XhrReadyState {
        use self::XhrReadyState::*;
        let state: u16 = js!( return @{self}.readyState; ).try_into().unwrap();
        match state {
            0 => Unsent,
            1 => Opened,
            2 => HeadersReceived,
            3 => Loading,
            4 => Done,
            _ => unreachable!( "Unexpected value of XMLHttpRequest::readyState: {}", state )
        }
    }

    /// Returns the type of the request as a [XhrResponseType](enum.XhrResponseType.html)
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType)
    // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-responsetype
    pub fn response_type(&self) -> XhrResponseType {
        use self::XhrResponseType::*;
        let repsonse_type: String = js! ( return @{self}.responseType; ).try_into().unwrap();
        match repsonse_type.as_str() {
            "arraybuffer" => ArrayBuffer,
            "blob" => Blob,
            "document" => Document,
            "json" => Json,
            "text" | "" => Text,
            x => unreachable!( "Unexpected value of XMLHttpRequest::responseType:: {}", x)
        }
    }

    /// Set the type that the XmlHttpRequest should return
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType)
    // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-responsetype
    pub fn set_response_type(&self, kind: XhrResponseType) -> Result<(), SetResponseTypeError> {
        use self::XhrResponseType::*;
        let response_type = match kind {
            ArrayBuffer => "arraybuffer",
            Blob => "blob",
            Document => "document",
            Json => "json",
            Text => "text"
        };

        js_try!(
            @{self}.responseType = @{response_type};
        ).unwrap()
    }

    /// Returns a string that contains the response to the request as text, or None
    /// if the request was unsuccessful or has not yet been sent.
    ///
    ///[(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseText)
    // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-responsetext
    pub fn response_text(&self) -> Result< Option< String >, TODO > {
        let response = js!(return @{self}.responseText;);
        match response {
            Value::Null => Ok( None ),
            Value::String( resp ) => Ok( Some( resp ) ),
            _ => unreachable!(),
        }
    }

    /// Returns the object representing the response
    ///
    ///[(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/response)
    // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-response
    pub fn raw_response(&self) -> Value {
        js!(return @{self}.response;)
    }

    /// Returns an unsigned short with the status of the response of the request.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/status)
    // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-status
    pub fn status(&self) -> u16 {
        js!(return @{self}.status;).try_into().unwrap()
    }

    /// Open connection with given method (ie GET or POST), and the url to hit.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/open)
    // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-open
    pub fn open(&self, method: &str, url: &str) -> Result< (), TODO > {
        js! { @(no_return)
            @{self}.open(@{method}, @{url}, true);
        };

        Ok(())
    }

    /// Returns the string containing the text of the specified header. If there
    /// are multiple response headers with the same name, then their values are
    /// returned as a single concatenated string.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/getResponseHeader)
    // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-getresponseheader
    pub fn get_response_header(&self, header: &str) -> Option<String> {
        let header = js!( return @{self}.getResponseHeader(@{header}); );
        match header {
            Value::Null => None,
            Value::String(text) => Some(text),
            _ => unreachable!(),
        }
    }

    /// Sets the value of an HTTP request header. Must be called after `open()`,
    /// but before `send()`. If this method is called several times with the same
    /// header, the values are merged into one single request header.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/setRequestHeader)
    // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-setrequestheader
    pub fn set_request_header(&self, header: &str, value: &str) -> Result< (), TODO > {
        js! { @(no_return)
            @{self}.setRequestHeader(@{header}, @{value});
        };

        Ok(())
    }

    /// Send request on an open connection with no data
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/send)
    // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-send
    pub fn send(&self) -> Result< (), TODO > {
        js! { @(no_return)
            @{self}.send();
        };

        Ok(())
    }

    /// Send request on an open connection with string body
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/send)
    // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-send
    pub fn send_with_string(&self, body: &str) -> Result< (), TODO > {
        js! { @(no_return)
            @{self}.send(@{body});
        };

        Ok(())
    }

    /// Send request on an open connection with a byte array body
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/send)
    // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-send
    pub fn send_with_bytes(&self, body: &[u8]) -> Result< (), TODO > {
        js! { @(no_return)
            @{self}.send(@{UnsafeTypedArray(body)});
        };

        Ok(())
    }

    /// Aborts the request if it has already been sent.
    /// When a request is aborted, its [ready_state](struct.XmlHttpRequest.html#method.ready_state) is changed to [Done](enum.XhrReadyState.html#variant.Done)
    /// and the [status](struct.XmlHttpRequest.html#method.status) code is set to
    /// [Unsent](enum.XhrReadyState.html#variant.Unsent).
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/abort)
    // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-abort
    pub fn abort(&self) {
        js! { @(no_return)
            @{self}.abort();
        };
    }
}
<|endoftext|>


<commit_before><commit_msg>Adjust to ptr::Shared now handing out *const T<commit_after><|endoftext|>


<commit_before>use chrono::UTC;
use chrono::datetime::DateTime;

use params::*;

use rs_es::Client;
use rs_es::query::{Filter, Query};
use rs_es::units::{JsonVal, DurationUnit};
use rs_es::units::Duration as ESDuration;
use rs_es::operations::search::{Sort, SortField, Order};
use rs_es::operations::index::IndexResult;
use rs_es::operations::bulk::Action;
use rs_es::error::EsError;

extern crate searchspot;
use searchspot::terms::VectorOfTerms;

#[derive(RustcEncodable, RustcDecodable, Debug)]
pub struct Talent {
  pub id:                 u32,
  pub accepted:           bool,
  pub work_roles:         Vec<String>,
  pub work_languages:     Vec<String>,
  pub work_experience:    String,
  pub work_locations:     Vec<String>,
  pub work_authorization: String,
  pub company_ids:        Vec<u32>,
  pub batch_starts_at:    i64,
  pub batch_ends_at:      i64,
  pub added_to_batch_at:  i64,
  pub weight:             i32,
  pub blocked_companies:  Vec<u32>
}

impl Talent {
  /// Populate the ElasticSearch index with `self`.
  pub fn index(&self, mut es: &mut Client, index: &str) -> Result<IndexResult, EsError> {
    es.index(index, "talent")
      .with_doc(&self)
      .with_id(&*format!("{}", self.id))
      .send()
  }

  #[allow(dead_code)]
  pub fn delete_all(mut es: &mut Client, index: &str) {
    let mut scan = match es.search_query()
                           .with_indexes(&[&index])
                           .with_query(&Query::build_match_all().build())
                           .scan(ESDuration::new(1, DurationUnit::Minute)) {
                              Ok(scan) => scan,
                              Err(_)   => return
                           };

    loop {
      let     page = scan.scroll(&mut es).unwrap();
      let mut hits = page.hits.hits;

      if hits.len() == 0 {
        break;
      }

      let actions = hits.drain(..)
                        .map(|hit| {
                           Action::delete(hit.id).with_index(&*index)
                                                 .with_doc_type(hit.doc_type)
                        })
                        .collect::<Vec<Action>>();
      es.bulk(&actions)
        .send()
        .unwrap();
    }

    scan.close(&mut es)
        .unwrap();
  }

  /// Query ElasticSearch on given `indexes` and `params` and return the IDs of
  /// the found talents.
  pub fn search(mut es: &mut Client, default_index: &str, params: &Map) -> Vec<u32> {
    let epoch = match params.find(&["epoch"]) {
      Some(&Value::I64(epoch)) => epoch,
      _ => DateTime::timestamp(&UTC::now())
    };

    let index: Vec<&str> = match params.find(&["index"]) {
      Some(&Value::String(ref index)) => vec![&index[..]],
      _ => vec![default_index]
    };

    let result = es.search_query()
                   .with_indexes(&*index)
                   .with_query(&Talent::search_filters(params, epoch))
                   .with_sort(&Talent::sorting_criteria())
                   .send();

    match result {
      Ok(result) => {
        let mut results = result.hits.hits.into_iter()
                                          .map(|hit| hit.source.unwrap()["id"]
                                                               .as_u64()
                                                               .unwrap() as u32)
                                          .collect::<Vec<u32>>();
        results.dedup();
        results
      },
      Err(err) => {
        println!("{:?}", err);
        vec![]
      }
    }
  }

  /// Return a `Vec<Filter>` with visibility criteria for the talents.
  /// The `epoch` must be given as `I64` (UNIX time in seconds) and is
  /// the range in which batches are searched.
  /// If `presented_talents` is provided, talents who match the IDs
  /// contained there skip the standard visibility criteria.
  ///
  /// Basically, the talents must be accepted into the platform and must be
  /// inside a living batch to match the visibility criteria.
  fn visibility_filters(epoch: i64, presented_talents: Vec<i32>) -> Vec<Filter> {
    let visibility_rules = Filter::build_bool()
                                  .with_must(
                                    vec![
                                      Filter::build_term("accepted", true)
                                             .build(),
                                      Filter::build_range("batch_starts_at")
                                             .with_lte(JsonVal::from(epoch))
                                             .with_format("epoch_second")
                                             .build(),
                                      Filter::build_range("batch_ends_at")
                                             .with_gte(JsonVal::from(epoch))
                                             .with_format("epoch_second")
                                             .build()
                                    ])
                                  .build();

    if presented_talents.len() > 0 { // preferred over !_.is_empty()
      let presented_talents_filters = Filter::build_bool()
                                             .with_must(
                                               vec![
                                                 <Filter as VectorOfTerms<i32>>::build_terms(
                                                   "ids", &presented_talents)
                                               ].into_iter()
                                                .flat_map(|x| x)
                                                .collect::<Vec<Filter>>())
                                             .build();
      vec![
        Filter::build_bool()
               .with_should(vec![visibility_rules, presented_talents_filters])
               .build()
      ]
    }
    else {
      vec![visibility_rules]
    }
  }

  /// Given parameters inside the query string mapped inside a `Map`,
  /// and the `epoch` (defined as UNIX time in seconds) for batches,
  /// return a `Query` for ElasticSearch.
  ///
  /// `VectorOfTerms` are ORred, while `Filter`s are ANDed.
  /// I.e.: given ["Fullstack", "DevOps"] as `work_roles`, found talents
  /// will present at least one of these roles), but both `work_roles`
  /// and `work_languages`, if provided, must not be empty.
  fn search_filters(params: &Map, epoch: i64) -> Query {
    let company_id = i32_vec_from_params!(params, "company_id");

    Query::build_filtered(Filter::build_bool()
                                 .with_must(
                                   vec![
                                     <Filter as VectorOfTerms<String>>::build_terms(
                                       "work_roles", &vec_from_params!(params, "work_roles")),

                                     <Filter as VectorOfTerms<String>>::build_terms(
                                       "work_languages", &vec_from_params!(params, "work_languages")),

                                     <Filter as VectorOfTerms<String>>::build_terms(
                                       "work_experience", &string_vec_from_params!(params, "work_experience")),

                                     <Filter as VectorOfTerms<String>>::build_terms(
                                      "work_authorization", &string_vec_from_params!(params, "work_authorization")),

                                     <Filter as VectorOfTerms<String>>::build_terms(
                                       "work_locations", &vec_from_params!(params, "work_locations")),

                                     Talent::visibility_filters(epoch,
                                       i32_vec_from_params!(params, "presented_talents"))
                                   ].into_iter()
                                    .flat_map(|x| x)
                                    .collect::<Vec<Filter>>())
                                 .with_must_not(
                                   vec![
                                     <Filter as VectorOfTerms<i32>>::build_terms(
                                       "company_ids", &company_id),

                                     <Filter as VectorOfTerms<i32>>::build_terms(
                                       "blocked_companies", &company_id)
                                   ].into_iter()
                                    .flat_map(|x| x)
                                    .collect::<Vec<Filter>>())
                                 .build())
          .build()
  }

  /// Return a `Sort` that makes values be sorted for given fields, descendently.
  fn sorting_criteria() -> Sort {
    Sort::new(
      vec![
        SortField::new("batch_starts_at",   Some(Order::Desc)).build(),
        SortField::new("weight",            Some(Order::Desc)).build(),
        SortField::new("added_to_batch_at", Some(Order::Desc)).build()
      ])
  }
}

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

  use rs_es::Client;

  use params::*;

  extern crate searchspot;
  use searchspot::config::*;

  use resources::user::Talent;

  const CONFIG_FILE: &'static str = "examples/tests.toml";

  lazy_static! {
    static ref config: Config = Config::from_file(CONFIG_FILE.to_owned());
  }

  pub fn make_client() -> Client {
    Client::new(&*config.es.host, config.es.port)
  }

  macro_rules! epoch_from_year {
    ($year:expr) => {
      UTC.datetime_from_str(&format!("{}-01-01 12:00:00", $year),
        "%Y-%m-%d %H:%M:%S").unwrap().timestamp()
    }
  }

  pub fn populate_es(mut client: &mut Client) {
    vec![
      Talent {
        id:                 1,
        accepted:           true,
        work_roles:         vec![],
        work_languages:     vec![],
        work_experience:    "1..2".to_owned(),
        work_locations:     vec!["Berlin".to_owned()],
        work_authorization: "yes".to_owned(),
        company_ids:        vec![],
        batch_starts_at:    epoch_from_year!("2006"),
        batch_ends_at:      epoch_from_year!("2020"),
        added_to_batch_at:  epoch_from_year!("2006"),
        weight:             -5,
        blocked_companies:  vec![]
      },

      Talent {
        id:                 2,
        accepted:           true,
        work_roles:         vec![],
        work_languages:     vec![],
        work_experience:    "1..2".to_owned(),
        work_locations:     vec!["Berlin".to_owned()],
        work_authorization: "yes".to_owned(),
        company_ids:        vec![],
        batch_starts_at:    epoch_from_year!("2006"),
        batch_ends_at:      epoch_from_year!("2020"),
        added_to_batch_at:  epoch_from_year!("2006"),
        weight:             6,
        blocked_companies:  vec![]
      },

      Talent {
        id:                 3,
        accepted:           false,
        work_roles:         vec![],
        work_languages:     vec![],
        work_experience:    "1..2".to_owned(),
        work_locations:     vec!["Berlin".to_owned()],
        work_authorization: "yes".to_owned(),
        company_ids:        vec![],
        batch_starts_at:    epoch_from_year!("2007"),
        batch_ends_at:      epoch_from_year!("2020"),
        added_to_batch_at:  epoch_from_year!("2011"),
        weight:             6,
        blocked_companies:  vec![]
      },

      Talent {
        id:                 4,
        accepted:           true,
        work_roles:         vec!["Fullstack".to_owned(), "DevOps".to_owned()],
        work_languages:     vec![],
        work_experience:    "1..2".to_owned(),
        work_locations:     vec!["Berlin".to_owned()],
        work_authorization:  "yes".to_owned(),
        company_ids:        vec![6],
        batch_starts_at:    epoch_from_year!("2008"),
        batch_ends_at:      epoch_from_year!("2020"),
        added_to_batch_at:  epoch_from_year!("2011"),
        weight:             0,
        blocked_companies:  vec![]
      }
    ].iter()
     .all(|user| user.index(&mut client, &config.es.index)
                     .is_ok());
  }

  #[test]
  fn test_search() {
    let mut client = make_client();
    Talent::delete_all(&mut client, &config.es.index);
    populate_es(&mut client);

    // no parameters are given
    {
      let results = Talent::search(&mut client, &*config.es.index, &Map::new());
      assert_eq!(vec![4, 2, 1], results);
    }

    // a non existing index is given
    {
      let mut map = Map::new();
      map.assign("index", Value::String("lololol".to_owned())).unwrap();

      let results = Talent::search(&mut client, &*config.es.index, &map);
      assert!(results.is_empty());
    }

    // a date that doesn't match given indexes is given
    {
      let mut map = Map::new();
      map.assign("epoch", Value::I64(epoch_from_year!("2040"))).unwrap();

      let results = Talent::search(&mut client, &*config.es.index, &map);
      assert!(results.is_empty());
    }

    // TODO
    // filtering for valid work roles
    // {
    //   let mut map = Map::new();
    //   map.assign("work_roles[]", Value::String("Fullstack".to_owned())).unwrap();

    //   let results = Talent::search(&mut client, config.es.index, &map);
    //   assert_eq!(vec![4], results);
    // }

    // filtering for given company_id
    {
      let mut map = Map::new();
      map.assign("company_id", Value::String("6".into())).unwrap();

      let results = Talent::search(&mut client, &*config.es.index, &map);
      assert_eq!(vec![2, 1], results);
    }
  }
}
<commit_msg>resources/user: work around to the work_roles test<commit_after>use chrono::UTC;
use chrono::datetime::DateTime;

use params::*;

use rs_es::Client;
use rs_es::query::{Filter, Query};
use rs_es::units::{JsonVal, DurationUnit};
use rs_es::units::Duration as ESDuration;
use rs_es::operations::search::{Sort, SortField, Order};
use rs_es::operations::index::IndexResult;
use rs_es::operations::bulk::Action;
use rs_es::error::EsError;

extern crate searchspot;
use searchspot::terms::VectorOfTerms;

#[derive(RustcEncodable, RustcDecodable, Debug)]
pub struct Talent {
  pub id:                 u32,
  pub accepted:           bool,
  pub work_roles:         Vec<String>,
  pub work_languages:     Vec<String>,
  pub work_experience:    String,
  pub work_locations:     Vec<String>,
  pub work_authorization: String,
  pub company_ids:        Vec<u32>,
  pub batch_starts_at:    i64,
  pub batch_ends_at:      i64,
  pub added_to_batch_at:  i64,
  pub weight:             i32,
  pub blocked_companies:  Vec<u32>
}

impl Talent {
  /// Populate the ElasticSearch index with `self`.
  pub fn index(&self, mut es: &mut Client, index: &str) -> Result<IndexResult, EsError> {
    es.index(index, "talent")
      .with_doc(&self)
      .with_id(&*format!("{}", self.id))
      .send()
  }

  #[allow(dead_code)]
  pub fn delete_all(mut es: &mut Client, index: &str) {
    let mut scan = match es.search_query()
                           .with_indexes(&[&index])
                           .with_query(&Query::build_match_all().build())
                           .scan(ESDuration::new(1, DurationUnit::Minute)) {
                              Ok(scan) => scan,
                              Err(_)   => return
                           };

    loop {
      let     page = scan.scroll(&mut es).unwrap();
      let mut hits = page.hits.hits;

      if hits.len() == 0 {
        break;
      }

      let actions = hits.drain(..)
                        .map(|hit| {
                           Action::delete(hit.id).with_index(&*index)
                                                 .with_doc_type(hit.doc_type)
                        })
                        .collect::<Vec<Action>>();
      es.bulk(&actions)
        .send()
        .unwrap();
    }

    scan.close(&mut es)
        .unwrap();
  }

  /// Query ElasticSearch on given `indexes` and `params` and return the IDs of
  /// the found talents.
  pub fn search(mut es: &mut Client, default_index: &str, params: &Map) -> Vec<u32> {
    let epoch = match params.find(&["epoch"]) {
      Some(&Value::I64(epoch)) => epoch,
      _ => DateTime::timestamp(&UTC::now())
    };

    let index: Vec<&str> = match params.find(&["index"]) {
      Some(&Value::String(ref index)) => vec![&index[..]],
      _ => vec![default_index]
    };

    let result = es.search_query()
                   .with_indexes(&*index)
                   .with_query(&Talent::search_filters(params, epoch))
                   .with_sort(&Talent::sorting_criteria())
                   .send();

    match result {
      Ok(result) => {
        let mut results = result.hits.hits.into_iter()
                                          .map(|hit| hit.source.unwrap()["id"]
                                                               .as_u64()
                                                               .unwrap() as u32)
                                          .collect::<Vec<u32>>();
        results.dedup();
        results
      },
      Err(err) => {
        println!("{:?}", err);
        vec![]
      }
    }
  }

  /// Return a `Vec<Filter>` with visibility criteria for the talents.
  /// The `epoch` must be given as `I64` (UNIX time in seconds) and is
  /// the range in which batches are searched.
  /// If `presented_talents` is provided, talents who match the IDs
  /// contained there skip the standard visibility criteria.
  ///
  /// Basically, the talents must be accepted into the platform and must be
  /// inside a living batch to match the visibility criteria.
  fn visibility_filters(epoch: i64, presented_talents: Vec<i32>) -> Vec<Filter> {
    let visibility_rules = Filter::build_bool()
                                  .with_must(
                                    vec![
                                      Filter::build_term("accepted", true)
                                             .build(),
                                      Filter::build_range("batch_starts_at")
                                             .with_lte(JsonVal::from(epoch))
                                             .with_format("epoch_second")
                                             .build(),
                                      Filter::build_range("batch_ends_at")
                                             .with_gte(JsonVal::from(epoch))
                                             .with_format("epoch_second")
                                             .build()
                                    ])
                                  .build();

    if presented_talents.len() > 0 { // preferred over !_.is_empty()
      let presented_talents_filters = Filter::build_bool()
                                             .with_must(
                                               vec![
                                                 <Filter as VectorOfTerms<i32>>::build_terms(
                                                   "ids", &presented_talents)
                                               ].into_iter()
                                                .flat_map(|x| x)
                                                .collect::<Vec<Filter>>())
                                             .build();
      vec![
        Filter::build_bool()
               .with_should(vec![visibility_rules, presented_talents_filters])
               .build()
      ]
    }
    else {
      vec![visibility_rules]
    }
  }

  /// Given parameters inside the query string mapped inside a `Map`,
  /// and the `epoch` (defined as UNIX time in seconds) for batches,
  /// return a `Query` for ElasticSearch.
  ///
  /// `VectorOfTerms` are ORred, while `Filter`s are ANDed.
  /// I.e.: given ["Fullstack", "DevOps"] as `work_roles`, found talents
  /// will present at least one of these roles), but both `work_roles`
  /// and `work_languages`, if provided, must not be empty.
  fn search_filters(params: &Map, epoch: i64) -> Query {
    let company_id = i32_vec_from_params!(params, "company_id");

    Query::build_filtered(Filter::build_bool()
                                 .with_must(
                                   vec![
                                     <Filter as VectorOfTerms<String>>::build_terms(
                                       "work_roles", &vec_from_params!(params, "work_roles")),

                                     <Filter as VectorOfTerms<String>>::build_terms(
                                       "work_languages", &vec_from_params!(params, "work_languages")),

                                     <Filter as VectorOfTerms<String>>::build_terms(
                                       "work_experience", &string_vec_from_params!(params, "work_experience")),

                                     <Filter as VectorOfTerms<String>>::build_terms(
                                      "work_authorization", &string_vec_from_params!(params, "work_authorization")),

                                     <Filter as VectorOfTerms<String>>::build_terms(
                                       "work_locations", &vec_from_params!(params, "work_locations")),

                                     Talent::visibility_filters(epoch,
                                       i32_vec_from_params!(params, "presented_talents"))
                                   ].into_iter()
                                    .flat_map(|x| x)
                                    .collect::<Vec<Filter>>())
                                 .with_must_not(
                                   vec![
                                     <Filter as VectorOfTerms<i32>>::build_terms(
                                       "company_ids", &company_id),

                                     <Filter as VectorOfTerms<i32>>::build_terms(
                                       "blocked_companies", &company_id)
                                   ].into_iter()
                                    .flat_map(|x| x)
                                    .collect::<Vec<Filter>>())
                                 .build())
          .build()
  }

  /// Return a `Sort` that makes values be sorted for given fields, descendently.
  fn sorting_criteria() -> Sort {
    Sort::new(
      vec![
        SortField::new("batch_starts_at",   Some(Order::Desc)).build(),
        SortField::new("weight",            Some(Order::Desc)).build(),
        SortField::new("added_to_batch_at", Some(Order::Desc)).build()
      ])
  }
}

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

  use rs_es::Client;

  use params::*;

  extern crate searchspot;
  use searchspot::config::*;

  use resources::user::Talent;

  const CONFIG_FILE: &'static str = "examples/tests.toml";

  lazy_static! {
    static ref config: Config = Config::from_file(CONFIG_FILE.to_owned());
  }

  pub fn make_client() -> Client {
    Client::new(&*config.es.host, config.es.port)
  }

  macro_rules! epoch_from_year {
    ($year:expr) => {
      UTC.datetime_from_str(&format!("{}-01-01 12:00:00", $year),
        "%Y-%m-%d %H:%M:%S").unwrap().timestamp()
    }
  }

  pub fn populate_es(mut client: &mut Client) {
    vec![
      Talent {
        id:                 1,
        accepted:           true,
        work_roles:         vec![],
        work_languages:     vec![],
        work_experience:    "1..2".to_owned(),
        work_locations:     vec!["Berlin".to_owned()],
        work_authorization: "yes".to_owned(),
        company_ids:        vec![],
        batch_starts_at:    epoch_from_year!("2006"),
        batch_ends_at:      epoch_from_year!("2020"),
        added_to_batch_at:  epoch_from_year!("2006"),
        weight:             -5,
        blocked_companies:  vec![]
      },

      Talent {
        id:                 2,
        accepted:           true,
        work_roles:         vec![],
        work_languages:     vec![],
        work_experience:    "1..2".to_owned(),
        work_locations:     vec!["Berlin".to_owned()],
        work_authorization: "yes".to_owned(),
        company_ids:        vec![],
        batch_starts_at:    epoch_from_year!("2006"),
        batch_ends_at:      epoch_from_year!("2020"),
        added_to_batch_at:  epoch_from_year!("2006"),
        weight:             6,
        blocked_companies:  vec![]
      },

      Talent {
        id:                 3,
        accepted:           false,
        work_roles:         vec![],
        work_languages:     vec![],
        work_experience:    "1..2".to_owned(),
        work_locations:     vec!["Berlin".to_owned()],
        work_authorization: "yes".to_owned(),
        company_ids:        vec![],
        batch_starts_at:    epoch_from_year!("2007"),
        batch_ends_at:      epoch_from_year!("2020"),
        added_to_batch_at:  epoch_from_year!("2011"),
        weight:             6,
        blocked_companies:  vec![]
      },

      Talent {
        id:                 4,
        accepted:           true,
        work_roles:         vec!["Fullstack".to_owned(), "DevOps".to_owned()],
        work_languages:     vec![],
        work_experience:    "1..2".to_owned(),
        work_locations:     vec!["Berlin".to_owned()],
        work_authorization:  "yes".to_owned(),
        company_ids:        vec![6],
        batch_starts_at:    epoch_from_year!("2008"),
        batch_ends_at:      epoch_from_year!("2020"),
        added_to_batch_at:  epoch_from_year!("2011"),
        weight:             0,
        blocked_companies:  vec![]
      }
    ].iter()
     .all(|user| user.index(&mut client, &config.es.index)
                     .is_ok());
  }

  #[test]
  fn test_search() {
    let mut client = make_client();
    Talent::delete_all(&mut client, &config.es.index);
    populate_es(&mut client);

    // no parameters are given
    {
      let results = Talent::search(&mut client, &*config.es.index, &Map::new());
      assert_eq!(vec![4, 2, 1], results);
    }

    // a non existing index is given
    {
      let mut map = Map::new();
      map.assign("index", Value::String("lololol".to_owned())).unwrap();

      let results = Talent::search(&mut client, &*config.es.index, &map);
      assert!(results.is_empty());
    }

    // a date that doesn't match given indexes is given
    {
      let mut map = Map::new();
      map.assign("epoch", Value::I64(epoch_from_year!("2040"))).unwrap();

      let results = Talent::search(&mut client, &*config.es.index, &map);
      assert!(results.is_empty());
    }

    // TODO: map field type properly (see benashford/rs-es#11)
    // // filtering for valid work roles
    // // {
    // //   let mut map = Map::new();
    // //   map.assign("work_roles[]", Value::String("Fullstack".to_owned())).unwrap();
    // //
    // //   let results = Talent::search(&mut client, &*config.es.index, &map);
    // //   assert_eq!(vec![4], results);
    // // }

    // filtering for given company_id
    {
      let mut map = Map::new();
      map.assign("company_id", Value::String("6".into())).unwrap();

      let results = Talent::search(&mut client, &*config.es.index, &map);
      assert_eq!(vec![2, 1], results);
    }
  }
}
<|endoftext|>


<commit_before>extern crate getopts;
pub use getopts::Options;
use std::collections::HashMap;
use std::num::Float;
use std::num::Int;
use std::iter::range_step;

#[macro_export]
macro_rules! solutions {
    (inputs: ($($n:ident : $ty:ty = $def:expr),*) $(sol $name:ident $content:block)+) => (
        {
            let args: Vec<String> = ::std::os::args();
            let mut opts = $crate::Options::new();

            $(
                opts.optopt("", stringify!($n), "", "VALUE");
            )*
            opts.optflag("h", "help", "Display this help text");

            let help = || {
                let brief = format!("Usage: {} [options] [versions] \nVersions: {:?}", &args[0], [$(stringify!($name)),+]);
                print!("{}", opts.usage(brief.as_slice()));
            };

            let matches = match opts.parse(args.tail()) {
                Ok(m) => m,
                Err(_) => { help(); return; }
            };

            if matches.opt_present("h") {
                help();
                return;
            }

            $(
                let $n: $ty = match matches.opt_str(stringify!($n)) {
                    Some(s) => { s.parse().unwrap_or($def) },
                    None => $def
                };
            )*

            $(
                let $name = || {
                    $content
                };
            )+

            let valid_solutions = vec![$(stringify!($name)),*];
            let solutions: Vec<&String> = matches.free.iter()
                .filter(|&m| valid_solutions.contains(&m.as_slice()))
                .collect();

            $(
                if solutions.len() <= 0 || solutions.contains(&&stringify!($name).to_string()) {
                    println!("Running: {}", stringify!($name));
                    println!("Result: {:?}", $name());
                    println!("");
                }
            )+
        }
    )
}

pub struct PrimeIterator {
    current: i64,
    previous_primes: Vec<i64>
}

impl PrimeIterator {
    pub fn new() -> PrimeIterator {
        PrimeIterator {
            current: 1,
            previous_primes: Vec::new()
        }
    }

    fn is_prime(&self, v: i64) -> bool {
        for &pp in self.previous_primes.iter() {
            if v % pp == 0 {
                return false;
            }
        }

        true
    }
}

impl Iterator for PrimeIterator {
    type Item = i64;

    fn next(&mut self) -> Option<i64> {
        loop {
            self.current += 1;

            if self.is_prime(self.current) {
                self.previous_primes.push(self.current);
                return Some(self.current);
            }
        }
    }
}

pub struct SieveOfAtkinIterator {
    ix: usize,
    generated: Vec<u64>
}

impl SieveOfAtkinIterator {
    pub fn new(limit: u64) -> SieveOfAtkinIterator {
        let sqroot = (limit as f64).sqrt() as u64 + 1;
        let mut is_prime: HashMap<u64, bool> = HashMap::new();
        let mut primes = vec![2u64, 3];

        {
            let mut invert = |n: u64| {
                let v = is_prime.remove(&n).unwrap_or(false);
                is_prime.insert(n, !v);
            };

            for x in 0..sqroot {
                let xp2 = x*x;
                for y in 0..sqroot {
                    let yp2 = y*y;

                    let n = 3*xp2 + yp2;
                    if n <= limit && n % 12 == 7 {
                        invert(n);
                    }

                    let n = n + xp2;
                    if n <= limit && (n % 12 == 1 || n % 12 == 5) {
                        invert(n);
                    }

                    if x > y {
                        let n = n - (xp2 + 2*yp2);
                        if n <= limit && n % 12 == 11 {
                            invert(n);
                        }
                    }
                }
            }
        }

        for x in range_step(5, limit, 2) {
            if (is_prime.get(&x).unwrap_or(&false) == &true) {
                for y in range_step(x*x, limit, x) {
                    is_prime.remove(&y);
                    is_prime.insert(y, false);
                }

                primes.push(x as u64);
            }
        }

        SieveOfAtkinIterator {
            ix: 0,
            generated: primes
        }
    }
}

impl Iterator for SieveOfAtkinIterator {
    type Item = u64;

    fn next(&mut self) -> Option<u64> {
        self.ix += 1;
        if self.ix <= self.generated.len() {
            let val = self.generated[self.ix - 1];
            Some(val)
        } else {
            None
        }
    }
}
<commit_msg>Use a vec instead of a hashmap for SieveOfAtkinIterator<commit_after>extern crate getopts;
pub use getopts::Options;
use std::collections::HashMap;
use std::num::Float;
use std::num::Int;
use std::iter::range_step;

#[macro_export]
macro_rules! solutions {
    (inputs: ($($n:ident : $ty:ty = $def:expr),*) $(sol $name:ident $content:block)+) => (
        {
            let args: Vec<String> = ::std::os::args();
            let mut opts = $crate::Options::new();

            $(
                opts.optopt("", stringify!($n), "", "VALUE");
            )*
            opts.optflag("h", "help", "Display this help text");

            let help = || {
                let brief = format!("Usage: {} [options] [versions] \nVersions: {:?}", &args[0], [$(stringify!($name)),+]);
                print!("{}", opts.usage(brief.as_slice()));
            };

            let matches = match opts.parse(args.tail()) {
                Ok(m) => m,
                Err(_) => { help(); return; }
            };

            if matches.opt_present("h") {
                help();
                return;
            }

            $(
                let $n: $ty = match matches.opt_str(stringify!($n)) {
                    Some(s) => { s.parse().unwrap_or($def) },
                    None => $def
                };
            )*

            $(
                let $name = || {
                    $content
                };
            )+

            let valid_solutions = vec![$(stringify!($name)),*];
            let solutions: Vec<&String> = matches.free.iter()
                .filter(|&m| valid_solutions.contains(&m.as_slice()))
                .collect();

            $(
                if solutions.len() <= 0 || solutions.contains(&&stringify!($name).to_string()) {
                    println!("Running: {}", stringify!($name));
                    println!("Result: {:?}", $name());
                    println!("");
                }
            )+
        }
    )
}

pub struct PrimeIterator {
    current: i64,
    previous_primes: Vec<i64>
}

impl PrimeIterator {
    pub fn new() -> PrimeIterator {
        PrimeIterator {
            current: 1,
            previous_primes: Vec::new()
        }
    }

    fn is_prime(&self, v: i64) -> bool {
        for &pp in self.previous_primes.iter() {
            if v % pp == 0 {
                return false;
            }
        }

        true
    }
}

impl Iterator for PrimeIterator {
    type Item = i64;

    fn next(&mut self) -> Option<i64> {
        loop {
            self.current += 1;

            if self.is_prime(self.current) {
                self.previous_primes.push(self.current);
                return Some(self.current);
            }
        }
    }
}

pub struct SieveOfAtkinIterator {
    ix: usize,
    generated: Vec<u64>
}

impl SieveOfAtkinIterator {
    pub fn new(limit: u64) -> SieveOfAtkinIterator {
        let sqroot = (limit as f64).sqrt() as u64 + 1;

        let mut is_prime = Vec::new();
        is_prime.resize(limit as usize, false);

        let mut primes = vec![2u64, 3];

        {
            let mut invert = |n: u64| {
                is_prime[n as usize] = !is_prime[n as usize];
            };

            for x in 0..sqroot {
                let xp2 = x*x;
                for y in 0..sqroot {
                    let yp2 = y*y;

                    let n = 3*xp2 + yp2;
                    if n <= limit && n % 12 == 7 {
                        invert(n);
                    }

                    let n = n + xp2;
                    if n <= limit && (n % 12 == 1 || n % 12 == 5) {
                        invert(n);
                    }

                    if x > y {
                        let n = n - (xp2 + 2*yp2);
                        if n <= limit && n % 12 == 11 {
                            invert(n);
                        }
                    }
                }
            }
        }

        for x in range_step(5, limit, 2) {
            if (is_prime[x as usize]) {
                for y in range_step(x*x, limit, x) {
                    is_prime[y as usize] = false;
                }

                primes.push(x as u64);
            }
        }

        SieveOfAtkinIterator {
            ix: 0,
            generated: primes
        }
    }
}

impl Iterator for SieveOfAtkinIterator {
    type Item = u64;

    fn next(&mut self) -> Option<u64> {
        self.ix += 1;
        if self.ix <= self.generated.len() {
            let val = self.generated[self.ix - 1];
            Some(val)
        } else {
            None
        }
    }
}
<|endoftext|>


<commit_before>// run-pass
//! This snippet causes the type length to blowup exponentially,
//! so check that we don't accidentially exceed the type length limit.
// FIXME: Once the size of iterator adaptors is further reduced,
// increase the complexity of this test.

fn main() {
    let c = 2;
    let bv = vec![2];
    let b = bv
        .iter()
        .filter(|a| **a == c);

    let _a = vec![1, 2, 3]
        .into_iter()
        .filter(|a| b.clone().any(|b| *b == *a))
        .filter(|a| b.clone().any(|b| *b == *a))
        .filter(|a| b.clone().any(|b| *b == *a))
        .filter(|a| b.clone().any(|b| *b == *a))
        .filter(|a| b.clone().any(|b| *b == *a))
        .filter(|a| b.clone().any(|b| *b == *a))
        .filter(|a| b.clone().any(|b| *b == *a))
        .filter(|a| b.clone().any(|b| *b == *a))
        .filter(|a| b.clone().any(|b| *b == *a))
        .filter(|a| b.clone().any(|b| *b == *a))
        .filter(|a| b.clone().any(|b| *b == *a))
        .filter(|a| b.clone().any(|b| *b == *a))
        .filter(|a| b.clone().any(|b| *b == *a))
        .filter(|a| b.clone().any(|b| *b == *a))
        .collect::<Vec<_>>();
}
<commit_msg>avoid applying in-place collect specialization in type-length test<commit_after>// run-pass
//! This snippet causes the type length to blowup exponentially,
//! so check that we don't accidentially exceed the type length limit.
// FIXME: Once the size of iterator adaptors is further reduced,
// increase the complexity of this test.
use std::collections::VecDeque;

fn main() {
    let c = 2;
    let bv = vec![2];
    let b = bv
        .iter()
        .filter(|a| **a == c);

    let _a = vec![1, 2, 3]
        .into_iter()
        .filter(|a| b.clone().any(|b| *b == *a))
        .filter(|a| b.clone().any(|b| *b == *a))
        .filter(|a| b.clone().any(|b| *b == *a))
        .filter(|a| b.clone().any(|b| *b == *a))
        .filter(|a| b.clone().any(|b| *b == *a))
        .filter(|a| b.clone().any(|b| *b == *a))
        .filter(|a| b.clone().any(|b| *b == *a))
        .filter(|a| b.clone().any(|b| *b == *a))
        .filter(|a| b.clone().any(|b| *b == *a))
        .filter(|a| b.clone().any(|b| *b == *a))
        .filter(|a| b.clone().any(|b| *b == *a))
        .filter(|a| b.clone().any(|b| *b == *a))
        .filter(|a| b.clone().any(|b| *b == *a))
        .filter(|a| b.clone().any(|b| *b == *a))
        .collect::<VecDeque<_>>();
}
<|endoftext|>