<commit_before>//! Tests for configuration values that point to programs.

use cargo_test_support::{basic_lib_manifest, no_such_file_err_msg, project, rustc_host};

#[cargo_test]
fn pathless_tools() {
    let target = rustc_host();

    let foo = project()
        .file("Cargo.toml", &basic_lib_manifest("foo"))
        .file("src/lib.rs", "")
        .file(
            ".cargo/config",
            &format!(
                r#"
                    [target.{}]
                    linker = "nonexistent-linker"
                "#,
                target
            ),
        )
        .build();

    foo.cargo("build --verbose")
        .with_stderr(
            "\
[COMPILING] foo v0.5.0 ([CWD])
[RUNNING] `rustc [..] -C linker=nonexistent-linker [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
        )
        .run();
}

#[cargo_test]
fn absolute_tools() {
    let target = rustc_host();

    // Escaped as they appear within a TOML config file
    let linker = if cfg!(windows) {
        r#"C:\\bogus\\nonexistent-linker"#
    } else {
        r#"/bogus/nonexistent-linker"#
    };

    let foo = project()
        .file("Cargo.toml", &basic_lib_manifest("foo"))
        .file("src/lib.rs", "")
        .file(
            ".cargo/config",
            &format!(
                r#"
                    [target.{target}]
                    linker = "{linker}"
                "#,
                target = target,
                linker = linker
            ),
        )
        .build();

    foo.cargo("build --verbose")
        .with_stderr(
            "\
[COMPILING] foo v0.5.0 ([CWD])
[RUNNING] `rustc [..] -C linker=[..]bogus/nonexistent-linker [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
        )
        .run();
}

#[cargo_test]
fn relative_tools() {
    let target = rustc_host();

    // Escaped as they appear within a TOML config file
    let linker = if cfg!(windows) {
        r#".\\tools\\nonexistent-linker"#
    } else {
        r#"./tools/nonexistent-linker"#
    };

    // Funky directory structure to test that relative tool paths are made absolute
    // by reference to the `.cargo/..` directory and not to (for example) the CWD.
    let p = project()
        .no_manifest()
        .file("bar/Cargo.toml", &basic_lib_manifest("bar"))
        .file("bar/src/lib.rs", "")
        .file(
            ".cargo/config",
            &format!(
                r#"
                    [target.{target}]
                    linker = "{linker}"
                "#,
                target = target,
                linker = linker
            ),
        )
        .build();

    let prefix = p.root().into_os_string().into_string().unwrap();

    p.cargo("build --verbose")
        .cwd("bar")
        .with_stderr(&format!(
            "\
[COMPILING] bar v0.5.0 ([CWD])
[RUNNING] `rustc [..] -C linker={prefix}/./tools/nonexistent-linker [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
            prefix = prefix,
        ))
        .run();
}

#[cargo_test]
fn custom_runner() {
    let target = rustc_host();

    let p = project()
        .file("src/main.rs", "fn main() {}")
        .file("tests/test.rs", "")
        .file("benches/bench.rs", "")
        .file(
            ".cargo/config",
            &format!(
                r#"
                    [target.{}]
                    runner = "nonexistent-runner -r"
                "#,
                target
            ),
        )
        .build();

    p.cargo("run -- --param")
        .with_status(101)
        .with_stderr_contains(
            "\
[COMPILING] foo v0.0.1 ([CWD])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
[RUNNING] `nonexistent-runner -r target/debug/foo[EXE] --param`
",
        )
        .run();

    p.cargo("test --test test --verbose -- --param")
        .with_status(101)
        .with_stderr_contains(
            "\
[COMPILING] foo v0.0.1 ([CWD])
[RUNNING] `rustc [..]`
[FINISHED] test [unoptimized + debuginfo] target(s) in [..]
[RUNNING] `nonexistent-runner -r [..]/target/debug/deps/test-[..][EXE] --param`
",
        )
        .run();

    p.cargo("bench --bench bench --verbose -- --param")
        .with_status(101)
        .with_stderr_contains(
            "\
[COMPILING] foo v0.0.1 ([CWD])
[RUNNING] `rustc [..]`
[RUNNING] `rustc [..]`
[FINISHED] bench [optimized] target(s) in [..]
[RUNNING] `nonexistent-runner -r [..]/target/release/deps/bench-[..][EXE] --param --bench`
",
        )
        .run();
}

// can set a custom runner via `target.'cfg(..)'.runner`
#[cargo_test]
fn custom_runner_cfg() {
    let p = project()
        .file("src/main.rs", "fn main() {}")
        .file(
            ".cargo/config",
            r#"
            [target.'cfg(not(target_os = "none"))']
            runner = "nonexistent-runner -r"
            "#,
        )
        .build();

    p.cargo("run -- --param")
        .with_status(101)
        .with_stderr_contains(
            "\
[COMPILING] foo v0.0.1 ([CWD])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
[RUNNING] `nonexistent-runner -r target/debug/foo[EXE] --param`
",
        )
        .run();
}

// custom runner set via `target.$triple.runner` have precedence over `target.'cfg(..)'.runner`
#[cargo_test]
fn custom_runner_cfg_precedence() {
    let target = rustc_host();

    let p = project()
        .file("src/main.rs", "fn main() {}")
        .file(
            ".cargo/config",
            &format!(
                r#"
                    [target.'cfg(not(target_os = "none"))']
                    runner = "ignored-runner"

                    [target.{}]
                    runner = "nonexistent-runner -r"
                "#,
                target
            ),
        )
        .build();

    p.cargo("run -- --param")
        .with_status(101)
        .with_stderr_contains(
            "\
[COMPILING] foo v0.0.1 ([CWD])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
[RUNNING] `nonexistent-runner -r target/debug/foo[EXE] --param`
",
        )
        .run();
}

#[cargo_test]
fn custom_runner_cfg_collision() {
    let p = project()
        .file("src/main.rs", "fn main() {}")
        .file(
            ".cargo/config",
            r#"
            [target.'cfg(not(target_arch = "avr"))']
            runner = "true"

            [target.'cfg(not(target_os = "none"))']
            runner = "false"
            "#,
        )
        .build();

    p.cargo("run -- --param")
        .with_status(101)
        .with_stderr(
            "\
[ERROR] several matching instances of `target.'cfg(..)'.runner` in `.cargo/config`
first match `cfg(not(target_arch = \"avr\"))` located in [..]/foo/.cargo/config
second match `cfg(not(target_os = \"none\"))` located in [..]/foo/.cargo/config
",
        )
        .run();
}

#[cargo_test]
fn custom_runner_env() {
    let target = rustc_host();
    let p = project().file("src/main.rs", "fn main() {}").build();

    let key = format!(
        "CARGO_TARGET_{}_RUNNER",
        target.to_uppercase().replace('-', "_")
    );

    p.cargo("run")
        .env(&key, "nonexistent-runner --foo")
        .with_status(101)
        .with_stderr(&format!(
            "\
[COMPILING] foo [..]
[FINISHED] dev [..]
[RUNNING] `nonexistent-runner --foo target/debug/foo[EXE]`
[ERROR] could not execute process `nonexistent-runner --foo target/debug/foo[EXE]` (never executed)

Caused by:
  {}
",
            no_such_file_err_msg()
        ))
        .run();
}

#[cargo_test]
fn custom_runner_env_overrides_config() {
    let target = rustc_host();
    let p = project()
        .file("src/main.rs", "fn main() {}")
        .file(
            ".cargo/config.toml",
            &format!(
                r#"
                    [target.{}]
                    runner = "should-not-run -r"
                "#,
                target
            ),
        )
        .build();

    let key = format!(
        "CARGO_TARGET_{}_RUNNER",
        target.to_uppercase().replace('-', "_")
    );

    p.cargo("run")
        .env(&key, "should-run --foo")
        .with_status(101)
        .with_stderr_contains("[RUNNING] `should-run --foo target/debug/foo[EXE]`")
        .run();
}

#[cargo_test]
#[cfg(unix)] // Assumes `true` is in PATH.
fn custom_runner_env_true() {
    // Check for a bug where "true" was interpreted as a boolean instead of
    // the executable.
    let target = rustc_host();
    let p = project().file("src/main.rs", "fn main() {}").build();

    let key = format!(
        "CARGO_TARGET_{}_RUNNER",
        target.to_uppercase().replace('-', "_")
    );

    p.cargo("run")
        .env(&key, "true")
        .with_stderr_contains("[RUNNING] `true target/debug/foo[EXE]`")
        .run();
}

#[cargo_test]
fn custom_linker_env() {
    let target = rustc_host();
    let p = project().file("src/main.rs", "fn main() {}").build();

    let key = format!(
        "CARGO_TARGET_{}_LINKER",
        target.to_uppercase().replace('-', "_")
    );

    p.cargo("build -v")
        .env(&key, "nonexistent-linker")
        .with_status(101)
        .with_stderr_contains("[RUNNING] `rustc [..]-C linker=nonexistent-linker [..]")
        .run();
}

#[cargo_test]
#[cfg(not(windows))]
fn target_in_environment_contains_lower_case() {
    let p = project().file("src/main.rs", "fn main() {}").build();

    let target_keys = [
        "CARGO_TARGET_X86_64_UNKNOWN_LINUX_musl_LINKER",
        "CARGO_TARGET_x86_64_unknown_linux_musl_LINKER",
    ];

    for target_key in &target_keys {
        p.cargo("build -v --target x86_64-unknown-linux-musl")
            .env(target_key, "nonexistent-linker")
            .with_status(101)
            .with_stderr_contains(format!(
                "warning: Environment variables are expected to use uppercase letters and underscores, \
                the variable `{}` will be ignored and have no effect",
                target_key
            ))
            .run();
    }
}

#[cargo_test]
#[cfg(windows)]
fn target_in_environment_contains_lower_case_on_windows() {
    let p = project().file("src/main.rs", "fn main() {}").build();

    let target_keys = [
        "CARGO_TARGET_X86_64_UNKNOWN_LINUX_musl_LINKER",
        "CARGO_TARGET_x86_64_unknown_linux_musl_LINKER",
    ];

    for target_key in &target_keys {
        p.cargo("build -v --target x86_64-unknown-linux-musl")
            .env(target_key, "nonexistent-linker")
            .with_status(101)
            .with_stderr_does_not_contain(format!(
                "warning: Environment variables are expected to use uppercase letters and underscores, \
                the variable `{}` will be ignored and have no effect",
                target_key
            ))
            .run();
    }
}

#[cargo_test]
fn cfg_ignored_fields() {
    // Test for some ignored fields in [target.'cfg()'] tables.
    let p = project()
        .file(
            ".cargo/config",
            r#"
            # Try some empty tables.
            [target.'cfg(not(foo))']
            [target.'cfg(not(bar))'.somelib]

            # A bunch of unused fields.
            [target.'cfg(not(target_os = "none"))']
            linker = 'false'
            ar = 'false'
            foo = {rustc-flags = "-l foo"}
            invalid = 1
            runner = 'false'
            rustflags = ''
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("check")
        .with_stderr(
            "\
[WARNING] unused key `somelib` in [target] config table `cfg(not(bar))`
[WARNING] unused key `ar` in [target] config table `cfg(not(target_os = \"none\"))`
[WARNING] unused key `foo` in [target] config table `cfg(not(target_os = \"none\"))`
[WARNING] unused key `invalid` in [target] config table `cfg(not(target_os = \"none\"))`
[WARNING] unused key `linker` in [target] config table `cfg(not(target_os = \"none\"))`
[CHECKING] foo v0.0.1 ([..])
[FINISHED] [..]
",
        )
        .run();
}
<commit_msg>Combine target env tests.<commit_after>//! Tests for configuration values that point to programs.

use cargo_test_support::{basic_lib_manifest, no_such_file_err_msg, project, rustc_host};

#[cargo_test]
fn pathless_tools() {
    let target = rustc_host();

    let foo = project()
        .file("Cargo.toml", &basic_lib_manifest("foo"))
        .file("src/lib.rs", "")
        .file(
            ".cargo/config",
            &format!(
                r#"
                    [target.{}]
                    linker = "nonexistent-linker"
                "#,
                target
            ),
        )
        .build();

    foo.cargo("build --verbose")
        .with_stderr(
            "\
[COMPILING] foo v0.5.0 ([CWD])
[RUNNING] `rustc [..] -C linker=nonexistent-linker [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
        )
        .run();
}

#[cargo_test]
fn absolute_tools() {
    let target = rustc_host();

    // Escaped as they appear within a TOML config file
    let linker = if cfg!(windows) {
        r#"C:\\bogus\\nonexistent-linker"#
    } else {
        r#"/bogus/nonexistent-linker"#
    };

    let foo = project()
        .file("Cargo.toml", &basic_lib_manifest("foo"))
        .file("src/lib.rs", "")
        .file(
            ".cargo/config",
            &format!(
                r#"
                    [target.{target}]
                    linker = "{linker}"
                "#,
                target = target,
                linker = linker
            ),
        )
        .build();

    foo.cargo("build --verbose")
        .with_stderr(
            "\
[COMPILING] foo v0.5.0 ([CWD])
[RUNNING] `rustc [..] -C linker=[..]bogus/nonexistent-linker [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
        )
        .run();
}

#[cargo_test]
fn relative_tools() {
    let target = rustc_host();

    // Escaped as they appear within a TOML config file
    let linker = if cfg!(windows) {
        r#".\\tools\\nonexistent-linker"#
    } else {
        r#"./tools/nonexistent-linker"#
    };

    // Funky directory structure to test that relative tool paths are made absolute
    // by reference to the `.cargo/..` directory and not to (for example) the CWD.
    let p = project()
        .no_manifest()
        .file("bar/Cargo.toml", &basic_lib_manifest("bar"))
        .file("bar/src/lib.rs", "")
        .file(
            ".cargo/config",
            &format!(
                r#"
                    [target.{target}]
                    linker = "{linker}"
                "#,
                target = target,
                linker = linker
            ),
        )
        .build();

    let prefix = p.root().into_os_string().into_string().unwrap();

    p.cargo("build --verbose")
        .cwd("bar")
        .with_stderr(&format!(
            "\
[COMPILING] bar v0.5.0 ([CWD])
[RUNNING] `rustc [..] -C linker={prefix}/./tools/nonexistent-linker [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
            prefix = prefix,
        ))
        .run();
}

#[cargo_test]
fn custom_runner() {
    let target = rustc_host();

    let p = project()
        .file("src/main.rs", "fn main() {}")
        .file("tests/test.rs", "")
        .file("benches/bench.rs", "")
        .file(
            ".cargo/config",
            &format!(
                r#"
                    [target.{}]
                    runner = "nonexistent-runner -r"
                "#,
                target
            ),
        )
        .build();

    p.cargo("run -- --param")
        .with_status(101)
        .with_stderr_contains(
            "\
[COMPILING] foo v0.0.1 ([CWD])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
[RUNNING] `nonexistent-runner -r target/debug/foo[EXE] --param`
",
        )
        .run();

    p.cargo("test --test test --verbose -- --param")
        .with_status(101)
        .with_stderr_contains(
            "\
[COMPILING] foo v0.0.1 ([CWD])
[RUNNING] `rustc [..]`
[FINISHED] test [unoptimized + debuginfo] target(s) in [..]
[RUNNING] `nonexistent-runner -r [..]/target/debug/deps/test-[..][EXE] --param`
",
        )
        .run();

    p.cargo("bench --bench bench --verbose -- --param")
        .with_status(101)
        .with_stderr_contains(
            "\
[COMPILING] foo v0.0.1 ([CWD])
[RUNNING] `rustc [..]`
[RUNNING] `rustc [..]`
[FINISHED] bench [optimized] target(s) in [..]
[RUNNING] `nonexistent-runner -r [..]/target/release/deps/bench-[..][EXE] --param --bench`
",
        )
        .run();
}

// can set a custom runner via `target.'cfg(..)'.runner`
#[cargo_test]
fn custom_runner_cfg() {
    let p = project()
        .file("src/main.rs", "fn main() {}")
        .file(
            ".cargo/config",
            r#"
            [target.'cfg(not(target_os = "none"))']
            runner = "nonexistent-runner -r"
            "#,
        )
        .build();

    p.cargo("run -- --param")
        .with_status(101)
        .with_stderr_contains(
            "\
[COMPILING] foo v0.0.1 ([CWD])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
[RUNNING] `nonexistent-runner -r target/debug/foo[EXE] --param`
",
        )
        .run();
}

// custom runner set via `target.$triple.runner` have precedence over `target.'cfg(..)'.runner`
#[cargo_test]
fn custom_runner_cfg_precedence() {
    let target = rustc_host();

    let p = project()
        .file("src/main.rs", "fn main() {}")
        .file(
            ".cargo/config",
            &format!(
                r#"
                    [target.'cfg(not(target_os = "none"))']
                    runner = "ignored-runner"

                    [target.{}]
                    runner = "nonexistent-runner -r"
                "#,
                target
            ),
        )
        .build();

    p.cargo("run -- --param")
        .with_status(101)
        .with_stderr_contains(
            "\
[COMPILING] foo v0.0.1 ([CWD])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
[RUNNING] `nonexistent-runner -r target/debug/foo[EXE] --param`
",
        )
        .run();
}

#[cargo_test]
fn custom_runner_cfg_collision() {
    let p = project()
        .file("src/main.rs", "fn main() {}")
        .file(
            ".cargo/config",
            r#"
            [target.'cfg(not(target_arch = "avr"))']
            runner = "true"

            [target.'cfg(not(target_os = "none"))']
            runner = "false"
            "#,
        )
        .build();

    p.cargo("run -- --param")
        .with_status(101)
        .with_stderr(
            "\
[ERROR] several matching instances of `target.'cfg(..)'.runner` in `.cargo/config`
first match `cfg(not(target_arch = \"avr\"))` located in [..]/foo/.cargo/config
second match `cfg(not(target_os = \"none\"))` located in [..]/foo/.cargo/config
",
        )
        .run();
}

#[cargo_test]
fn custom_runner_env() {
    let target = rustc_host();
    let p = project().file("src/main.rs", "fn main() {}").build();

    let key = format!(
        "CARGO_TARGET_{}_RUNNER",
        target.to_uppercase().replace('-', "_")
    );

    p.cargo("run")
        .env(&key, "nonexistent-runner --foo")
        .with_status(101)
        .with_stderr(&format!(
            "\
[COMPILING] foo [..]
[FINISHED] dev [..]
[RUNNING] `nonexistent-runner --foo target/debug/foo[EXE]`
[ERROR] could not execute process `nonexistent-runner --foo target/debug/foo[EXE]` (never executed)

Caused by:
  {}
",
            no_such_file_err_msg()
        ))
        .run();
}

#[cargo_test]
fn custom_runner_env_overrides_config() {
    let target = rustc_host();
    let p = project()
        .file("src/main.rs", "fn main() {}")
        .file(
            ".cargo/config.toml",
            &format!(
                r#"
                    [target.{}]
                    runner = "should-not-run -r"
                "#,
                target
            ),
        )
        .build();

    let key = format!(
        "CARGO_TARGET_{}_RUNNER",
        target.to_uppercase().replace('-', "_")
    );

    p.cargo("run")
        .env(&key, "should-run --foo")
        .with_status(101)
        .with_stderr_contains("[RUNNING] `should-run --foo target/debug/foo[EXE]`")
        .run();
}

#[cargo_test]
#[cfg(unix)] // Assumes `true` is in PATH.
fn custom_runner_env_true() {
    // Check for a bug where "true" was interpreted as a boolean instead of
    // the executable.
    let target = rustc_host();
    let p = project().file("src/main.rs", "fn main() {}").build();

    let key = format!(
        "CARGO_TARGET_{}_RUNNER",
        target.to_uppercase().replace('-', "_")
    );

    p.cargo("run")
        .env(&key, "true")
        .with_stderr_contains("[RUNNING] `true target/debug/foo[EXE]`")
        .run();
}

#[cargo_test]
fn custom_linker_env() {
    let target = rustc_host();
    let p = project().file("src/main.rs", "fn main() {}").build();

    let key = format!(
        "CARGO_TARGET_{}_LINKER",
        target.to_uppercase().replace('-', "_")
    );

    p.cargo("build -v")
        .env(&key, "nonexistent-linker")
        .with_status(101)
        .with_stderr_contains("[RUNNING] `rustc [..]-C linker=nonexistent-linker [..]")
        .run();
}

#[cargo_test]
fn target_in_environment_contains_lower_case() {
    let p = project().file("src/main.rs", "fn main() {}").build();

    let target_keys = [
        "CARGO_TARGET_X86_64_UNKNOWN_LINUX_musl_LINKER",
        "CARGO_TARGET_x86_64_unknown_linux_musl_LINKER",
    ];

    for target_key in &target_keys {
        let mut execs = p.cargo("build -v --target x86_64-unknown-linux-musl");
        execs.env(target_key, "nonexistent-linker").with_status(101);
        if cfg!(windows) {
            execs.with_stderr_does_not_contain("warning:[..]");
        } else {
            execs.with_stderr_contains(format!(
                "warning: Environment variables are expected to use uppercase letters and underscores, \
                the variable `{}` will be ignored and have no effect",
                target_key
            ));
        }
        execs.run();
    }
}

#[cargo_test]
fn cfg_ignored_fields() {
    // Test for some ignored fields in [target.'cfg()'] tables.
    let p = project()
        .file(
            ".cargo/config",
            r#"
            # Try some empty tables.
            [target.'cfg(not(foo))']
            [target.'cfg(not(bar))'.somelib]

            # A bunch of unused fields.
            [target.'cfg(not(target_os = "none"))']
            linker = 'false'
            ar = 'false'
            foo = {rustc-flags = "-l foo"}
            invalid = 1
            runner = 'false'
            rustflags = ''
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("check")
        .with_stderr(
            "\
[WARNING] unused key `somelib` in [target] config table `cfg(not(bar))`
[WARNING] unused key `ar` in [target] config table `cfg(not(target_os = \"none\"))`
[WARNING] unused key `foo` in [target] config table `cfg(not(target_os = \"none\"))`
[WARNING] unused key `invalid` in [target] config table `cfg(not(target_os = \"none\"))`
[WARNING] unused key `linker` in [target] config table `cfg(not(target_os = \"none\"))`
[CHECKING] foo v0.0.1 ([..])
[FINISHED] [..]
",
        )
        .run();
}
<|endoftext|>


<commit_before>//! Tests for --unit-graph option.

use cargo_test_support::project;
use cargo_test_support::registry::Package;

#[cargo_test]
fn gated() {
    let p = project().file("src/lib.rs", "").build();
    p.cargo("build --unit-graph")
        .with_status(101)
        .with_stderr(
            "\
[ERROR] the `--unit-graph` flag is unstable[..]
See [..]
See [..]
",
        )
        .run();
}

#[cargo_test]
fn simple() {
    Package::new("a", "1.0.0")
        .dep("b", "1.0")
        .feature("feata", &["b/featb"])
        .publish();
    Package::new("b", "1.0.0")
        .dep("c", "1.0")
        .feature("featb", &["c/featc"])
        .publish();
    Package::new("c", "1.0.0").feature("featc", &[]).publish();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.1.0"

            [dependencies]
            a = "1.0"
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("build --features a/feata --unit-graph -Zunstable-options")
        .masquerade_as_nightly_cargo()
        .with_json(
            r#"{
              "roots": [
                3
              ],
              "units": [
                {
                  "dependencies": [
                    {
                      "extern_crate_name": "b",
                      "index": 1,
                      "noprelude": false,
                      "public": false
                    }
                  ],
                  "features": [
                    "feata"
                  ],
                  "mode": "build",
                  "pkg_id": "a 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
                  "platform": null,
                  "profile": {
                    "codegen_backend": null,
                    "codegen_units": null,
                    "debug_assertions": true,
                    "debuginfo": 2,
                    "incremental": false,
                    "lto": "false",
                    "name": "dev",
                    "opt_level": "0",
                    "overflow_checks": true,
                    "panic": "unwind",
                    "rpath": false,
                    "split_debuginfo": null,
                    "strip": "none"
                  },
                  "target": {
                    "crate_types": [
                      "lib"
                    ],
                    "doc": true,
                    "doctest": true,
                    "edition": "2015",
                    "kind": [
                      "lib"
                    ],
                    "name": "a",
                    "src_path": "[..]/a-1.0.0/src/lib.rs",
                    "test": true
                  }
                },
                {
                  "dependencies": [
                    {
                      "extern_crate_name": "c",
                      "index": 2,
                      "noprelude": false,
                      "public": false
                    }
                  ],
                  "features": [
                    "featb"
                  ],
                  "mode": "build",
                  "pkg_id": "b 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
                  "platform": null,
                  "profile": {
                    "codegen_backend": null,
                    "codegen_units": null,
                    "debug_assertions": true,
                    "debuginfo": 2,
                    "incremental": false,
                    "lto": "false",
                    "name": "dev",
                    "opt_level": "0",
                    "overflow_checks": true,
                    "panic": "unwind",
                    "rpath": false,
                    "split_debuginfo": null,
                    "strip": "none"
                  },
                  "target": {
                    "crate_types": [
                      "lib"
                    ],
                    "doc": true,
                    "doctest": true,
                    "edition": "2015",
                    "kind": [
                      "lib"
                    ],
                    "name": "b",
                    "src_path": "[..]/b-1.0.0/src/lib.rs",
                    "test": true
                  }
                },
                {
                  "dependencies": [],
                  "features": [
                    "featc"
                  ],
                  "mode": "build",
                  "pkg_id": "c 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
                  "platform": null,
                  "profile": {
                    "codegen_backend": null,
                    "codegen_units": null,
                    "debug_assertions": true,
                    "debuginfo": 2,
                    "incremental": false,
                    "lto": "false",
                    "name": "dev",
                    "opt_level": "0",
                    "overflow_checks": true,
                    "panic": "unwind",
                    "rpath": false,
                    "split_debuginfo": null,
                    "strip": "none"
                  },
                  "target": {
                    "crate_types": [
                      "lib"
                    ],
                    "doc": true,
                    "doctest": true,
                    "edition": "2015",
                    "kind": [
                      "lib"
                    ],
                    "name": "c",
                    "src_path": "[..]/c-1.0.0/src/lib.rs",
                    "test": true
                  }
                },
                {
                  "dependencies": [
                    {
                      "extern_crate_name": "a",
                      "index": 0,
                      "noprelude": false,
                      "public": false
                    }
                  ],
                  "features": [],
                  "mode": "build",
                  "pkg_id": "foo 0.1.0 (path+file://[..]/foo)",
                  "platform": null,
                  "profile": {
                    "codegen_backend": null,
                    "codegen_units": null,
                    "debug_assertions": true,
                    "debuginfo": 2,
                    "incremental": false,
                    "lto": "false",
                    "name": "dev",
                    "opt_level": "0",
                    "overflow_checks": true,
                    "panic": "unwind",
                    "rpath": false,
                    "split_debuginfo": null,
                    "strip": "none"
                  },
                  "target": {
                    "crate_types": [
                      "lib"
                    ],
                    "doc": true,
                    "doctest": true,
                    "edition": "2015",
                    "kind": [
                      "lib"
                    ],
                    "name": "foo",
                    "src_path": "[..]/foo/src/lib.rs",
                    "test": true
                  }
                }
              ],
              "version": 1
            }
            "#,
        )
        .run();
}
<commit_msg>Fix test<commit_after>//! Tests for --unit-graph option.

use cargo_test_support::project;
use cargo_test_support::registry::Package;

#[cargo_test]
fn gated() {
    let p = project().file("src/lib.rs", "").build();
    p.cargo("build --unit-graph")
        .with_status(101)
        .with_stderr(
            "\
[ERROR] the `--unit-graph` flag is unstable[..]
See [..]
See [..]
",
        )
        .run();
}

#[cargo_test]
fn simple() {
    Package::new("a", "1.0.0")
        .dep("b", "1.0")
        .feature("feata", &["b/featb"])
        .publish();
    Package::new("b", "1.0.0")
        .dep("c", "1.0")
        .feature("featb", &["c/featc"])
        .publish();
    Package::new("c", "1.0.0").feature("featc", &[]).publish();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.1.0"

            [dependencies]
            a = "1.0"
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("build --features a/feata --unit-graph -Zunstable-options")
        .masquerade_as_nightly_cargo()
        .with_json(
            r#"{
              "roots": [
                3
              ],
              "units": [
                {
                  "dependencies": [
                    {
                      "extern_crate_name": "b",
                      "index": 1,
                      "noprelude": false,
                      "public": false
                    }
                  ],
                  "features": [
                    "feata"
                  ],
                  "mode": "build",
                  "pkg_id": "a 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
                  "platform": null,
                  "profile": {
                    "codegen_backend": null,
                    "codegen_units": null,
                    "debug_assertions": true,
                    "debuginfo": 2,
                    "incremental": false,
                    "lto": "false",
                    "name": "dev",
                    "opt_level": "0",
                    "overflow_checks": true,
                    "panic": "unwind",
                    "rpath": false,
                    "split_debuginfo": "{...}",
                    "strip": "none"
                  },
                  "target": {
                    "crate_types": [
                      "lib"
                    ],
                    "doc": true,
                    "doctest": true,
                    "edition": "2015",
                    "kind": [
                      "lib"
                    ],
                    "name": "a",
                    "src_path": "[..]/a-1.0.0/src/lib.rs",
                    "test": true
                  }
                },
                {
                  "dependencies": [
                    {
                      "extern_crate_name": "c",
                      "index": 2,
                      "noprelude": false,
                      "public": false
                    }
                  ],
                  "features": [
                    "featb"
                  ],
                  "mode": "build",
                  "pkg_id": "b 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
                  "platform": null,
                  "profile": {
                    "codegen_backend": null,
                    "codegen_units": null,
                    "debug_assertions": true,
                    "debuginfo": 2,
                    "incremental": false,
                    "lto": "false",
                    "name": "dev",
                    "opt_level": "0",
                    "overflow_checks": true,
                    "panic": "unwind",
                    "rpath": false,
                    "split_debuginfo": "{...}",
                    "strip": "none"
                  },
                  "target": {
                    "crate_types": [
                      "lib"
                    ],
                    "doc": true,
                    "doctest": true,
                    "edition": "2015",
                    "kind": [
                      "lib"
                    ],
                    "name": "b",
                    "src_path": "[..]/b-1.0.0/src/lib.rs",
                    "test": true
                  }
                },
                {
                  "dependencies": [],
                  "features": [
                    "featc"
                  ],
                  "mode": "build",
                  "pkg_id": "c 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
                  "platform": null,
                  "profile": {
                    "codegen_backend": null,
                    "codegen_units": null,
                    "debug_assertions": true,
                    "debuginfo": 2,
                    "incremental": false,
                    "lto": "false",
                    "name": "dev",
                    "opt_level": "0",
                    "overflow_checks": true,
                    "panic": "unwind",
                    "rpath": false,
                    "split_debuginfo": "{...}",
                    "strip": "none"
                  },
                  "target": {
                    "crate_types": [
                      "lib"
                    ],
                    "doc": true,
                    "doctest": true,
                    "edition": "2015",
                    "kind": [
                      "lib"
                    ],
                    "name": "c",
                    "src_path": "[..]/c-1.0.0/src/lib.rs",
                    "test": true
                  }
                },
                {
                  "dependencies": [
                    {
                      "extern_crate_name": "a",
                      "index": 0,
                      "noprelude": false,
                      "public": false
                    }
                  ],
                  "features": [],
                  "mode": "build",
                  "pkg_id": "foo 0.1.0 (path+file://[..]/foo)",
                  "platform": null,
                  "profile": {
                    "codegen_backend": null,
                    "codegen_units": null,
                    "debug_assertions": true,
                    "debuginfo": 2,
                    "incremental": false,
                    "lto": "false",
                    "name": "dev",
                    "opt_level": "0",
                    "overflow_checks": true,
                    "panic": "unwind",
                    "rpath": false,
                    "split_debuginfo": "{...}",
                    "strip": "none"
                  },
                  "target": {
                    "crate_types": [
                      "lib"
                    ],
                    "doc": true,
                    "doctest": true,
                    "edition": "2015",
                    "kind": [
                      "lib"
                    ],
                    "name": "foo",
                    "src_path": "[..]/foo/src/lib.rs",
                    "test": true
                  }
                }
              ],
              "version": 1
            }
            "#,
        )
        .run();
}
<|endoftext|>


<commit_before>use std::path::{Path, PathBuf};
use std::io;
use std::str;
use std::io::{Cursor, Read, Write};
use std::ops::DerefMut;
use std::collections::hash_map::{HashMap, Entry};
use std::sync::{Arc, Mutex};
use std::mem;
use std::marker::PhantomData;

use rex::filesystem::Filesystem;

const NUM_CONFIG_TESTS: usize = 2;

const CONFIG_PATH: &'static str = "/config/rex/rex.conf";

pub trait MockFilesystemBackend {
    fn get_backend() -> MockFilesystemImpl;
}

pub struct MockFilesystemImpl {
    files: Arc<Mutex<HashMap<PathBuf, Arc<Mutex<Vec<u8>>>>>>,
}

impl Default for MockFilesystemImpl {
    fn default() -> MockFilesystemImpl {
        MockFilesystemImpl {
            files: Arc::new(Mutex::new(HashMap::new()))
        }
    }
}

impl Clone for MockFilesystemImpl {
    fn clone(&self) -> MockFilesystemImpl {
        MockFilesystemImpl {
            files: self.files.clone()
        }
    }
}

pub struct MockFile(Arc<Mutex<Vec<u8>>>, u64);

impl MockFile {
    fn new(vec: Arc<Mutex<Vec<u8>>>) -> MockFile {
        MockFile(vec, 0)
    }
}

// A small wrapper to help with a workaround until https://github.com/rust-lang/rust/issues/30132
// is fixed.
macro_rules! do_with_cursor {
    ($obj:expr, $func:ident($($arg:expr),*)) => ({
        let mut self_ = $obj;
        let mut vec = self_.0.lock().unwrap();
        let mut p_vec = vec.deref_mut();
        let mut tmp = Vec::new();

        mem::swap(p_vec, &mut tmp);
        let mut c = Cursor::new(tmp);
        c.set_position(self_.1);
        let ret = c.$func($($arg),*);
        self_.1 = c.position();
        tmp = c.into_inner();
        mem::swap(p_vec, &mut tmp);
        ret
    })
}

impl Read for MockFile {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        do_with_cursor!(self, read(buf))
    }
}

impl Write for MockFile {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        do_with_cursor!(self, write(buf))
    }

    fn flush(&mut self) -> io::Result<()> {
        do_with_cursor!(self, flush())
    }
}

#[derive(Debug, Clone, Copy)]
pub struct ThreadLocalMockFilesystem;

thread_local!(static THREAD_LOCAL_MOCK_FILESYSTEM: MockFilesystemImpl = Default::default());

impl MockFilesystemBackend for ThreadLocalMockFilesystem {
    fn get_backend() -> MockFilesystemImpl {
        let mut ret: Option<MockFilesystemImpl> = None;
        THREAD_LOCAL_MOCK_FILESYSTEM.with(
            |val| ret = Some(val.clone())
        );
        ret.unwrap()
    }
}

pub struct MockFilesystem<T: MockFilesystemBackend + 'static = ThreadLocalMockFilesystem>(PhantomData<T>);

impl<T: MockFilesystemBackend + 'static> Filesystem for MockFilesystem<T> {
    type FSRead = MockFile;
    type FSWrite = MockFile;

    fn get_config_home() -> PathBuf {
        PathBuf::from("/config/")
    }

    fn make_absolute<P: AsRef<Path>>(p: P) -> io::Result<PathBuf> {
        Ok(p.as_ref().into())
    }

    fn open<P: AsRef<Path>>(path: P) -> io::Result<Self::FSRead> {
        let backend = T::get_backend();
        let file_map = backend.files.lock().unwrap();
        file_map.get(path.as_ref()).ok_or(io::Error::new(io::ErrorKind::NotFound, "File not found!")).map(|file|
            MockFile::new(file.clone())
        )
    }

    fn can_open<P: AsRef<Path>>(_p: P) -> io::Result<()> {
        Ok(())
    }

    fn save<P: AsRef<Path>>(path: P) -> io::Result<Self::FSWrite> {
        let backend = T::get_backend();
        let mut file_map = backend.files.lock().unwrap();
        let file = file_map.entry(path.as_ref().into()).or_insert_with(|| Arc::new(Mutex::new(Vec::new())));

        Ok(MockFile::new(file.clone()))
    }

    fn can_save<P: AsRef<Path>>(_p: P) -> io::Result<()> {
        Ok(())
    }
}

impl<T: MockFilesystemBackend + 'static> MockFilesystem<T> {
    pub fn open_config() -> io::Result<<MockFilesystem<T> as Filesystem>::FSRead> {
        Self::open(CONFIG_PATH)
    }

    pub fn save_config() -> io::Result<<MockFilesystem<T> as Filesystem>::FSWrite> {
        Self::save(CONFIG_PATH)
    }

    }

    pub fn reset() {
        let backend = T::get_backend();
        backend.files.lock().unwrap().clear();
    }

    pub fn get_inner<'a, P: AsRef<Path>>(path: P) -> Vec<u8> {
        // This function is very ugly, in general we would like to "unwrap" the file from the
        // mock filesystem. Sadly, there doesn't seem to be a better way.
        let backend = T::get_backend();
        let mut file_map = backend.files.lock().unwrap();
        let f = file_map.remove(path.as_ref()).unwrap();
        let a = Arc::try_unwrap(f).unwrap();
        let m = a.lock().unwrap();
        let v = m.clone();
        v
    }

    pub fn put<'a, P: AsRef<Path>>(path: P, v: Vec<u8>) {
        let backend = T::get_backend();
        let mut file_map = backend.files.lock().unwrap();
        file_map.insert(path.as_ref().into(), Arc::new(Mutex::new(v)));
    }
}
<commit_msg>Add helper function to mock filesystem for debugging<commit_after>use std::path::{Path, PathBuf};
use std::io;
use std::str;
use std::io::{Cursor, Read, Write};
use std::ops::DerefMut;
use std::collections::hash_map::{HashMap, Entry};
use std::sync::{Arc, Mutex};
use std::mem;
use std::marker::PhantomData;

use rex::filesystem::Filesystem;

const NUM_CONFIG_TESTS: usize = 2;

const CONFIG_PATH: &'static str = "/config/rex/rex.conf";

pub trait MockFilesystemBackend {
    fn get_backend() -> MockFilesystemImpl;
}

pub struct MockFilesystemImpl {
    files: Arc<Mutex<HashMap<PathBuf, Arc<Mutex<Vec<u8>>>>>>,
}

impl Default for MockFilesystemImpl {
    fn default() -> MockFilesystemImpl {
        MockFilesystemImpl {
            files: Arc::new(Mutex::new(HashMap::new()))
        }
    }
}

impl Clone for MockFilesystemImpl {
    fn clone(&self) -> MockFilesystemImpl {
        MockFilesystemImpl {
            files: self.files.clone()
        }
    }
}

pub struct MockFile(Arc<Mutex<Vec<u8>>>, u64);

impl MockFile {
    fn new(vec: Arc<Mutex<Vec<u8>>>) -> MockFile {
        MockFile(vec, 0)
    }
}

// A small wrapper to help with a workaround until https://github.com/rust-lang/rust/issues/30132
// is fixed.
macro_rules! do_with_cursor {
    ($obj:expr, $func:ident($($arg:expr),*)) => ({
        let mut self_ = $obj;
        let mut vec = self_.0.lock().unwrap();
        let mut p_vec = vec.deref_mut();
        let mut tmp = Vec::new();

        mem::swap(p_vec, &mut tmp);
        let mut c = Cursor::new(tmp);
        c.set_position(self_.1);
        let ret = c.$func($($arg),*);
        self_.1 = c.position();
        tmp = c.into_inner();
        mem::swap(p_vec, &mut tmp);
        ret
    })
}

impl Read for MockFile {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        do_with_cursor!(self, read(buf))
    }
}

impl Write for MockFile {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        do_with_cursor!(self, write(buf))
    }

    fn flush(&mut self) -> io::Result<()> {
        do_with_cursor!(self, flush())
    }
}

#[derive(Debug, Clone, Copy)]
pub struct ThreadLocalMockFilesystem;

thread_local!(static THREAD_LOCAL_MOCK_FILESYSTEM: MockFilesystemImpl = Default::default());

impl MockFilesystemBackend for ThreadLocalMockFilesystem {
    fn get_backend() -> MockFilesystemImpl {
        let mut ret: Option<MockFilesystemImpl> = None;
        THREAD_LOCAL_MOCK_FILESYSTEM.with(
            |val| ret = Some(val.clone())
        );
        ret.unwrap()
    }
}

pub struct MockFilesystem<T: MockFilesystemBackend + 'static = ThreadLocalMockFilesystem>(PhantomData<T>);

impl<T: MockFilesystemBackend + 'static> Filesystem for MockFilesystem<T> {
    type FSRead = MockFile;
    type FSWrite = MockFile;

    fn get_config_home() -> PathBuf {
        PathBuf::from("/config/")
    }

    fn make_absolute<P: AsRef<Path>>(p: P) -> io::Result<PathBuf> {
        Ok(p.as_ref().into())
    }

    fn open<P: AsRef<Path>>(path: P) -> io::Result<Self::FSRead> {
        let backend = T::get_backend();
        let file_map = backend.files.lock().unwrap();
        file_map.get(path.as_ref()).ok_or(io::Error::new(io::ErrorKind::NotFound, "File not found!")).map(|file|
            MockFile::new(file.clone())
        )
    }

    fn can_open<P: AsRef<Path>>(_p: P) -> io::Result<()> {
        Ok(())
    }

    fn save<P: AsRef<Path>>(path: P) -> io::Result<Self::FSWrite> {
        let backend = T::get_backend();
        let mut file_map = backend.files.lock().unwrap();
        let file = file_map.entry(path.as_ref().into()).or_insert_with(|| Arc::new(Mutex::new(Vec::new())));

        Ok(MockFile::new(file.clone()))
    }

    fn can_save<P: AsRef<Path>>(_p: P) -> io::Result<()> {
        Ok(())
    }
}

impl<T: MockFilesystemBackend + 'static> MockFilesystem<T> {
    pub fn open_config() -> io::Result<<MockFilesystem<T> as Filesystem>::FSRead> {
        Self::open(CONFIG_PATH)
    }

    pub fn save_config() -> io::Result<<MockFilesystem<T> as Filesystem>::FSWrite> {
        Self::save(CONFIG_PATH)
    }

    pub fn list_paths() -> Vec<PathBuf> {
        let backend = T::get_backend();
        let r : Vec<PathBuf> = backend.files.lock().unwrap().keys().map( |i| i.clone() ).collect();
        r
    }

    pub fn reset() {
        let backend = T::get_backend();
        backend.files.lock().unwrap().clear();
    }

    pub fn get_inner<'a, P: AsRef<Path>>(path: P) -> Vec<u8> {
        // This function is very ugly, in general we would like to "unwrap" the file from the
        // mock filesystem. Sadly, there doesn't seem to be a better way.
        let backend = T::get_backend();
        let mut file_map = backend.files.lock().unwrap();
        let f = file_map.remove(path.as_ref()).unwrap();
        let a = Arc::try_unwrap(f).unwrap();
        let m = a.lock().unwrap();
        let v = m.clone();
        v
    }

    pub fn put<'a, P: AsRef<Path>>(path: P, v: Vec<u8>) {
        let backend = T::get_backend();
        let mut file_map = backend.files.lock().unwrap();
        file_map.insert(path.as_ref().into(), Arc::new(Mutex::new(v)));
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015-2017 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use std::env;
use std::path::PathBuf;
use std::process::Command;

pub fn run_java(class: &str, arguments: &str) -> bool {
    Command::new(&java())
        .arg(format!("-agentpath:{}{}", jvmkill().to_str().unwrap(), arguments))
        .arg("-cp").arg(jvmkill_test().to_str().unwrap())
        .arg(class)
        .status().unwrap().success()
}

fn java() -> PathBuf {
    return PathBuf::from(env::var("JAVA_HOME").unwrap()).join("bin").join("java");
}

fn jvmkill_test() -> PathBuf {
    return env::current_dir().unwrap().parent().unwrap().join("resource-exhaustion-generator").join("target").join("resource-exhaustion-generator-0.0.0.jar");
}

fn jvmkill() -> PathBuf {
    let root = PathBuf::from(env::var("LD_LIBRARY_PATH").or(env::var("DYLD_LIBRARY_PATH")).unwrap().split(":").next().unwrap());

    if cfg!(target_os = "macos") {
        return root.join("libjvmkill.dylib");
    } else {
        return root.join("libjvmkill.so");
    }
}<commit_msg>Polishing<commit_after>/*
 * Copyright (c) 2015-2017 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use std::env;
use std::path::PathBuf;
use std::process::Command;

pub fn run_java(class: &str, arguments: &str) -> bool {
    return Command::new(&java())
        .arg(format!("-agentpath:{}{}", jvmkill().to_str().unwrap(), arguments))
        .arg("-cp").arg(jvmkill_test().to_str().unwrap())
        .arg(class)
        .status().unwrap().success();
}

fn java() -> PathBuf {
    return PathBuf::from(env::var("JAVA_HOME").unwrap()).join("bin").join("java");
}

fn jvmkill_test() -> PathBuf {
    return env::current_dir().unwrap().parent().unwrap().join("resource-exhaustion-generator").join("target").join("resource-exhaustion-generator-0.0.0.jar");
}

fn jvmkill() -> PathBuf {
    let root = PathBuf::from(env::var("LD_LIBRARY_PATH").or(env::var("DYLD_LIBRARY_PATH")).unwrap().split(":").next().unwrap());

    if cfg!(target_os = "macos") {
        return root.join("libjvmkill.dylib");
    } else {
        return root.join("libjvmkill.so");
    }
}<|endoftext|>


<commit_before>use termbox_simple::Termbox;
use term_input::Key;

use std::collections::HashMap;
use std::convert::From;
use std::rc::Rc;

use time::Tm;
use time;

use config::Style;
use config;
use trie::Trie;
use tui::exit_dialogue::ExitDialogue;
use tui::msg_area::MsgArea;
use tui::termbox;
use tui::text_field::TextField;
use tui::widget::{WidgetRet, Widget};

/// A messaging screen is just a text field to type messages and msg area to
/// show incoming/sent messages.
pub struct MessagingUI {
    /// Incoming and sent messages appear
    msg_area: MsgArea,

    /// Stacked user input fields. Topmost one handles keypresses.
    input_field: Vec<Box<Widget>>,

    width: i32,
    height: i32,

    // NOTE: Color is encoded in Termbox's 216 colors. (in 256-color mode)
    nick_colors: HashMap<String, u8>,
    /// Index of the next color to use when highlighting a new nick. Always a valid index to
    /// `config::NICK_COLORS`.
    next_color_idx: usize,

    // All nicks in the channel. Need to keep this up-to-date to be able to
    // properly highlight mentions.
    //
    // Rc to be able to share with dynamic messages.
    nicks: Rc<Trie>,

    current_nick: Option<Rc<String>>,
    draw_current_nick: bool,

    last_activity_line: Option<ActivityLine>,
    last_activity_ts: Option<Timestamp>,
}

/// Like `time::Tm`, but we only care about hour and minute parts.
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct Timestamp {
    hour: i32,
    min: i32,
}

impl Timestamp {
    pub fn now() -> Timestamp {
        Timestamp::from(time::now())
    }

    fn stamp(&self, msg_area: &mut MsgArea) {
        msg_area.set_style(config::TIMESTAMP);
        msg_area.add_text(&format!("{:02}:{:02} ", self.hour, self.min));
    }
}

impl From<Tm> for Timestamp {
    fn from(tm: Tm) -> Timestamp {
        Timestamp { hour: tm.tm_hour, min: tm.tm_min }
    }
}

/// An activity line is just a line that we update on joins / leaves /
/// disconnects. We group activities that happen in the same minute to avoid
/// redundantly showing lines.
struct ActivityLine {
    ts: Timestamp,
    line_idx: usize,
}

impl MessagingUI {
    pub fn new(width : i32, height : i32) -> MessagingUI {
        MessagingUI {
            msg_area: MsgArea::new(width, height - 1),
            input_field: vec![Box::new(TextField::new(width))],
            width: width,
            height: height,
            nick_colors: HashMap::new(),
            next_color_idx: 0,
            nicks: Rc::new(Trie::new()),
            current_nick: None,
            draw_current_nick: true,
            last_activity_line: None,
            last_activity_ts: None,
        }
    }

    pub fn set_nick(&mut self, nick: Rc<String>) {
        self.current_nick = Some(nick);
    }

    pub fn get_nick(&self) -> Option<Rc<String>> {
        self.current_nick.clone()
    }

    pub fn draw(&self, tb: &mut Termbox, pos_x: i32, pos_y: i32) {
        self.msg_area.draw(tb, pos_x, pos_y);

        if let &Some(ref nick) = &self.current_nick {
            if self.draw_current_nick {
                termbox::print_chars(
                    tb,
                    pos_x,
                    pos_y + self.height - 1,
                    config::USER_MSG,
                    &mut nick.chars());
                tb.change_cell(
                    pos_x + nick.len() as i32,
                    pos_y + self.height - 1,
                    ':',
                    config::USER_MSG.fg | config::TB_BOLD,
                    config::USER_MSG.bg);
                self.input_field.draw(
                    tb,
                    pos_x + nick.len() as i32 + 2,
                    pos_y + self.height - 1);
            } else {
                self.input_field.draw(tb, pos_x, pos_y + self.height - 1);
            }
        } else {
            self.input_field.draw(tb, pos_x, pos_y + self.height - 1);
        }
    }

    pub fn keypressed(&mut self, key : Key) -> WidgetRet {
        match key {
            Key::Ctrl('c') => {
                self.toggle_exit_dialogue();
                WidgetRet::KeyHandled
            },

            Key::Ctrl('u') => {
                self.msg_area.page_up();
                WidgetRet::KeyHandled
            },

            Key::Ctrl('d') => {
                self.msg_area.page_down();
                WidgetRet::KeyHandled
            },

            Key::PageUp => {
                self.msg_area.page_up();
                WidgetRet::KeyHandled
            },

            Key::PageDown => {
                self.msg_area.page_down();
                WidgetRet::KeyHandled
            },

            Key::ShiftUp => {
                self.msg_area.scroll_up();
                WidgetRet::KeyHandled
            },

            Key::ShiftDown => {
                self.msg_area.scroll_down();
                WidgetRet::KeyHandled
            },

            Key::Tab => {
                self.input_field.event(Box::new(self.nicks.clone()));
                WidgetRet::KeyHandled
            },

            key => {
                match self.input_field.keypressed(key) {
                    WidgetRet::Remove => {
                        self.input_field.pop();
                        WidgetRet::KeyHandled
                    },
                    ret => ret,
                }
            },
        }
    }

    pub fn resize(&mut self, width: i32, height: i32) {
        self.width = width;
        self.height = height;
        self.msg_area.resize(width, height - 1);

        let nick_width = match &self.current_nick {
            &None =>
                0,
            &Some(ref rc) =>
                // +2 for ": "
                rc.len() as i32 + 2,
        };

        self.draw_current_nick =
            (nick_width as f32) <= (width as f32) * (30f32 / 100f32);

        let widget_width =
            if self.draw_current_nick { width - nick_width } else { width };

        for w in &mut self.input_field {
            w.resize(widget_width, 1);
        }
    }

    fn toggle_exit_dialogue(&mut self) {
        assert!(self.input_field.len() > 0);
        // FIXME: This is a bit too fragile I think. Since we only stack an exit
        // dialogue on top of the input field at the moment, checking the len()
        // is fine. If we decide to stack more stuff it'll break.
        if self.input_field.len() == 1 {
            self.input_field.push(Box::new(ExitDialogue::new(self.width)));
        } else {
            self.input_field.pop();
        }
    }
}

////////////////////////////////////////////////////////////////////////////////
// Adding new messages

impl MessagingUI {

    fn add_timestamp(&mut self, ts: Timestamp) {
        if let Some(ts_) = self.last_activity_ts {
            if ts_ != ts {
                ts.stamp(&mut self.msg_area);
            }
        } else {
            ts.stamp(&mut self.msg_area);

        }
        self.last_activity_ts = Some(ts);
    }

    pub fn show_topic(&mut self, topic: &str, ts: Timestamp) {
        self.add_timestamp(ts);

        self.msg_area.set_style(config::TOPIC);
        self.msg_area.add_text(&format!("Channel topic is: \"{}\"", topic));

        self.msg_area.flush_line();
    }

    pub fn add_client_err_msg(&mut self, msg : &str) {
        self.reset_activity_line();

        self.msg_area.set_style(config::ERR_MSG);
        self.msg_area.add_text(msg);
        self.msg_area.flush_line();
    }

    pub fn add_client_msg(&mut self, msg : &str) {
        self.reset_activity_line();

        self.msg_area.set_style(config::USER_MSG);
        self.msg_area.add_text(msg);
        self.msg_area.flush_line();
        self.reset_activity_line();
    }

    pub fn add_privmsg(&mut self, sender: &str, msg: &str, ts: Timestamp, higlight: bool) {
        self.reset_activity_line();
        self.add_timestamp(ts);

        {
            let nick_color = self.get_nick_color(sender);
            let style = Style { fg: nick_color as u16, bg: config::USER_MSG.bg };
            self.msg_area.set_style(style);
            self.msg_area.add_text(sender);
        }

        self.msg_area.set_style(Style { fg: config::USER_MSG.fg | config::TB_BOLD, bg: config::USER_MSG.bg });
        self.msg_area.add_text(": ");

        self.msg_area.set_style(
            if higlight {
                config::HIGHLIGHT
            } else {
                config::USER_MSG
            });

        self.msg_area.add_text(msg);
        self.msg_area.flush_line();
    }

    pub fn add_msg(&mut self, msg: &str, ts: Timestamp) {
        self.reset_activity_line();

        self.add_timestamp(ts);
        self.msg_area.set_style(config::USER_MSG);
        self.msg_area.add_text(msg);
        self.msg_area.flush_line();
    }

    pub fn add_err_msg(&mut self, msg: &str, ts: Timestamp) {
        self.reset_activity_line();

        self.add_timestamp(ts);
        self.msg_area.set_style(config::ERR_MSG);
        self.msg_area.add_text(msg);
        self.msg_area.flush_line();
    }

    fn get_nick_color(&mut self, sender: &str) -> u8 {
        if let Some(color) = self.nick_colors.get(sender) {
            return *color;
        }

        let color = config::NICK_COLORS[self.next_color_idx];
        self.nick_colors.insert(sender.to_owned(), color);
        self.next_color_idx = (self.next_color_idx + 1) % (config::NICK_COLORS.len() - 1);
        color
    }
}

////////////////////////////////////////////////////////////////////////////////
// Keeping nick list up-to-date

impl MessagingUI {
    pub fn join(&mut self, nick: &str, ts: Option<Timestamp>) {
        Rc::get_mut(&mut self.nicks).unwrap().insert(nick);

        if let Some(ts) = ts {
            let line_idx = self.get_activity_line_idx(ts);
            self.msg_area.modify_line(line_idx, |line| {
                line.set_style(config::JOIN);
                line.add_char('+');
                line.add_text(nick);
                line.add_char(' ');
            });
        }
    }

    pub fn part(&mut self, nick: &str, ts: Option<Timestamp>) {
        Rc::get_mut(&mut self.nicks).unwrap().remove(nick);

        if let Some(ts) = ts {
            let line_idx = self.get_activity_line_idx(ts);
            self.msg_area.modify_line(line_idx, |line| {
                line.set_style(config::PART);
                line.add_char('-');
                line.add_text(nick);
                line.add_char(' ');
            });
        }
    }

    pub fn nick(&mut self, old_nick: &str, new_nick: &str, ts: Timestamp) {
        Rc::get_mut(&mut self.nicks).unwrap().remove(old_nick);
        Rc::get_mut(&mut self.nicks).unwrap().insert(new_nick);
        let color = self.nick_colors.remove(old_nick);
        if let Some(color_) = color {
            self.nick_colors.insert(new_nick.to_owned(), color_);
        }

        let line_idx = self.get_activity_line_idx(ts);
        self.msg_area.modify_line(line_idx, |line| {
            line.set_style(config::NICK);
            line.add_text(old_nick);
            line.add_text("->");
            line.add_text(new_nick);
            line.add_char(' ');
        });
    }

    pub fn has_nick(&self, nick : &str) -> bool {
        self.nicks.contains(nick)
    }

    fn reset_activity_line(&mut self) {
        self.last_activity_line = None;
    }

    fn get_activity_line_idx(&mut self, ts: Timestamp) -> usize {
        // borrow checker strikes again
        if let Some(ref mut l) = self.last_activity_line {
            if l.ts == ts {
                return l.line_idx;
            }
        }

        self.add_timestamp(ts);
        let line_idx = self.msg_area.flush_line();
        self.last_activity_line = Some(ActivityLine {
            ts: ts,
            line_idx: line_idx,
        });
        line_idx
    }
}
<commit_msg>Delete bookeeping for nick colors, use nick hash for color index<commit_after>use termbox_simple::Termbox;
use term_input::Key;

use std::convert::From;
use std::rc::Rc;

use time::Tm;
use time;

use config::Style;
use config;
use trie::Trie;
use tui::exit_dialogue::ExitDialogue;
use tui::msg_area::MsgArea;
use tui::termbox;
use tui::text_field::TextField;
use tui::widget::{WidgetRet, Widget};

/// A messaging screen is just a text field to type messages and msg area to
/// show incoming/sent messages.
pub struct MessagingUI {
    /// Incoming and sent messages appear
    msg_area: MsgArea,

    /// Stacked user input fields. Topmost one handles keypresses.
    input_field: Vec<Box<Widget>>,

    width: i32,
    height: i32,

    // All nicks in the channel. Need to keep this up-to-date to be able to
    // properly highlight mentions.
    //
    // Rc to be able to share with dynamic messages.
    nicks: Rc<Trie>,

    current_nick: Option<Rc<String>>,
    draw_current_nick: bool,

    last_activity_line: Option<ActivityLine>,
    last_activity_ts: Option<Timestamp>,
}

/// Like `time::Tm`, but we only care about hour and minute parts.
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct Timestamp {
    hour: i32,
    min: i32,
}

impl Timestamp {
    pub fn now() -> Timestamp {
        Timestamp::from(time::now())
    }

    fn stamp(&self, msg_area: &mut MsgArea) {
        msg_area.set_style(config::TIMESTAMP);
        msg_area.add_text(&format!("{:02}:{:02} ", self.hour, self.min));
    }
}

impl From<Tm> for Timestamp {
    fn from(tm: Tm) -> Timestamp {
        Timestamp { hour: tm.tm_hour, min: tm.tm_min }
    }
}

/// An activity line is just a line that we update on joins / leaves /
/// disconnects. We group activities that happen in the same minute to avoid
/// redundantly showing lines.
struct ActivityLine {
    ts: Timestamp,
    line_idx: usize,
}

impl MessagingUI {
    pub fn new(width : i32, height : i32) -> MessagingUI {
        MessagingUI {
            msg_area: MsgArea::new(width, height - 1),
            input_field: vec![Box::new(TextField::new(width))],
            width: width,
            height: height,
            nicks: Rc::new(Trie::new()),
            current_nick: None,
            draw_current_nick: true,
            last_activity_line: None,
            last_activity_ts: None,
        }
    }

    pub fn set_nick(&mut self, nick: Rc<String>) {
        self.current_nick = Some(nick);
    }

    pub fn get_nick(&self) -> Option<Rc<String>> {
        self.current_nick.clone()
    }

    pub fn draw(&self, tb: &mut Termbox, pos_x: i32, pos_y: i32) {
        self.msg_area.draw(tb, pos_x, pos_y);

        if let &Some(ref nick) = &self.current_nick {
            if self.draw_current_nick {
                termbox::print_chars(
                    tb,
                    pos_x,
                    pos_y + self.height - 1,
                    config::USER_MSG,
                    &mut nick.chars());
                tb.change_cell(
                    pos_x + nick.len() as i32,
                    pos_y + self.height - 1,
                    ':',
                    config::USER_MSG.fg | config::TB_BOLD,
                    config::USER_MSG.bg);
                self.input_field.draw(
                    tb,
                    pos_x + nick.len() as i32 + 2,
                    pos_y + self.height - 1);
            } else {
                self.input_field.draw(tb, pos_x, pos_y + self.height - 1);
            }
        } else {
            self.input_field.draw(tb, pos_x, pos_y + self.height - 1);
        }
    }

    pub fn keypressed(&mut self, key : Key) -> WidgetRet {
        match key {
            Key::Ctrl('c') => {
                self.toggle_exit_dialogue();
                WidgetRet::KeyHandled
            },

            Key::Ctrl('u') => {
                self.msg_area.page_up();
                WidgetRet::KeyHandled
            },

            Key::Ctrl('d') => {
                self.msg_area.page_down();
                WidgetRet::KeyHandled
            },

            Key::PageUp => {
                self.msg_area.page_up();
                WidgetRet::KeyHandled
            },

            Key::PageDown => {
                self.msg_area.page_down();
                WidgetRet::KeyHandled
            },

            Key::ShiftUp => {
                self.msg_area.scroll_up();
                WidgetRet::KeyHandled
            },

            Key::ShiftDown => {
                self.msg_area.scroll_down();
                WidgetRet::KeyHandled
            },

            Key::Tab => {
                self.input_field.event(Box::new(self.nicks.clone()));
                WidgetRet::KeyHandled
            },

            key => {
                match self.input_field.keypressed(key) {
                    WidgetRet::Remove => {
                        self.input_field.pop();
                        WidgetRet::KeyHandled
                    },
                    ret => ret,
                }
            },
        }
    }

    pub fn resize(&mut self, width: i32, height: i32) {
        self.width = width;
        self.height = height;
        self.msg_area.resize(width, height - 1);

        let nick_width = match &self.current_nick {
            &None =>
                0,
            &Some(ref rc) =>
                // +2 for ": "
                rc.len() as i32 + 2,
        };

        self.draw_current_nick =
            (nick_width as f32) <= (width as f32) * (30f32 / 100f32);

        let widget_width =
            if self.draw_current_nick { width - nick_width } else { width };

        for w in &mut self.input_field {
            w.resize(widget_width, 1);
        }
    }

    fn toggle_exit_dialogue(&mut self) {
        assert!(self.input_field.len() > 0);
        // FIXME: This is a bit too fragile I think. Since we only stack an exit
        // dialogue on top of the input field at the moment, checking the len()
        // is fine. If we decide to stack more stuff it'll break.
        if self.input_field.len() == 1 {
            self.input_field.push(Box::new(ExitDialogue::new(self.width)));
        } else {
            self.input_field.pop();
        }
    }
}

////////////////////////////////////////////////////////////////////////////////
// Adding new messages

impl MessagingUI {

    fn add_timestamp(&mut self, ts: Timestamp) {
        if let Some(ts_) = self.last_activity_ts {
            if ts_ != ts {
                ts.stamp(&mut self.msg_area);
            }
        } else {
            ts.stamp(&mut self.msg_area);

        }
        self.last_activity_ts = Some(ts);
    }

    pub fn show_topic(&mut self, topic: &str, ts: Timestamp) {
        self.add_timestamp(ts);

        self.msg_area.set_style(config::TOPIC);
        self.msg_area.add_text(&format!("Channel topic is: \"{}\"", topic));

        self.msg_area.flush_line();
    }

    pub fn add_client_err_msg(&mut self, msg : &str) {
        self.reset_activity_line();

        self.msg_area.set_style(config::ERR_MSG);
        self.msg_area.add_text(msg);
        self.msg_area.flush_line();
    }

    pub fn add_client_msg(&mut self, msg : &str) {
        self.reset_activity_line();

        self.msg_area.set_style(config::USER_MSG);
        self.msg_area.add_text(msg);
        self.msg_area.flush_line();
        self.reset_activity_line();
    }

    pub fn add_privmsg(&mut self, sender: &str, msg: &str, ts: Timestamp, higlight: bool) {
        self.reset_activity_line();
        self.add_timestamp(ts);

        {
            let nick_color = self.get_nick_color(sender);
            let style = Style { fg: nick_color as u16, bg: config::USER_MSG.bg };
            self.msg_area.set_style(style);
            self.msg_area.add_text(sender);
        }

        self.msg_area.set_style(Style { fg: config::USER_MSG.fg | config::TB_BOLD, bg: config::USER_MSG.bg });
        self.msg_area.add_text(": ");

        self.msg_area.set_style(
            if higlight {
                config::HIGHLIGHT
            } else {
                config::USER_MSG
            });

        self.msg_area.add_text(msg);
        self.msg_area.flush_line();
    }

    pub fn add_msg(&mut self, msg: &str, ts: Timestamp) {
        self.reset_activity_line();

        self.add_timestamp(ts);
        self.msg_area.set_style(config::USER_MSG);
        self.msg_area.add_text(msg);
        self.msg_area.flush_line();
    }

    pub fn add_err_msg(&mut self, msg: &str, ts: Timestamp) {
        self.reset_activity_line();

        self.add_timestamp(ts);
        self.msg_area.set_style(config::ERR_MSG);
        self.msg_area.add_text(msg);
        self.msg_area.flush_line();
    }

    fn get_nick_color(&self, sender: &str) -> u8 {
        // Anything works as long as it's fast
        let mut hash: usize = 5381;
        for c in sender.chars() {
            hash = hash * 33 + (c as usize);
        }
        config::NICK_COLORS[hash % config::NICK_COLORS.len()]
    }
}

////////////////////////////////////////////////////////////////////////////////
// Keeping nick list up-to-date

impl MessagingUI {
    pub fn join(&mut self, nick: &str, ts: Option<Timestamp>) {
        Rc::get_mut(&mut self.nicks).unwrap().insert(nick);

        if let Some(ts) = ts {
            let line_idx = self.get_activity_line_idx(ts);
            self.msg_area.modify_line(line_idx, |line| {
                line.set_style(config::JOIN);
                line.add_char('+');
                line.add_text(nick);
                line.add_char(' ');
            });
        }
    }

    pub fn part(&mut self, nick: &str, ts: Option<Timestamp>) {
        Rc::get_mut(&mut self.nicks).unwrap().remove(nick);

        if let Some(ts) = ts {
            let line_idx = self.get_activity_line_idx(ts);
            self.msg_area.modify_line(line_idx, |line| {
                line.set_style(config::PART);
                line.add_char('-');
                line.add_text(nick);
                line.add_char(' ');
            });
        }
    }

    pub fn nick(&mut self, old_nick: &str, new_nick: &str, ts: Timestamp) {
        Rc::get_mut(&mut self.nicks).unwrap().remove(old_nick);
        Rc::get_mut(&mut self.nicks).unwrap().insert(new_nick);

        let line_idx = self.get_activity_line_idx(ts);
        self.msg_area.modify_line(line_idx, |line| {
            line.set_style(config::NICK);
            line.add_text(old_nick);
            line.add_text("->");
            line.add_text(new_nick);
            line.add_char(' ');
        });
    }

    pub fn has_nick(&self, nick : &str) -> bool {
        self.nicks.contains(nick)
    }

    fn reset_activity_line(&mut self) {
        self.last_activity_line = None;
    }

    fn get_activity_line_idx(&mut self, ts: Timestamp) -> usize {
        // borrow checker strikes again
        if let Some(ref mut l) = self.last_activity_line {
            if l.ts == ts {
                return l.line_idx;
            }
        }

        self.add_timestamp(ts);
        let line_idx = self.msg_area.flush_line();
        self.last_activity_line = Some(ActivityLine {
            ts: ts,
            line_idx: line_idx,
        });
        line_idx
    }
}
<|endoftext|>


<commit_before>use std::sync::Arc;
use std::sync::mpsc::Receiver;
use sdl2::audio::{AudioDevice, AudioCallback, AudioSpecDesired};
use resampler::{Resampler, Async};

/// Reader struct used to feed the samples to the SDL callback
struct Reader {
    resampler: Resampler<Sample>,
}

impl Reader {
    pub fn new<'n>(resampler: Resampler<Sample>) -> Reader {
        Reader {
            resampler: resampler,
        }
    }
}

impl AudioCallback<Sample> for Reader {
    fn callback(&mut self, buf: &mut [Sample]) {
        self.resampler.fill_buf(buf);
    }
}

pub struct Audio {
    dev:   AudioDevice<Reader>,
    async: Arc<Async<Sample>>
}

impl Audio {
    pub fn new(channel: Receiver<::spu::SampleBuffer>) -> Audio {
        ::sdl2::init(::sdl2::INIT_AUDIO);

        let resampler = Resampler::new(channel, SAMPLE_RATE);

        let async = resampler.async();

        let reader = Reader::new(resampler);

        let spec = AudioSpecDesired {
            freq:     SAMPLE_RATE as i32,
            channels: 1,
            samples:  ::spu::SAMPLES_PER_BUFFER as u16,
            callback: reader,
        };

        let dev =
            match spec.open_audio_device(None, false) {
                Ok(d)  => d,
                Err(e) => panic!("{}", e),
            };

        Audio {
            dev:   dev,
            async: async,
        }
    }

    pub fn start(&self) {
        self.dev.resume();
    }
}

impl ::ui::Audio for Audio {
    fn adjust_resampling(&mut self, in_samples: u32) {
        self.async.adjust_resampling(in_samples);
    }
}

// Use 16bit sound samples
type Sample = i16;

/// Audio output sample rate
const SAMPLE_RATE: u32 = 44_100;
<commit_msg>Use 8bit sound samples for SDL<commit_after>use std::sync::Arc;
use std::sync::mpsc::Receiver;
use sdl2::audio::{AudioDevice, AudioCallback, AudioSpecDesired};
use resampler::{Resampler, Async};

/// Reader struct used to feed the samples to the SDL callback
struct Reader {
    resampler: Resampler<Sample>,
}

impl Reader {
    pub fn new<'n>(resampler: Resampler<Sample>) -> Reader {
        Reader {
            resampler: resampler,
        }
    }
}

impl AudioCallback<Sample> for Reader {
    fn callback(&mut self, buf: &mut [Sample]) {
        self.resampler.fill_buf(buf);
    }
}

pub struct Audio {
    dev:   AudioDevice<Reader>,
    async: Arc<Async<Sample>>
}

impl Audio {
    pub fn new(channel: Receiver<::spu::SampleBuffer>) -> Audio {
        ::sdl2::init(::sdl2::INIT_AUDIO);

        let resampler = Resampler::new(channel, SAMPLE_RATE);

        let async = resampler.async();

        let reader = Reader::new(resampler);

        let spec = AudioSpecDesired {
            freq:     SAMPLE_RATE as i32,
            channels: 1,
            samples:  ::spu::SAMPLES_PER_BUFFER as u16,
            callback: reader,
        };

        let dev =
            match spec.open_audio_device(None, false) {
                Ok(d)  => d,
                Err(e) => panic!("{}", e),
            };

        Audio {
            dev:   dev,
            async: async,
        }
    }

    pub fn start(&self) {
        self.dev.resume();
    }
}

impl ::ui::Audio for Audio {
    fn adjust_resampling(&mut self, in_samples: u32) {
        self.async.adjust_resampling(in_samples);
    }
}

// Use 8bit sound samples
type Sample = u8;

/// Audio output sample rate
const SAMPLE_RATE: u32 = 44_100;
<|endoftext|>