<commit_before>//! Tests for profiles defined in config files.

use cargo_test_support::paths::CargoPathExt;
use cargo_test_support::{basic_lib_manifest, paths, project};

#[cargo_test]
fn profile_config_gated() {
    let p = project()
        .file("Cargo.toml", &basic_lib_manifest("foo"))
        .file("src/lib.rs", "")
        .file(
            ".cargo/config",
            r#"
            [profile.dev]
            debug = 1
        "#,
        )
        .build();

    p.cargo("build -v")
        .with_stderr_contains(
            "\
[WARNING] config profiles require the `-Z config-profile` command-line option \
    (found profile `dev` in [..]/foo/.cargo/config)
",
        )
        .with_stderr_contains("[..]-C debuginfo=2[..]")
        .run();
}

#[cargo_test]
fn named_profile_gated() {
    // Named profile in config requires enabling in Cargo.toml.
    let p = project()
        .file("src/lib.rs", "")
        .file(
            ".cargo/config",
            r#"
            [profile.foo]
            inherits = 'dev'
            opt-level = 1
            "#,
        )
        .build();
    p.cargo("build --profile foo -Zunstable-options -Zconfig-profile")
        .masquerade_as_nightly_cargo()
        .with_stderr(
            "\
[ERROR] config profile `foo` is not valid (defined in `[..]/foo/.cargo/config`)

Caused by:
  feature `named-profiles` is required

consider adding `cargo-features = [\"named-profiles\"]` to the manifest
",
        )
        .with_status(101)
        .run();
}

#[cargo_test]
fn profile_config_validate_warnings() {
    let p = project()
        .file("Cargo.toml", &basic_lib_manifest("foo"))
        .file("src/lib.rs", "")
        .file(
            ".cargo/config",
            r#"
            [profile.test]
            opt-level = 3

            [profile.asdf]
            opt-level = 3

            [profile.dev]
            bad-key = true

            [profile.dev.build-override]
            bad-key-bo = true

            [profile.dev.package.bar]
            bad-key-bar = true
        "#,
        )
        .build();

    p.cargo("build -Z config-profile")
        .masquerade_as_nightly_cargo()
        .with_stderr_unordered(
            "\
[WARNING] unused config key `profile.dev.bad-key` in `[..].cargo/config`
[WARNING] unused config key `profile.dev.package.bar.bad-key-bar` in `[..].cargo/config`
[WARNING] unused config key `profile.dev.build-override.bad-key-bo` in `[..].cargo/config`
[COMPILING] foo [..]
[FINISHED] [..]
",
        )
        .run();
}

#[cargo_test]
fn profile_config_error_paths() {
    // Errors in config show where the error is located.
    let p = project()
        .file("Cargo.toml", &basic_lib_manifest("foo"))
        .file("src/lib.rs", "")
        .file(
            ".cargo/config",
            r#"
            [profile.dev]
            opt-level = 3
        "#,
        )
        .file(
            paths::home().join(".cargo/config"),
            r#"
            [profile.dev]
            rpath = "foo"
            "#,
        )
        .build();

    p.cargo("build -Z config-profile")
        .masquerade_as_nightly_cargo()
        .with_status(101)
        .with_stderr(
            "\
[ERROR] error in [..]/foo/.cargo/config: \
    could not load config key `profile.dev`: \
    error in [..]/home/.cargo/config: \
    `profile.dev.rpath` expected true/false, but found a string
",
        )
        .run();
}

#[cargo_test]
fn profile_config_validate_errors() {
    let p = project()
        .file("Cargo.toml", &basic_lib_manifest("foo"))
        .file("src/lib.rs", "")
        .file(
            ".cargo/config",
            r#"
            [profile.dev.package.foo]
            panic = "abort"
        "#,
        )
        .build();

    p.cargo("build -Z config-profile")
        .masquerade_as_nightly_cargo()
        .with_status(101)
        .with_stderr(
            "\
[ERROR] config profile `dev` is not valid (defined in `[..]/foo/.cargo/config`)

Caused by:
  `panic` may not be specified in a `package` profile
",
        )
        .run();
}

#[cargo_test]
fn profile_config_syntax_errors() {
    let p = project()
        .file("Cargo.toml", &basic_lib_manifest("foo"))
        .file("src/lib.rs", "")
        .file(
            ".cargo/config",
            r#"
            [profile.dev]
            codegen-units = "foo"
        "#,
        )
        .build();

    p.cargo("build -Z config-profile")
        .masquerade_as_nightly_cargo()
        .with_status(101)
        .with_stderr(
            "\
[ERROR] error in [..]/foo/.cargo/config: \
    could not load config key `profile.dev`: \
    error in [..]/foo/.cargo/config: \
    `profile.dev.codegen-units` expected an integer, but found a string
",
        )
        .run();
}

#[cargo_test]
fn profile_config_override_spec_multiple() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.0.1"

            [dependencies]
            bar = { path = "bar" }
            "#,
        )
        .file(
            ".cargo/config",
            r#"
            [profile.dev.package.bar]
            opt-level = 3

            [profile.dev.package."bar:0.5.0"]
            opt-level = 3
        "#,
        )
        .file("src/lib.rs", "")
        .file("bar/Cargo.toml", &basic_lib_manifest("bar"))
        .file("bar/src/lib.rs", "")
        .build();

    // Unfortunately this doesn't tell you which file, hopefully it's not too
    // much of a problem.
    p.cargo("build -v -Z config-profile")
        .masquerade_as_nightly_cargo()
        .with_status(101)
        .with_stderr(
            "\
[ERROR] multiple package overrides in profile `dev` match package `bar v0.5.0 ([..])`
found package specs: bar, bar:0.5.0",
        )
        .run();
}

#[cargo_test]
fn profile_config_all_options() {
    // Ensure all profile options are supported.
    let p = project()
        .file("src/main.rs", "fn main() {}")
        .file(
            ".cargo/config",
            r#"
        [profile.release]
        opt-level = 1
        debug = true
        debug-assertions = true
        overflow-checks = false
        rpath = true
        lto = true
        codegen-units = 2
        panic = "abort"
        incremental = true
        "#,
        )
        .build();

    p.cargo("build --release -v -Z config-profile")
        .masquerade_as_nightly_cargo()
        .env_remove("CARGO_INCREMENTAL")
        .with_stderr(
            "\
[COMPILING] foo [..]
[RUNNING] `rustc --crate-name foo [..] \
            -C opt-level=1 \
            -C panic=abort \
            -C lto \
            -C codegen-units=2 \
            -C debuginfo=2 \
            -C debug-assertions=on \
            -C overflow-checks=off [..]\
            -C rpath [..]\
            -C incremental=[..]
[FINISHED] release [optimized + debuginfo] [..]
",
        )
        .run();
}

#[cargo_test]
fn profile_config_override_precedence() {
    // Config values take precedence over manifest values.
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.0.1"

            [dependencies]
            bar = {path = "bar"}

            [profile.dev]
            codegen-units = 2

            [profile.dev.package.bar]
            opt-level = 3
        "#,
        )
        .file("src/lib.rs", "")
        .file("bar/Cargo.toml", &basic_lib_manifest("bar"))
        .file("bar/src/lib.rs", "")
        .file(
            ".cargo/config",
            r#"
            [profile.dev.package.bar]
            opt-level = 2
        "#,
        )
        .build();

    p.cargo("build -v -Z config-profile")
        .masquerade_as_nightly_cargo()
        .with_stderr(
            "\
[COMPILING] bar [..]
[RUNNING] `rustc --crate-name bar [..] -C opt-level=2 -C codegen-units=2 [..]
[COMPILING] foo [..]
[RUNNING] `rustc --crate-name foo [..]-C codegen-units=2 [..]
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]",
        )
        .run();
}

#[cargo_test]
fn profile_config_no_warn_unknown_override() {
    let p = project()
        .file("Cargo.toml", &basic_lib_manifest("foo"))
        .file("src/lib.rs", "")
        .file(
            ".cargo/config",
            r#"
            [profile.dev.package.bar]
            codegen-units = 4
        "#,
        )
        .build();

    p.cargo("build -Z config-profile")
        .masquerade_as_nightly_cargo()
        .with_stderr_does_not_contain("[..]warning[..]")
        .run();
}

#[cargo_test]
fn profile_config_mixed_types() {
    let p = project()
        .file("Cargo.toml", &basic_lib_manifest("foo"))
        .file("src/lib.rs", "")
        .file(
            ".cargo/config",
            r#"
            [profile.dev]
            opt-level = 3
        "#,
        )
        .file(
            paths::home().join(".cargo/config"),
            r#"
            [profile.dev]
            opt-level = 's'
            "#,
        )
        .build();

    p.cargo("build -v -Z config-profile")
        .masquerade_as_nightly_cargo()
        .with_stderr_contains("[..]-C opt-level=3 [..]")
        .run();
}

#[cargo_test]
fn named_config_profile() {
    // Exercises config named profies.
    // foo -> middle -> bar -> dev
    // middle exists in Cargo.toml, the others in .cargo/config
    use super::config::ConfigBuilder;
    use cargo::core::compiler::CompileMode;
    use cargo::core::enable_nightly_features;
    use cargo::core::features::Features;
    use cargo::core::profiles::{Profiles, UnitFor};
    use cargo::core::{InternedString, PackageId};
    use cargo::util::toml::TomlProfiles;
    use std::fs;
    enable_nightly_features();
    paths::root().join(".cargo").mkdir_p();
    fs::write(
        paths::root().join(".cargo/config"),
        r#"
        [profile.foo]
        inherits = "middle"
        codegen-units = 2
        [profile.foo.build-override]
        codegen-units = 6
        [profile.foo.package.dep]
        codegen-units = 7

        [profile.middle]
        inherits = "bar"
        codegen-units = 3

        [profile.bar]
        inherits = "dev"
        codegen-units = 4
        debug = 1
        "#,
    )
    .unwrap();
    let config = ConfigBuilder::new().unstable_flag("config-profile").build();
    let mut warnings = Vec::new();
    let features = Features::new(&["named-profiles".to_string()], &mut warnings).unwrap();
    assert_eq!(warnings.len(), 0);
    let profile_name = InternedString::new("foo");
    let toml = r#"
        [profile.middle]
        inherits = "bar"
        codegen-units = 1
        opt-level = 1
        [profile.middle.package.dep]
        overflow-checks = false

        [profile.foo.build-override]
        codegen-units = 5
        debug-assertions = false
        [profile.foo.package.dep]
        codegen-units = 8
    "#;
    #[derive(serde::Deserialize)]
    struct TomlManifest {
        profile: Option<TomlProfiles>,
    }
    let manifest: TomlManifest = toml::from_str(toml).unwrap();
    let profiles =
        Profiles::new(manifest.profile.as_ref(), &config, profile_name, &features).unwrap();

    let crates_io = cargo::core::source::SourceId::crates_io(&config).unwrap();
    let a_pkg = PackageId::new("a", "0.1.0", crates_io).unwrap();
    let dep_pkg = PackageId::new("dep", "0.1.0", crates_io).unwrap();

    // normal package
    let p = profiles.get_profile(a_pkg, true, UnitFor::new_normal(), CompileMode::Build);
    assert_eq!(p.name, "foo");
    assert_eq!(p.codegen_units, Some(2)); // "foo" from config
    assert_eq!(p.opt_level, "1"); // "middle" from manifest
    assert_eq!(p.debuginfo, Some(1)); // "bar" from config
    assert_eq!(p.debug_assertions, true); // "dev" built-in (ignore build-override)
    assert_eq!(p.overflow_checks, true); // "dev" built-in (ignore package override)

    // build-override
    let bo = profiles.get_profile(a_pkg, true, UnitFor::new_build(), CompileMode::Build);
    assert_eq!(bo.name, "foo");
    assert_eq!(bo.codegen_units, Some(6)); // "foo" build override from config
    assert_eq!(bo.opt_level, "1"); // SAME as normal
    assert_eq!(bo.debuginfo, Some(1)); // SAME as normal
    assert_eq!(bo.debug_assertions, false); // "foo" build override from manifest
    assert_eq!(bo.overflow_checks, true); // SAME as normal

    // package overrides
    let po = profiles.get_profile(dep_pkg, false, UnitFor::new_normal(), CompileMode::Build);
    assert_eq!(po.name, "foo");
    assert_eq!(po.codegen_units, Some(7)); // "foo" package override from config
    assert_eq!(po.opt_level, "1"); // SAME as normal
    assert_eq!(po.debuginfo, Some(1)); // SAME as normal
    assert_eq!(po.debug_assertions, true); // SAME as normal
    assert_eq!(po.overflow_checks, false); // "middle" package override from manifest
}

#[cargo_test]
fn named_env_profile() {
    // Environment variables used to define a named profile.
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            cargo-features = ["named-profiles"]
            [package]
            name = "foo"
            version = "0.1.0"
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("build -v -Zconfig-profile -Zunstable-options --profile=other")
        .masquerade_as_nightly_cargo()
        .env("CARGO_PROFILE_OTHER_CODEGEN_UNITS", "1")
        .env("CARGO_PROFILE_OTHER_INHERITS", "dev")
        .with_stderr_contains("[..]-C codegen-units=1 [..]")
        .run();
}
<commit_msg>Update tests for formatting changes due to `anyhow` changes.<commit_after>//! Tests for profiles defined in config files.

use cargo_test_support::paths::CargoPathExt;
use cargo_test_support::{basic_lib_manifest, paths, project};

#[cargo_test]
fn profile_config_gated() {
    let p = project()
        .file("Cargo.toml", &basic_lib_manifest("foo"))
        .file("src/lib.rs", "")
        .file(
            ".cargo/config",
            r#"
            [profile.dev]
            debug = 1
        "#,
        )
        .build();

    p.cargo("build -v")
        .with_stderr_contains(
            "\
[WARNING] config profiles require the `-Z config-profile` command-line option \
    (found profile `dev` in [..]/foo/.cargo/config)
",
        )
        .with_stderr_contains("[..]-C debuginfo=2[..]")
        .run();
}

#[cargo_test]
fn named_profile_gated() {
    // Named profile in config requires enabling in Cargo.toml.
    let p = project()
        .file("src/lib.rs", "")
        .file(
            ".cargo/config",
            r#"
            [profile.foo]
            inherits = 'dev'
            opt-level = 1
            "#,
        )
        .build();
    p.cargo("build --profile foo -Zunstable-options -Zconfig-profile")
        .masquerade_as_nightly_cargo()
        .with_stderr(
            "\
[ERROR] config profile `foo` is not valid (defined in `[..]/foo/.cargo/config`)

Caused by:
  feature `named-profiles` is required

consider adding `cargo-features = [\"named-profiles\"]` to the manifest
",
        )
        .with_status(101)
        .run();
}

#[cargo_test]
fn profile_config_validate_warnings() {
    let p = project()
        .file("Cargo.toml", &basic_lib_manifest("foo"))
        .file("src/lib.rs", "")
        .file(
            ".cargo/config",
            r#"
            [profile.test]
            opt-level = 3

            [profile.asdf]
            opt-level = 3

            [profile.dev]
            bad-key = true

            [profile.dev.build-override]
            bad-key-bo = true

            [profile.dev.package.bar]
            bad-key-bar = true
        "#,
        )
        .build();

    p.cargo("build -Z config-profile")
        .masquerade_as_nightly_cargo()
        .with_stderr_unordered(
            "\
[WARNING] unused config key `profile.dev.bad-key` in `[..].cargo/config`
[WARNING] unused config key `profile.dev.package.bar.bad-key-bar` in `[..].cargo/config`
[WARNING] unused config key `profile.dev.build-override.bad-key-bo` in `[..].cargo/config`
[COMPILING] foo [..]
[FINISHED] [..]
",
        )
        .run();
}

#[cargo_test]
fn profile_config_error_paths() {
    // Errors in config show where the error is located.
    let p = project()
        .file("Cargo.toml", &basic_lib_manifest("foo"))
        .file("src/lib.rs", "")
        .file(
            ".cargo/config",
            r#"
            [profile.dev]
            opt-level = 3
        "#,
        )
        .file(
            paths::home().join(".cargo/config"),
            r#"
            [profile.dev]
            rpath = "foo"
            "#,
        )
        .build();

    p.cargo("build -Z config-profile")
        .masquerade_as_nightly_cargo()
        .with_status(101)
        .with_stderr(
            "\
[ERROR] error in [..]/foo/.cargo/config: could not load config key `profile.dev`

Caused by:
  error in [..]/home/.cargo/config: `profile.dev.rpath` expected true/false, but found a string
",
        )
        .run();
}

#[cargo_test]
fn profile_config_validate_errors() {
    let p = project()
        .file("Cargo.toml", &basic_lib_manifest("foo"))
        .file("src/lib.rs", "")
        .file(
            ".cargo/config",
            r#"
            [profile.dev.package.foo]
            panic = "abort"
        "#,
        )
        .build();

    p.cargo("build -Z config-profile")
        .masquerade_as_nightly_cargo()
        .with_status(101)
        .with_stderr(
            "\
[ERROR] config profile `dev` is not valid (defined in `[..]/foo/.cargo/config`)

Caused by:
  `panic` may not be specified in a `package` profile
",
        )
        .run();
}

#[cargo_test]
fn profile_config_syntax_errors() {
    let p = project()
        .file("Cargo.toml", &basic_lib_manifest("foo"))
        .file("src/lib.rs", "")
        .file(
            ".cargo/config",
            r#"
            [profile.dev]
            codegen-units = "foo"
        "#,
        )
        .build();

    p.cargo("build -Z config-profile")
        .masquerade_as_nightly_cargo()
        .with_status(101)
        .with_stderr(
            "\
[ERROR] error in [..]/.cargo/config: could not load config key `profile.dev`

Caused by:
  error in [..]/foo/.cargo/config: `profile.dev.codegen-units` expected an integer, but found a string
",
        )
        .run();
}

#[cargo_test]
fn profile_config_override_spec_multiple() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.0.1"

            [dependencies]
            bar = { path = "bar" }
            "#,
        )
        .file(
            ".cargo/config",
            r#"
            [profile.dev.package.bar]
            opt-level = 3

            [profile.dev.package."bar:0.5.0"]
            opt-level = 3
        "#,
        )
        .file("src/lib.rs", "")
        .file("bar/Cargo.toml", &basic_lib_manifest("bar"))
        .file("bar/src/lib.rs", "")
        .build();

    // Unfortunately this doesn't tell you which file, hopefully it's not too
    // much of a problem.
    p.cargo("build -v -Z config-profile")
        .masquerade_as_nightly_cargo()
        .with_status(101)
        .with_stderr(
            "\
[ERROR] multiple package overrides in profile `dev` match package `bar v0.5.0 ([..])`
found package specs: bar, bar:0.5.0",
        )
        .run();
}

#[cargo_test]
fn profile_config_all_options() {
    // Ensure all profile options are supported.
    let p = project()
        .file("src/main.rs", "fn main() {}")
        .file(
            ".cargo/config",
            r#"
        [profile.release]
        opt-level = 1
        debug = true
        debug-assertions = true
        overflow-checks = false
        rpath = true
        lto = true
        codegen-units = 2
        panic = "abort"
        incremental = true
        "#,
        )
        .build();

    p.cargo("build --release -v -Z config-profile")
        .masquerade_as_nightly_cargo()
        .env_remove("CARGO_INCREMENTAL")
        .with_stderr(
            "\
[COMPILING] foo [..]
[RUNNING] `rustc --crate-name foo [..] \
            -C opt-level=1 \
            -C panic=abort \
            -C lto \
            -C codegen-units=2 \
            -C debuginfo=2 \
            -C debug-assertions=on \
            -C overflow-checks=off [..]\
            -C rpath [..]\
            -C incremental=[..]
[FINISHED] release [optimized + debuginfo] [..]
",
        )
        .run();
}

#[cargo_test]
fn profile_config_override_precedence() {
    // Config values take precedence over manifest values.
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.0.1"

            [dependencies]
            bar = {path = "bar"}

            [profile.dev]
            codegen-units = 2

            [profile.dev.package.bar]
            opt-level = 3
        "#,
        )
        .file("src/lib.rs", "")
        .file("bar/Cargo.toml", &basic_lib_manifest("bar"))
        .file("bar/src/lib.rs", "")
        .file(
            ".cargo/config",
            r#"
            [profile.dev.package.bar]
            opt-level = 2
        "#,
        )
        .build();

    p.cargo("build -v -Z config-profile")
        .masquerade_as_nightly_cargo()
        .with_stderr(
            "\
[COMPILING] bar [..]
[RUNNING] `rustc --crate-name bar [..] -C opt-level=2 -C codegen-units=2 [..]
[COMPILING] foo [..]
[RUNNING] `rustc --crate-name foo [..]-C codegen-units=2 [..]
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]",
        )
        .run();
}

#[cargo_test]
fn profile_config_no_warn_unknown_override() {
    let p = project()
        .file("Cargo.toml", &basic_lib_manifest("foo"))
        .file("src/lib.rs", "")
        .file(
            ".cargo/config",
            r#"
            [profile.dev.package.bar]
            codegen-units = 4
        "#,
        )
        .build();

    p.cargo("build -Z config-profile")
        .masquerade_as_nightly_cargo()
        .with_stderr_does_not_contain("[..]warning[..]")
        .run();
}

#[cargo_test]
fn profile_config_mixed_types() {
    let p = project()
        .file("Cargo.toml", &basic_lib_manifest("foo"))
        .file("src/lib.rs", "")
        .file(
            ".cargo/config",
            r#"
            [profile.dev]
            opt-level = 3
        "#,
        )
        .file(
            paths::home().join(".cargo/config"),
            r#"
            [profile.dev]
            opt-level = 's'
            "#,
        )
        .build();

    p.cargo("build -v -Z config-profile")
        .masquerade_as_nightly_cargo()
        .with_stderr_contains("[..]-C opt-level=3 [..]")
        .run();
}

#[cargo_test]
fn named_config_profile() {
    // Exercises config named profies.
    // foo -> middle -> bar -> dev
    // middle exists in Cargo.toml, the others in .cargo/config
    use super::config::ConfigBuilder;
    use cargo::core::compiler::CompileMode;
    use cargo::core::enable_nightly_features;
    use cargo::core::features::Features;
    use cargo::core::profiles::{Profiles, UnitFor};
    use cargo::core::{InternedString, PackageId};
    use cargo::util::toml::TomlProfiles;
    use std::fs;
    enable_nightly_features();
    paths::root().join(".cargo").mkdir_p();
    fs::write(
        paths::root().join(".cargo/config"),
        r#"
        [profile.foo]
        inherits = "middle"
        codegen-units = 2
        [profile.foo.build-override]
        codegen-units = 6
        [profile.foo.package.dep]
        codegen-units = 7

        [profile.middle]
        inherits = "bar"
        codegen-units = 3

        [profile.bar]
        inherits = "dev"
        codegen-units = 4
        debug = 1
        "#,
    )
    .unwrap();
    let config = ConfigBuilder::new().unstable_flag("config-profile").build();
    let mut warnings = Vec::new();
    let features = Features::new(&["named-profiles".to_string()], &mut warnings).unwrap();
    assert_eq!(warnings.len(), 0);
    let profile_name = InternedString::new("foo");
    let toml = r#"
        [profile.middle]
        inherits = "bar"
        codegen-units = 1
        opt-level = 1
        [profile.middle.package.dep]
        overflow-checks = false

        [profile.foo.build-override]
        codegen-units = 5
        debug-assertions = false
        [profile.foo.package.dep]
        codegen-units = 8
    "#;
    #[derive(serde::Deserialize)]
    struct TomlManifest {
        profile: Option<TomlProfiles>,
    }
    let manifest: TomlManifest = toml::from_str(toml).unwrap();
    let profiles =
        Profiles::new(manifest.profile.as_ref(), &config, profile_name, &features).unwrap();

    let crates_io = cargo::core::source::SourceId::crates_io(&config).unwrap();
    let a_pkg = PackageId::new("a", "0.1.0", crates_io).unwrap();
    let dep_pkg = PackageId::new("dep", "0.1.0", crates_io).unwrap();

    // normal package
    let p = profiles.get_profile(a_pkg, true, UnitFor::new_normal(), CompileMode::Build);
    assert_eq!(p.name, "foo");
    assert_eq!(p.codegen_units, Some(2)); // "foo" from config
    assert_eq!(p.opt_level, "1"); // "middle" from manifest
    assert_eq!(p.debuginfo, Some(1)); // "bar" from config
    assert_eq!(p.debug_assertions, true); // "dev" built-in (ignore build-override)
    assert_eq!(p.overflow_checks, true); // "dev" built-in (ignore package override)

    // build-override
    let bo = profiles.get_profile(a_pkg, true, UnitFor::new_build(), CompileMode::Build);
    assert_eq!(bo.name, "foo");
    assert_eq!(bo.codegen_units, Some(6)); // "foo" build override from config
    assert_eq!(bo.opt_level, "1"); // SAME as normal
    assert_eq!(bo.debuginfo, Some(1)); // SAME as normal
    assert_eq!(bo.debug_assertions, false); // "foo" build override from manifest
    assert_eq!(bo.overflow_checks, true); // SAME as normal

    // package overrides
    let po = profiles.get_profile(dep_pkg, false, UnitFor::new_normal(), CompileMode::Build);
    assert_eq!(po.name, "foo");
    assert_eq!(po.codegen_units, Some(7)); // "foo" package override from config
    assert_eq!(po.opt_level, "1"); // SAME as normal
    assert_eq!(po.debuginfo, Some(1)); // SAME as normal
    assert_eq!(po.debug_assertions, true); // SAME as normal
    assert_eq!(po.overflow_checks, false); // "middle" package override from manifest
}

#[cargo_test]
fn named_env_profile() {
    // Environment variables used to define a named profile.
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            cargo-features = ["named-profiles"]
            [package]
            name = "foo"
            version = "0.1.0"
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("build -v -Zconfig-profile -Zunstable-options --profile=other")
        .masquerade_as_nightly_cargo()
        .env("CARGO_PROFILE_OTHER_CODEGEN_UNITS", "1")
        .env("CARGO_PROFILE_OTHER_INHERITS", "dev")
        .with_stderr_contains("[..]-C codegen-units=1 [..]")
        .run();
}
<|endoftext|>


<commit_before>use super::LoweringContext;

use rustc_ast::*;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_span::{Span, Symbol};
use rustc_target::asm;
use std::collections::hash_map::Entry;
use std::fmt::Write;

impl<'a, 'hir> LoweringContext<'a, 'hir> {
    crate fn lower_inline_asm(&mut self, sp: Span, asm: &InlineAsm) -> &'hir hir::InlineAsm<'hir> {
        // Rustdoc needs to support asm! from foriegn architectures: don't try
        // lowering the register contraints in this case.
        let asm_arch = if self.sess.opts.actually_rustdoc { None } else { self.sess.asm_arch };
        if asm_arch.is_none() && !self.sess.opts.actually_rustdoc {
            struct_span_err!(self.sess, sp, E0472, "inline assembly is unsupported on this target")
                .emit();
        }
        if asm.options.contains(InlineAsmOptions::ATT_SYNTAX)
            && !matches!(asm_arch, Some(asm::InlineAsmArch::X86 | asm::InlineAsmArch::X86_64))
            && !self.sess.opts.actually_rustdoc
        {
            self.sess
                .struct_span_err(sp, "the `att_syntax` option is only supported on x86")
                .emit();
        }

        let mut clobber_abi = None;
        if let Some(asm_arch) = asm_arch {
            if let Some((abi_name, abi_span)) = asm.clobber_abi {
                match asm::InlineAsmClobberAbi::parse(asm_arch, &self.sess.target, abi_name) {
                    Ok(abi) => clobber_abi = Some((abi, abi_span)),
                    Err(&[]) => {
                        self.sess
                            .struct_span_err(
                                abi_span,
                                "`clobber_abi` is not supported on this target",
                            )
                            .emit();
                    }
                    Err(supported_abis) => {
                        let mut err =
                            self.sess.struct_span_err(abi_span, "invalid ABI for `clobber_abi`");
                        let mut abis = format!("`{}`", supported_abis[0]);
                        for m in &supported_abis[1..] {
                            let _ = write!(abis, ", `{}`", m);
                        }
                        err.note(&format!(
                            "the following ABIs are supported on this target: {}",
                            abis
                        ));
                        err.emit();
                    }
                }
            }
        }

        // Lower operands to HIR. We use dummy register classes if an error
        // occurs during lowering because we still need to be able to produce a
        // valid HIR.
        let sess = self.sess;
        let mut operands: Vec<_> = asm
            .operands
            .iter()
            .map(|(op, op_sp)| {
                let lower_reg = |reg| match reg {
                    InlineAsmRegOrRegClass::Reg(s) => {
                        asm::InlineAsmRegOrRegClass::Reg(if let Some(asm_arch) = asm_arch {
                            asm::InlineAsmReg::parse(
                                asm_arch,
                                |feature| sess.target_features.contains(&Symbol::intern(feature)),
                                &sess.target,
                                s,
                            )
                            .unwrap_or_else(|e| {
                                let msg = format!("invalid register `{}`: {}", s.as_str(), e);
                                sess.struct_span_err(*op_sp, &msg).emit();
                                asm::InlineAsmReg::Err
                            })
                        } else {
                            asm::InlineAsmReg::Err
                        })
                    }
                    InlineAsmRegOrRegClass::RegClass(s) => {
                        asm::InlineAsmRegOrRegClass::RegClass(if let Some(asm_arch) = asm_arch {
                            asm::InlineAsmRegClass::parse(asm_arch, s).unwrap_or_else(|e| {
                                let msg = format!("invalid register class `{}`: {}", s.as_str(), e);
                                sess.struct_span_err(*op_sp, &msg).emit();
                                asm::InlineAsmRegClass::Err
                            })
                        } else {
                            asm::InlineAsmRegClass::Err
                        })
                    }
                };

                let op = match *op {
                    InlineAsmOperand::In { reg, ref expr } => hir::InlineAsmOperand::In {
                        reg: lower_reg(reg),
                        expr: self.lower_expr_mut(expr),
                    },
                    InlineAsmOperand::Out { reg, late, ref expr } => hir::InlineAsmOperand::Out {
                        reg: lower_reg(reg),
                        late,
                        expr: expr.as_ref().map(|expr| self.lower_expr_mut(expr)),
                    },
                    InlineAsmOperand::InOut { reg, late, ref expr } => {
                        hir::InlineAsmOperand::InOut {
                            reg: lower_reg(reg),
                            late,
                            expr: self.lower_expr_mut(expr),
                        }
                    }
                    InlineAsmOperand::SplitInOut { reg, late, ref in_expr, ref out_expr } => {
                        hir::InlineAsmOperand::SplitInOut {
                            reg: lower_reg(reg),
                            late,
                            in_expr: self.lower_expr_mut(in_expr),
                            out_expr: out_expr.as_ref().map(|expr| self.lower_expr_mut(expr)),
                        }
                    }
                    InlineAsmOperand::Const { ref anon_const } => hir::InlineAsmOperand::Const {
                        anon_const: self.lower_anon_const(anon_const),
                    },
                    InlineAsmOperand::Sym { ref expr } => {
                        hir::InlineAsmOperand::Sym { expr: self.lower_expr_mut(expr) }
                    }
                };
                (op, self.lower_span(*op_sp))
            })
            .collect();

        // Validate template modifiers against the register classes for the operands
        for p in &asm.template {
            if let InlineAsmTemplatePiece::Placeholder {
                operand_idx,
                modifier: Some(modifier),
                span: placeholder_span,
            } = *p
            {
                let op_sp = asm.operands[operand_idx].1;
                match &operands[operand_idx].0 {
                    hir::InlineAsmOperand::In { reg, .. }
                    | hir::InlineAsmOperand::Out { reg, .. }
                    | hir::InlineAsmOperand::InOut { reg, .. }
                    | hir::InlineAsmOperand::SplitInOut { reg, .. } => {
                        let class = reg.reg_class();
                        if class == asm::InlineAsmRegClass::Err {
                            continue;
                        }
                        let valid_modifiers = class.valid_modifiers(asm_arch.unwrap());
                        if !valid_modifiers.contains(&modifier) {
                            let mut err = sess.struct_span_err(
                                placeholder_span,
                                "invalid asm template modifier for this register class",
                            );
                            err.span_label(placeholder_span, "template modifier");
                            err.span_label(op_sp, "argument");
                            if !valid_modifiers.is_empty() {
                                let mut mods = format!("`{}`", valid_modifiers[0]);
                                for m in &valid_modifiers[1..] {
                                    let _ = write!(mods, ", `{}`", m);
                                }
                                err.note(&format!(
                                    "the `{}` register class supports \
                                     the following template modifiers: {}",
                                    class.name(),
                                    mods
                                ));
                            } else {
                                err.note(&format!(
                                    "the `{}` register class does not support template modifiers",
                                    class.name()
                                ));
                            }
                            err.emit();
                        }
                    }
                    hir::InlineAsmOperand::Const { .. } => {
                        let mut err = sess.struct_span_err(
                            placeholder_span,
                            "asm template modifiers are not allowed for `const` arguments",
                        );
                        err.span_label(placeholder_span, "template modifier");
                        err.span_label(op_sp, "argument");
                        err.emit();
                    }
                    hir::InlineAsmOperand::Sym { .. } => {
                        let mut err = sess.struct_span_err(
                            placeholder_span,
                            "asm template modifiers are not allowed for `sym` arguments",
                        );
                        err.span_label(placeholder_span, "template modifier");
                        err.span_label(op_sp, "argument");
                        err.emit();
                    }
                }
            }
        }

        let mut used_input_regs = FxHashMap::default();
        let mut used_output_regs = FxHashMap::default();

        for (idx, &(ref op, op_sp)) in operands.iter().enumerate() {
            if let Some(reg) = op.reg() {
                let reg_class = reg.reg_class();
                if reg_class == asm::InlineAsmRegClass::Err {
                    continue;
                }

                // Some register classes can only be used as clobbers. This
                // means that we disallow passing a value in/out of the asm and
                // require that the operand name an explicit register, not a
                // register class.
                if reg_class.is_clobber_only(asm_arch.unwrap())
                    && !(op.is_clobber() && matches!(reg, asm::InlineAsmRegOrRegClass::Reg(_)))
                {
                    let msg = format!(
                        "register class `{}` can only be used as a clobber, \
                             not as an input or output",
                        reg_class.name()
                    );
                    sess.struct_span_err(op_sp, &msg).emit();
                    continue;
                }

                // Check for conflicts between explicit register operands.
                if let asm::InlineAsmRegOrRegClass::Reg(reg) = reg {
                    let (input, output) = match op {
                        hir::InlineAsmOperand::In { .. } => (true, false),

                        // Late output do not conflict with inputs, but normal outputs do
                        hir::InlineAsmOperand::Out { late, .. } => (!late, true),

                        hir::InlineAsmOperand::InOut { .. }
                        | hir::InlineAsmOperand::SplitInOut { .. } => (true, true),

                        hir::InlineAsmOperand::Const { .. } | hir::InlineAsmOperand::Sym { .. } => {
                            unreachable!()
                        }
                    };

                    // Flag to output the error only once per operand
                    let mut skip = false;
                    reg.overlapping_regs(|r| {
                        let mut check = |used_regs: &mut FxHashMap<asm::InlineAsmReg, usize>,
                                         input| {
                            match used_regs.entry(r) {
                                Entry::Occupied(o) => {
                                    if skip {
                                        return;
                                    }
                                    skip = true;

                                    let idx2 = *o.get();
                                    let &(ref op2, op_sp2) = &operands[idx2];
                                    let reg2 = match op2.reg() {
                                        Some(asm::InlineAsmRegOrRegClass::Reg(r)) => r,
                                        _ => unreachable!(),
                                    };

                                    let msg = format!(
                                        "register `{}` conflicts with register `{}`",
                                        reg.name(),
                                        reg2.name()
                                    );
                                    let mut err = sess.struct_span_err(op_sp, &msg);
                                    err.span_label(op_sp, &format!("register `{}`", reg.name()));
                                    err.span_label(op_sp2, &format!("register `{}`", reg2.name()));

                                    match (op, op2) {
                                        (
                                            hir::InlineAsmOperand::In { .. },
                                            hir::InlineAsmOperand::Out { late, .. },
                                        )
                                        | (
                                            hir::InlineAsmOperand::Out { late, .. },
                                            hir::InlineAsmOperand::In { .. },
                                        ) => {
                                            assert!(!*late);
                                            let out_op_sp = if input { op_sp2 } else { op_sp };
                                            let msg = "use `lateout` instead of \
                                                       `out` to avoid conflict";
                                            err.span_help(out_op_sp, msg);
                                        }
                                        _ => {}
                                    }

                                    err.emit();
                                }
                                Entry::Vacant(v) => {
                                    v.insert(idx);
                                }
                            }
                        };
                        if input {
                            check(&mut used_input_regs, true);
                        }
                        if output {
                            check(&mut used_output_regs, false);
                        }
                    });
                }
            }
        }

        // If a clobber_abi is specified, add the necessary clobbers to the
        // operands list.
        if let Some((abi, abi_span)) = clobber_abi {
            for &clobber in abi.clobbered_regs() {
                let mut output_used = false;
                clobber.overlapping_regs(|reg| {
                    if used_output_regs.contains_key(&reg) {
                        output_used = true;
                    }
                });

                if !output_used {
                    operands.push((
                        hir::InlineAsmOperand::Out {
                            reg: asm::InlineAsmRegOrRegClass::Reg(clobber),
                            late: true,
                            expr: None,
                        },
                        self.lower_span(abi_span),
                    ));
                }
            }
        }

        let operands = self.arena.alloc_from_iter(operands);
        let template = self.arena.alloc_from_iter(asm.template.iter().cloned());
        let template_strs = self.arena.alloc_from_iter(
            asm.template_strs
                .iter()
                .map(|(sym, snippet, span)| (*sym, *snippet, self.lower_span(*span))),
        );
        let line_spans =
            self.arena.alloc_from_iter(asm.line_spans.iter().map(|span| self.lower_span(*span)));
        let hir_asm =
            hir::InlineAsm { template, template_strs, operands, options: asm.options, line_spans };
        self.arena.alloc(hir_asm)
    }
}
<commit_msg>Fix some typos<commit_after>use super::LoweringContext;

use rustc_ast::*;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_span::{Span, Symbol};
use rustc_target::asm;
use std::collections::hash_map::Entry;
use std::fmt::Write;

impl<'a, 'hir> LoweringContext<'a, 'hir> {
    crate fn lower_inline_asm(&mut self, sp: Span, asm: &InlineAsm) -> &'hir hir::InlineAsm<'hir> {
        // Rustdoc needs to support asm! from foreign architectures: don't try
        // lowering the register constraints in this case.
        let asm_arch = if self.sess.opts.actually_rustdoc { None } else { self.sess.asm_arch };
        if asm_arch.is_none() && !self.sess.opts.actually_rustdoc {
            struct_span_err!(self.sess, sp, E0472, "inline assembly is unsupported on this target")
                .emit();
        }
        if asm.options.contains(InlineAsmOptions::ATT_SYNTAX)
            && !matches!(asm_arch, Some(asm::InlineAsmArch::X86 | asm::InlineAsmArch::X86_64))
            && !self.sess.opts.actually_rustdoc
        {
            self.sess
                .struct_span_err(sp, "the `att_syntax` option is only supported on x86")
                .emit();
        }

        let mut clobber_abi = None;
        if let Some(asm_arch) = asm_arch {
            if let Some((abi_name, abi_span)) = asm.clobber_abi {
                match asm::InlineAsmClobberAbi::parse(asm_arch, &self.sess.target, abi_name) {
                    Ok(abi) => clobber_abi = Some((abi, abi_span)),
                    Err(&[]) => {
                        self.sess
                            .struct_span_err(
                                abi_span,
                                "`clobber_abi` is not supported on this target",
                            )
                            .emit();
                    }
                    Err(supported_abis) => {
                        let mut err =
                            self.sess.struct_span_err(abi_span, "invalid ABI for `clobber_abi`");
                        let mut abis = format!("`{}`", supported_abis[0]);
                        for m in &supported_abis[1..] {
                            let _ = write!(abis, ", `{}`", m);
                        }
                        err.note(&format!(
                            "the following ABIs are supported on this target: {}",
                            abis
                        ));
                        err.emit();
                    }
                }
            }
        }

        // Lower operands to HIR. We use dummy register classes if an error
        // occurs during lowering because we still need to be able to produce a
        // valid HIR.
        let sess = self.sess;
        let mut operands: Vec<_> = asm
            .operands
            .iter()
            .map(|(op, op_sp)| {
                let lower_reg = |reg| match reg {
                    InlineAsmRegOrRegClass::Reg(s) => {
                        asm::InlineAsmRegOrRegClass::Reg(if let Some(asm_arch) = asm_arch {
                            asm::InlineAsmReg::parse(
                                asm_arch,
                                |feature| sess.target_features.contains(&Symbol::intern(feature)),
                                &sess.target,
                                s,
                            )
                            .unwrap_or_else(|e| {
                                let msg = format!("invalid register `{}`: {}", s.as_str(), e);
                                sess.struct_span_err(*op_sp, &msg).emit();
                                asm::InlineAsmReg::Err
                            })
                        } else {
                            asm::InlineAsmReg::Err
                        })
                    }
                    InlineAsmRegOrRegClass::RegClass(s) => {
                        asm::InlineAsmRegOrRegClass::RegClass(if let Some(asm_arch) = asm_arch {
                            asm::InlineAsmRegClass::parse(asm_arch, s).unwrap_or_else(|e| {
                                let msg = format!("invalid register class `{}`: {}", s.as_str(), e);
                                sess.struct_span_err(*op_sp, &msg).emit();
                                asm::InlineAsmRegClass::Err
                            })
                        } else {
                            asm::InlineAsmRegClass::Err
                        })
                    }
                };

                let op = match *op {
                    InlineAsmOperand::In { reg, ref expr } => hir::InlineAsmOperand::In {
                        reg: lower_reg(reg),
                        expr: self.lower_expr_mut(expr),
                    },
                    InlineAsmOperand::Out { reg, late, ref expr } => hir::InlineAsmOperand::Out {
                        reg: lower_reg(reg),
                        late,
                        expr: expr.as_ref().map(|expr| self.lower_expr_mut(expr)),
                    },
                    InlineAsmOperand::InOut { reg, late, ref expr } => {
                        hir::InlineAsmOperand::InOut {
                            reg: lower_reg(reg),
                            late,
                            expr: self.lower_expr_mut(expr),
                        }
                    }
                    InlineAsmOperand::SplitInOut { reg, late, ref in_expr, ref out_expr } => {
                        hir::InlineAsmOperand::SplitInOut {
                            reg: lower_reg(reg),
                            late,
                            in_expr: self.lower_expr_mut(in_expr),
                            out_expr: out_expr.as_ref().map(|expr| self.lower_expr_mut(expr)),
                        }
                    }
                    InlineAsmOperand::Const { ref anon_const } => hir::InlineAsmOperand::Const {
                        anon_const: self.lower_anon_const(anon_const),
                    },
                    InlineAsmOperand::Sym { ref expr } => {
                        hir::InlineAsmOperand::Sym { expr: self.lower_expr_mut(expr) }
                    }
                };
                (op, self.lower_span(*op_sp))
            })
            .collect();

        // Validate template modifiers against the register classes for the operands
        for p in &asm.template {
            if let InlineAsmTemplatePiece::Placeholder {
                operand_idx,
                modifier: Some(modifier),
                span: placeholder_span,
            } = *p
            {
                let op_sp = asm.operands[operand_idx].1;
                match &operands[operand_idx].0 {
                    hir::InlineAsmOperand::In { reg, .. }
                    | hir::InlineAsmOperand::Out { reg, .. }
                    | hir::InlineAsmOperand::InOut { reg, .. }
                    | hir::InlineAsmOperand::SplitInOut { reg, .. } => {
                        let class = reg.reg_class();
                        if class == asm::InlineAsmRegClass::Err {
                            continue;
                        }
                        let valid_modifiers = class.valid_modifiers(asm_arch.unwrap());
                        if !valid_modifiers.contains(&modifier) {
                            let mut err = sess.struct_span_err(
                                placeholder_span,
                                "invalid asm template modifier for this register class",
                            );
                            err.span_label(placeholder_span, "template modifier");
                            err.span_label(op_sp, "argument");
                            if !valid_modifiers.is_empty() {
                                let mut mods = format!("`{}`", valid_modifiers[0]);
                                for m in &valid_modifiers[1..] {
                                    let _ = write!(mods, ", `{}`", m);
                                }
                                err.note(&format!(
                                    "the `{}` register class supports \
                                     the following template modifiers: {}",
                                    class.name(),
                                    mods
                                ));
                            } else {
                                err.note(&format!(
                                    "the `{}` register class does not support template modifiers",
                                    class.name()
                                ));
                            }
                            err.emit();
                        }
                    }
                    hir::InlineAsmOperand::Const { .. } => {
                        let mut err = sess.struct_span_err(
                            placeholder_span,
                            "asm template modifiers are not allowed for `const` arguments",
                        );
                        err.span_label(placeholder_span, "template modifier");
                        err.span_label(op_sp, "argument");
                        err.emit();
                    }
                    hir::InlineAsmOperand::Sym { .. } => {
                        let mut err = sess.struct_span_err(
                            placeholder_span,
                            "asm template modifiers are not allowed for `sym` arguments",
                        );
                        err.span_label(placeholder_span, "template modifier");
                        err.span_label(op_sp, "argument");
                        err.emit();
                    }
                }
            }
        }

        let mut used_input_regs = FxHashMap::default();
        let mut used_output_regs = FxHashMap::default();

        for (idx, &(ref op, op_sp)) in operands.iter().enumerate() {
            if let Some(reg) = op.reg() {
                let reg_class = reg.reg_class();
                if reg_class == asm::InlineAsmRegClass::Err {
                    continue;
                }

                // Some register classes can only be used as clobbers. This
                // means that we disallow passing a value in/out of the asm and
                // require that the operand name an explicit register, not a
                // register class.
                if reg_class.is_clobber_only(asm_arch.unwrap())
                    && !(op.is_clobber() && matches!(reg, asm::InlineAsmRegOrRegClass::Reg(_)))
                {
                    let msg = format!(
                        "register class `{}` can only be used as a clobber, \
                             not as an input or output",
                        reg_class.name()
                    );
                    sess.struct_span_err(op_sp, &msg).emit();
                    continue;
                }

                // Check for conflicts between explicit register operands.
                if let asm::InlineAsmRegOrRegClass::Reg(reg) = reg {
                    let (input, output) = match op {
                        hir::InlineAsmOperand::In { .. } => (true, false),

                        // Late output do not conflict with inputs, but normal outputs do
                        hir::InlineAsmOperand::Out { late, .. } => (!late, true),

                        hir::InlineAsmOperand::InOut { .. }
                        | hir::InlineAsmOperand::SplitInOut { .. } => (true, true),

                        hir::InlineAsmOperand::Const { .. } | hir::InlineAsmOperand::Sym { .. } => {
                            unreachable!()
                        }
                    };

                    // Flag to output the error only once per operand
                    let mut skip = false;
                    reg.overlapping_regs(|r| {
                        let mut check = |used_regs: &mut FxHashMap<asm::InlineAsmReg, usize>,
                                         input| {
                            match used_regs.entry(r) {
                                Entry::Occupied(o) => {
                                    if skip {
                                        return;
                                    }
                                    skip = true;

                                    let idx2 = *o.get();
                                    let &(ref op2, op_sp2) = &operands[idx2];
                                    let reg2 = match op2.reg() {
                                        Some(asm::InlineAsmRegOrRegClass::Reg(r)) => r,
                                        _ => unreachable!(),
                                    };

                                    let msg = format!(
                                        "register `{}` conflicts with register `{}`",
                                        reg.name(),
                                        reg2.name()
                                    );
                                    let mut err = sess.struct_span_err(op_sp, &msg);
                                    err.span_label(op_sp, &format!("register `{}`", reg.name()));
                                    err.span_label(op_sp2, &format!("register `{}`", reg2.name()));

                                    match (op, op2) {
                                        (
                                            hir::InlineAsmOperand::In { .. },
                                            hir::InlineAsmOperand::Out { late, .. },
                                        )
                                        | (
                                            hir::InlineAsmOperand::Out { late, .. },
                                            hir::InlineAsmOperand::In { .. },
                                        ) => {
                                            assert!(!*late);
                                            let out_op_sp = if input { op_sp2 } else { op_sp };
                                            let msg = "use `lateout` instead of \
                                                       `out` to avoid conflict";
                                            err.span_help(out_op_sp, msg);
                                        }
                                        _ => {}
                                    }

                                    err.emit();
                                }
                                Entry::Vacant(v) => {
                                    v.insert(idx);
                                }
                            }
                        };
                        if input {
                            check(&mut used_input_regs, true);
                        }
                        if output {
                            check(&mut used_output_regs, false);
                        }
                    });
                }
            }
        }

        // If a clobber_abi is specified, add the necessary clobbers to the
        // operands list.
        if let Some((abi, abi_span)) = clobber_abi {
            for &clobber in abi.clobbered_regs() {
                let mut output_used = false;
                clobber.overlapping_regs(|reg| {
                    if used_output_regs.contains_key(&reg) {
                        output_used = true;
                    }
                });

                if !output_used {
                    operands.push((
                        hir::InlineAsmOperand::Out {
                            reg: asm::InlineAsmRegOrRegClass::Reg(clobber),
                            late: true,
                            expr: None,
                        },
                        self.lower_span(abi_span),
                    ));
                }
            }
        }

        let operands = self.arena.alloc_from_iter(operands);
        let template = self.arena.alloc_from_iter(asm.template.iter().cloned());
        let template_strs = self.arena.alloc_from_iter(
            asm.template_strs
                .iter()
                .map(|(sym, snippet, span)| (*sym, *snippet, self.lower_span(*span))),
        );
        let line_spans =
            self.arena.alloc_from_iter(asm.line_spans.iter().map(|span| self.lower_span(*span)));
        let hir_asm =
            hir::InlineAsm { template, template_strs, operands, options: asm.options, line_spans };
        self.arena.alloc(hir_asm)
    }
}
<|endoftext|>


<commit_before>use flowgger::config::Config;
use flowgger::decoder::Decoder;
use flowgger::encoder::Encoder;
use flate2::{Decompress, Flush, Status};
use std::io::{stderr, Write};
use std::net::UdpSocket;
use std::str;
use std::sync::mpsc::SyncSender;
use super::Input;

const DEFAULT_LISTEN: &'static str = "0.0.0.0:514";
const MAX_UDP_PACKET_SIZE: usize = 65527;
const MAX_COMPRESSION_RATIO: usize = 5;

pub struct UdpInput {
    listen: String,
}

impl UdpInput {
    pub fn new(config: &Config) -> UdpInput {
        let listen = config.lookup("input.listen")
            .map_or(DEFAULT_LISTEN,
                    |x| x.as_str().expect("input.listen must be an ip:port string"))
            .to_owned();
        UdpInput { listen: listen }
    }
}

impl Input for UdpInput {
    fn accept(&self,
              tx: SyncSender<Vec<u8>>,
              decoder: Box<Decoder + Send>,
              encoder: Box<Encoder + Send>) {
        let socket = UdpSocket::bind(&self.listen as &str)
            .expect(&format!("Unable to listen to {}", self.listen));
        let tx = tx.clone();
        let (decoder, encoder): (Box<Decoder>, Box<Encoder>) = (decoder.clone_boxed(),
                                                                encoder.clone_boxed());
        let mut buf = [0; MAX_UDP_PACKET_SIZE];
        loop {
            let (length, _src) = match socket.recv_from(&mut buf) {
                Ok(res) => res,
                Err(_) => continue,
            };
            let line = &buf[..length];
            if let Err(e) = handle_record_maybe_compressed(&line, &tx, &decoder, &encoder) {
                let _ = writeln!(stderr(), "{}", e);
            }
        }
    }
}

fn handle_record_maybe_compressed(line: &[u8],
                                  tx: &SyncSender<Vec<u8>>,
                                  decoder: &Box<Decoder>,
                                  encoder: &Box<Encoder>)
                                  -> Result<(), &'static str> {
    if line.len() > 2 && line[0] == 0x78 &&
       (line[1] == 0x01 || line[1] == 0x9c || line[1] == 0xda) {
        let mut decompressed = Vec::with_capacity(MAX_UDP_PACKET_SIZE * MAX_COMPRESSION_RATIO);
        match Decompress::new(true).decompress_vec(line, &mut decompressed, Flush::Finish) {
            Ok(Status::Ok) => handle_record(&decompressed, tx, decoder, encoder),
            _ => return Err("Corrupted compressed record"),
        }
    } else {
        handle_record(line, tx, decoder, encoder)
    }
}

fn handle_record(line: &[u8],
                 tx: &SyncSender<Vec<u8>>,
                 decoder: &Box<Decoder>,
                 encoder: &Box<Encoder>)
                 -> Result<(), &'static str> {
    let line = match str::from_utf8(line) {
        Err(_) => return Err("Invalid UTF-8 input"),
        Ok(line) => line,
    };
    let decoded = try!(decoder.decode(line));
    let reencoded = try!(encoder.encode(decoded));
    tx.send(reencoded).unwrap();
    Ok(())
}
<commit_msg>Accept `Status::StreamEnd` as a valid return code from flate2<commit_after>use flowgger::config::Config;
use flowgger::decoder::Decoder;
use flowgger::encoder::Encoder;
use flate2::{Decompress, Flush, Status};
use std::io::{stderr, Write};
use std::net::UdpSocket;
use std::str;
use std::sync::mpsc::SyncSender;
use super::Input;

const DEFAULT_LISTEN: &'static str = "0.0.0.0:514";
const MAX_UDP_PACKET_SIZE: usize = 65527;
const MAX_COMPRESSION_RATIO: usize = 5;

pub struct UdpInput {
    listen: String,
}

impl UdpInput {
    pub fn new(config: &Config) -> UdpInput {
        let listen = config.lookup("input.listen")
            .map_or(DEFAULT_LISTEN,
                    |x| x.as_str().expect("input.listen must be an ip:port string"))
            .to_owned();
        UdpInput { listen: listen }
    }
}

impl Input for UdpInput {
    fn accept(&self,
              tx: SyncSender<Vec<u8>>,
              decoder: Box<Decoder + Send>,
              encoder: Box<Encoder + Send>) {
        let socket = UdpSocket::bind(&self.listen as &str)
            .expect(&format!("Unable to listen to {}", self.listen));
        let tx = tx.clone();
        let (decoder, encoder): (Box<Decoder>, Box<Encoder>) = (decoder.clone_boxed(),
                                                                encoder.clone_boxed());
        let mut buf = [0; MAX_UDP_PACKET_SIZE];
        loop {
            let (length, _src) = match socket.recv_from(&mut buf) {
                Ok(res) => res,
                Err(_) => continue,
            };
            let line = &buf[..length];
            if let Err(e) = handle_record_maybe_compressed(&line, &tx, &decoder, &encoder) {
                let _ = writeln!(stderr(), "{}", e);
            }
        }
    }
}

fn handle_record_maybe_compressed(line: &[u8],
                                  tx: &SyncSender<Vec<u8>>,
                                  decoder: &Box<Decoder>,
                                  encoder: &Box<Encoder>)
                                  -> Result<(), &'static str> {
    if line.len() > 2 && line[0] == 0x78 &&
       (line[1] == 0x01 || line[1] == 0x9c || line[1] == 0xda) {
        let mut decompressed = Vec::with_capacity(MAX_UDP_PACKET_SIZE * MAX_COMPRESSION_RATIO);
        match Decompress::new(true).decompress_vec(line, &mut decompressed, Flush::Finish) {
            Ok(Status::Ok) |
            Ok(Status::StreamEnd) => handle_record(&decompressed, tx, decoder, encoder),
            _ => return Err("Corrupted compressed record"),
        }
    } else {
        handle_record(line, tx, decoder, encoder)
    }
}

fn handle_record(line: &[u8],
                 tx: &SyncSender<Vec<u8>>,
                 decoder: &Box<Decoder>,
                 encoder: &Box<Encoder>)
                 -> Result<(), &'static str> {
    let line = match str::from_utf8(line) {
        Err(_) => return Err("Invalid UTF-8 input"),
        Ok(line) => line,
    };
    let decoded = try!(decoder.decode(line));
    let reencoded = try!(encoder.encode(decoded));
    tx.send(reencoded).unwrap();
    Ok(())
}
<|endoftext|>


<commit_before>// Copyright 2017 The Exonum Team
//
// 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::net::SocketAddr;
use std::collections::HashMap;

use crypto::PublicKey;
use router::Router;
use iron::prelude::*;

use params::{Params, Value as ParamsValue};
use node::{NodeChannel, ApiSender};
use blockchain::{Service, Blockchain, SharedNodeState};
use api::{Api, ApiError};
use messages::{TEST_NETWORK_ID, PROTOCOL_MAJOR_VERSION};

#[derive(Serialize, Clone, Debug)]
struct ServiceInfo {
    name: String,
    id: u16,
}

/// `DTO` is used to transfer information about node.
#[derive(Serialize, Clone, Debug)]
pub struct NodeInfo {
    network_id: u8,
    protocol_version: u8,
    services: Vec<ServiceInfo>,
}

impl NodeInfo {
    /// Creates new `NodeInfo`, from services list.
    pub fn new<'a, I>(services: I) -> NodeInfo
    where
        I: IntoIterator<Item = &'a Box<Service>>,
    {
        NodeInfo {
            network_id: TEST_NETWORK_ID,
            protocol_version: PROTOCOL_MAJOR_VERSION,
            services: services
                .into_iter()
                .map(|s| {
                    ServiceInfo {
                        name: s.service_name().to_owned(),
                        id: s.service_id(),
                    }
                })
                .collect(),
        }
    }
}

#[derive(Serialize, Default)]
struct ReconnectInfo {
    delay: u64
}

#[derive(Serialize)]
enum IncommingConnectionState {
    Active,
    Reconnect(ReconnectInfo),
}

impl Default for IncommingConnectionState {
    fn default() -> IncommingConnectionState {
        IncommingConnectionState::Active
    }
}

#[derive(Serialize, Default)]
struct IncommingConnection {
    public_key: Option<PublicKey>,
    state: IncommingConnectionState
}

#[derive(Serialize)]
struct PeersInfo {
    incoming_connections: HashMap<SocketAddr, IncommingConnection>,
    outgoing_connections: Vec<SocketAddr>,
}

/// Private system API.
#[derive(Clone, Debug)]
pub struct SystemApi {
    blockchain: Blockchain,
    info: NodeInfo,
    shared_api_state: SharedNodeState,
    node_channel: ApiSender<NodeChannel>,
}

impl SystemApi {
    /// Creates a new `public::SystemApi` instance.
    pub fn new(
        info: NodeInfo,
        blockchain: Blockchain,
        shared_api_state: SharedNodeState,
        node_channel: ApiSender<NodeChannel>,
    ) -> SystemApi {
        SystemApi {
            info,
            blockchain,
            node_channel,
            shared_api_state,
        }
    }

    fn get_peers_info(&self) -> PeersInfo {
        let mut incoming_connections: HashMap<SocketAddr, IncommingConnection>
                = HashMap::new();

        for socket in self.shared_api_state.incoming_connections(){
            incoming_connections.insert(socket, Default::default());
        }

        for (s, delay) in self.shared_api_state
                          .reconnects_timeout(){
            incoming_connections.entry(s)
                                .or_insert(Default::default())
                                .state = IncommingConnectionState::Reconnect(ReconnectInfo{delay});
        }

        for (s, p) in self.shared_api_state
                          .peers_info(){
            incoming_connections.entry(s)
                                .or_insert(Default::default())
                                .public_key = Some(p);
        }

        PeersInfo {
            incoming_connections,
            outgoing_connections: self.shared_api_state.outgoing_connections(),
        }
    }

    fn get_network_info(&self) -> NodeInfo {
        self.info.clone()
    }

    fn peer_add(&self, ip_str: &str) -> Result<(), ApiError> {
        let addr: SocketAddr = ip_str.parse()?;
        self.node_channel.peer_add(addr)?;
        Ok(())
    }
}

impl Api for SystemApi {
    fn wire(&self, router: &mut Router) {

        let _self = self.clone();
        let peer_add = move |req: &mut Request| -> IronResult<Response> {
            let map = req.get_ref::<Params>().unwrap();
            match map.find(&["ip"]) {
                Some(&ParamsValue::String(ref ip_str)) => {
                    _self.peer_add(ip_str)?;
                    _self.ok_response(&::serde_json::to_value("Ok").unwrap())
                }
                _ => {
                    Err(ApiError::IncorrectRequest(
                        "Required parameter of peer 'ip' is missing".into(),
                    ))?
                }
            }
        };

        let _self = self.clone();
        let peers_info = move |_: &mut Request| -> IronResult<Response> {
            let info = _self.get_peers_info();
            _self.ok_response(&::serde_json::to_value(info).unwrap())
        };

        let _self = self.clone();
        let network = move |_: &mut Request| -> IronResult<Response> {
            let info = _self.get_network_info();
            _self.ok_response(&::serde_json::to_value(info).unwrap())
        };

        router.get("/v1/peers", peers_info, "peers_info");
        router.post("/v1/peers", peer_add, "peer_add");
        router.get("/v1/network", network, "network_info");
    }
}
<commit_msg>fix info about outgoing connections<commit_after>// Copyright 2017 The Exonum Team
//
// 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::net::SocketAddr;
use std::collections::HashMap;

use crypto::PublicKey;
use router::Router;
use iron::prelude::*;

use params::{Params, Value as ParamsValue};
use node::{NodeChannel, ApiSender};
use blockchain::{Service, Blockchain, SharedNodeState};
use api::{Api, ApiError};
use messages::{TEST_NETWORK_ID, PROTOCOL_MAJOR_VERSION};

#[derive(Serialize, Clone, Debug)]
struct ServiceInfo {
    name: String,
    id: u16,
}

/// `DTO` is used to transfer information about node.
#[derive(Serialize, Clone, Debug)]
pub struct NodeInfo {
    network_id: u8,
    protocol_version: u8,
    services: Vec<ServiceInfo>,
}

impl NodeInfo {
    /// Creates new `NodeInfo`, from services list.
    pub fn new<'a, I>(services: I) -> NodeInfo
    where
        I: IntoIterator<Item = &'a Box<Service>>,
    {
        NodeInfo {
            network_id: TEST_NETWORK_ID,
            protocol_version: PROTOCOL_MAJOR_VERSION,
            services: services
                .into_iter()
                .map(|s| {
                    ServiceInfo {
                        name: s.service_name().to_owned(),
                        id: s.service_id(),
                    }
                })
                .collect(),
        }
    }
}

#[derive(Serialize, Default)]
struct ReconnectInfo {
    delay: u64
}

#[derive(Serialize)]
enum IncommingConnectionState {
    Active,
    Reconnect(ReconnectInfo),
}

impl Default for IncommingConnectionState {
    fn default() -> IncommingConnectionState {
        IncommingConnectionState::Active
    }
}

#[derive(Serialize, Default)]
struct IncommingConnection {
    public_key: Option<PublicKey>,
    state: IncommingConnectionState
}

#[derive(Serialize)]
struct PeersInfo {
    incoming_connections: Vec<SocketAddr>,
    outgoing_connections: HashMap<SocketAddr, IncommingConnection>,
}

/// Private system API.
#[derive(Clone, Debug)]
pub struct SystemApi {
    blockchain: Blockchain,
    info: NodeInfo,
    shared_api_state: SharedNodeState,
    node_channel: ApiSender<NodeChannel>,
}

impl SystemApi {
    /// Creates a new `public::SystemApi` instance.
    pub fn new(
        info: NodeInfo,
        blockchain: Blockchain,
        shared_api_state: SharedNodeState,
        node_channel: ApiSender<NodeChannel>,
    ) -> SystemApi {
        SystemApi {
            info,
            blockchain,
            node_channel,
            shared_api_state,
        }
    }

    fn get_peers_info(&self) -> PeersInfo {
        let mut outgoing_connections: HashMap<SocketAddr, IncommingConnection>
                = HashMap::new();

        for socket in self.shared_api_state.outgoing_connections(){
            outgoing_connections.insert(socket, Default::default());
        }

        for (s, delay) in self.shared_api_state
                          .reconnects_timeout(){
            outgoing_connections.entry(s)
                                .or_insert(Default::default())
                                .state = IncommingConnectionState::Reconnect(ReconnectInfo{delay});
        }

        for (s, p) in self.shared_api_state
                          .peers_info(){
            outgoing_connections.entry(s)
                                .or_insert(Default::default())
                                .public_key = Some(p);
        }

        PeersInfo {
            incoming_connections: self.shared_api_state.incoming_connections(),
            outgoing_connections,
        }
    }

    fn get_network_info(&self) -> NodeInfo {
        self.info.clone()
    }

    fn peer_add(&self, ip_str: &str) -> Result<(), ApiError> {
        let addr: SocketAddr = ip_str.parse()?;
        self.node_channel.peer_add(addr)?;
        Ok(())
    }
}

impl Api for SystemApi {
    fn wire(&self, router: &mut Router) {

        let _self = self.clone();
        let peer_add = move |req: &mut Request| -> IronResult<Response> {
            let map = req.get_ref::<Params>().unwrap();
            match map.find(&["ip"]) {
                Some(&ParamsValue::String(ref ip_str)) => {
                    _self.peer_add(ip_str)?;
                    _self.ok_response(&::serde_json::to_value("Ok").unwrap())
                }
                _ => {
                    Err(ApiError::IncorrectRequest(
                        "Required parameter of peer 'ip' is missing".into(),
                    ))?
                }
            }
        };

        let _self = self.clone();
        let peers_info = move |_: &mut Request| -> IronResult<Response> {
            let info = _self.get_peers_info();
            _self.ok_response(&::serde_json::to_value(info).unwrap())
        };

        let _self = self.clone();
        let network = move |_: &mut Request| -> IronResult<Response> {
            let info = _self.get_network_info();
            _self.ok_response(&::serde_json::to_value(info).unwrap())
        };

        router.get("/v1/peers", peers_info, "peers_info");
        router.post("/v1/peers", peer_add, "peer_add");
        router.get("/v1/network", network, "network_info");
    }
}
<|endoftext|>


<commit_before><commit_msg>Fix name of table for locations<commit_after><|endoftext|>


<commit_before>use actix::prelude::*;
use godcoin::prelude::*;

mod common;

pub use common::*;

#[test]
fn fresh_blockchain() {
    System::run(|| {
        let minter = TestMinter::new();
        let chain = minter.chain();
        assert!(chain.get_block(0).is_some());
        assert_eq!(chain.get_chain_height(), 0);

        let owner = chain.get_owner();
        assert_eq!(owner.minter, minter.genesis_info().minter_key.0);
        assert_eq!(
            owner.script,
            script::Builder::new().push(OpFrame::False).build()
        );
        assert_eq!(owner.wallet, (&minter.genesis_info().script).into());

        assert!(chain.get_block(1).is_none());
        System::current().stop();
    })
    .unwrap();
}

#[test]
fn mint_tx_verification() {
    System::run(|| {
        let minter = TestMinter::new();
        let chain = minter.chain();
        let config = VerifyConfig::strict();

        let mut tx = MintTx {
            base: create_tx(TxType::MINT, "0 GOLD"),
            to: (&minter.genesis_info().script).into(),
            amount: Balance::default(),
            script: minter.genesis_info().script.clone(),
        };

        tx.append_sign(&minter.genesis_info().wallet_keys[0]);
        tx.append_sign(&minter.genesis_info().wallet_keys[3]);

        let tx = TxVariant::MintTx(tx);
        assert!(chain.verify_tx(&tx, &[], config).is_ok());

        System::current().stop();
    })
    .unwrap();
}

#[test]
fn mint_tx_updates_balances() {
    System::run(|| {
        let minter = TestMinter::new();

        let mut tx = MintTx {
            base: create_tx(TxType::MINT, "0 GOLD"),
            to: (&minter.genesis_info().script).into(),
            amount: get_balance("10.0 GOLD", "1000 SILVER"),
            script: minter.genesis_info().script.clone(),
        };

        tx.append_sign(&minter.genesis_info().wallet_keys[0]);
        tx.append_sign(&minter.genesis_info().wallet_keys[1]);

        let tx = TxVariant::MintTx(tx);
        let fut = minter.request(MsgRequest::Broadcast(tx));
        System::current().arbiter().send(
            fut.then(move |res| {
                let res = res.unwrap();
                assert!(!res.is_err(), format!("{:?}", res));

                minter.produce_block().map(|_| minter)
            })
            .then(|res| {
                let minter = res.unwrap();
                let chain = minter.chain();
                let props = chain.get_properties();
                let expected_bal = get_balance("10 GOLD", "1000 SILVER");
                assert_eq!(props.token_supply, expected_bal);

                let bal = chain.get_balance(&(&minter.genesis_info().script).into());
                assert_eq!(bal, expected_bal);

                System::current().stop();
                Ok(())
            }),
        );
    })
    .unwrap();
}
<commit_msg>Add fee test to mint tx<commit_after>use actix::prelude::*;
use godcoin::prelude::*;

mod common;

pub use common::*;

#[test]
fn fresh_blockchain() {
    System::run(|| {
        let minter = TestMinter::new();
        let chain = minter.chain();
        assert!(chain.get_block(0).is_some());
        assert_eq!(chain.get_chain_height(), 0);

        let owner = chain.get_owner();
        assert_eq!(owner.minter, minter.genesis_info().minter_key.0);
        assert_eq!(
            owner.script,
            script::Builder::new().push(OpFrame::False).build()
        );
        assert_eq!(owner.wallet, (&minter.genesis_info().script).into());

        assert!(chain.get_block(1).is_none());
        System::current().stop();
    })
    .unwrap();
}

#[test]
fn mint_tx_verification() {
    System::run(|| {
        let minter = TestMinter::new();
        let chain = minter.chain();
        let config = VerifyConfig::strict();

        let mut tx = MintTx {
            base: create_tx(TxType::MINT, "0 GOLD"),
            to: (&minter.genesis_info().script).into(),
            amount: Balance::default(),
            script: minter.genesis_info().script.clone(),
        };

        tx.append_sign(&minter.genesis_info().wallet_keys[0]);
        tx.append_sign(&minter.genesis_info().wallet_keys[3]);

        let mut tx = TxVariant::MintTx(tx);
        assert!(chain.verify_tx(&tx, &[], config).is_ok());

        tx.fee = "1 GOLD".parse().unwrap();
        assert!(chain.verify_tx(&tx, &[], config).is_err());

        System::current().stop();
    })
    .unwrap();
}

#[test]
fn mint_tx_updates_balances() {
    System::run(|| {
        let minter = TestMinter::new();

        let mut tx = MintTx {
            base: create_tx(TxType::MINT, "0 GOLD"),
            to: (&minter.genesis_info().script).into(),
            amount: get_balance("10.0 GOLD", "1000 SILVER"),
            script: minter.genesis_info().script.clone(),
        };

        tx.append_sign(&minter.genesis_info().wallet_keys[0]);
        tx.append_sign(&minter.genesis_info().wallet_keys[1]);

        let tx = TxVariant::MintTx(tx);
        let fut = minter.request(MsgRequest::Broadcast(tx));
        System::current().arbiter().send(
            fut.then(move |res| {
                let res = res.unwrap();
                assert!(!res.is_err(), format!("{:?}", res));

                minter.produce_block().map(|_| minter)
            })
            .then(|res| {
                let minter = res.unwrap();
                let chain = minter.chain();
                let props = chain.get_properties();
                let expected_bal = get_balance("10 GOLD", "1000 SILVER");
                assert_eq!(props.token_supply, expected_bal);

                let bal = chain.get_balance(&(&minter.genesis_info().script).into());
                assert_eq!(bal, expected_bal);

                System::current().stop();
                Ok(())
            }),
        );
    })
    .unwrap();
}
<|endoftext|>


<commit_before>use crate::faker::internet::raw::*;
use crate::faker::lorem::raw::Word;
use crate::faker::name::raw::FirstName;
use crate::locales::{Data, EN};
use crate::{Dummy, Fake, Faker};
use rand::distributions::{Distribution, Uniform};
use rand::seq::SliceRandom;
use rand::Rng;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};

impl<L: Data> Dummy<FreeEmailProvider<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &FreeEmailProvider<L>, rng: &mut R) -> Self {
        let s = *L::INTERNET_FREE_EMAIL_PROVIDER.choose(rng).unwrap();
        s.into()
    }
}

impl<L: Data> Dummy<FreeEmailProvider<L>> for &str {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &FreeEmailProvider<L>, rng: &mut R) -> Self {
        let s = *L::INTERNET_FREE_EMAIL_PROVIDER.choose(rng).unwrap();
        s
    }
}

impl<L: Data> Dummy<DomainSuffix<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &DomainSuffix<L>, rng: &mut R) -> Self {
        let s = *L::INTERNET_DOMAIN_SUFFIX.choose(rng).unwrap();
        s.into()
    }
}

impl<L: Data> Dummy<DomainSuffix<L>> for &str {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &DomainSuffix<L>, rng: &mut R) -> Self {
        let s = *L::INTERNET_DOMAIN_SUFFIX.choose(rng).unwrap();
        s
    }
}

impl<L: Data + Copy> Dummy<FreeEmail<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(c: &FreeEmail<L>, rng: &mut R) -> Self {
        let username: String = Username(c.0).fake_with_rng(rng);
        let provider: String = FreeEmailProvider(c.0).fake_with_rng(rng);
        format!("{}@{}", username, provider)
    }
}

impl<L: Data + Copy> Dummy<SafeEmail<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &SafeEmail<L>, rng: &mut R) -> Self {
        let username: String = FirstName(EN).fake_with_rng::<&str, _>(rng).to_lowercase();
        let domain = ["com", "net", "org"].choose(rng).unwrap();
        format!("{}@example.{}", username, domain)
    }
}

impl<L: Data> Dummy<Username<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &Username<L>, rng: &mut R) -> Self {
        match Faker.fake_with_rng::<u8, _>(rng) {
            0 => FirstName(EN).fake_with_rng::<&str, _>(rng).to_lowercase(),
            1 | 2 => format!(
                "{}.{}",
                Word(EN).fake_with_rng::<&str, _>(rng),
                FirstName(EN).fake_with_rng::<&str, _>(rng).to_lowercase()
            ),
            3 | 4 => format!(
                "{}{}",
                FirstName(EN).fake_with_rng::<&str, _>(rng).to_lowercase(),
                Faker.fake_with_rng::<u8, _>(rng)
            ),
            _ => format!(
                "{}_{}",
                FirstName(EN).fake_with_rng::<&str, _>(rng).to_lowercase(),
                Word(EN).fake_with_rng::<&str, _>(rng),
            ),
        }
    }
}

impl<L: Data> Dummy<Password<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(c: &Password<L>, rng: &mut R) -> Self {
        let len: usize = c.1.fake_with_rng(rng);
        let s: Option<String> = (0..len)
            .map(|_| Some(*L::INTERNET_PASSWORD_CHARS.choose(rng)?))
            .collect();
        s.unwrap_or_default()
    }
}

impl<L: Data> Dummy<IPv4<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &IPv4<L>, rng: &mut R) -> Self {
        let u = Uniform::new_inclusive(u8::min_value(), u8::max_value());
        format!(
            "{}.{}.{}.{}",
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
        )
    }
}

impl<L: Data> Dummy<IPv4<L>> for Ipv4Addr {
    #[inline]
    fn dummy_with_rng<R: Rng + ?Sized>(_: &IPv4<L>, rng: &mut R) -> Self {
        Faker.fake_with_rng::<Ipv4Addr, _>(rng)
    }
}

impl<L: Data> Dummy<IPv6<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &IPv6<L>, rng: &mut R) -> Self {
        let u = Uniform::new_inclusive(u16::min_value(), u16::max_value());
        format!(
            "{:X}:{:X}:{:X}:{:X}:{:X}:{:X}:{:X}:{:X}",
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
        )
    }
}

impl<L: Data> Dummy<IPv6<L>> for Ipv6Addr {
    #[inline]
    fn dummy_with_rng<R: Rng + ?Sized>(_: &IPv6<L>, rng: &mut R) -> Self {
        Faker.fake_with_rng::<Ipv6Addr, _>(rng)
    }
}

impl<L: Data> Dummy<IP<L>> for IpAddr {
    #[inline]
    fn dummy_with_rng<R: Rng + ?Sized>(_: &IP<L>, rng: &mut R) -> Self {
        Faker.fake_with_rng::<IpAddr, _>(rng)
    }
}

impl<L: Data> Dummy<MACAddress<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &MACAddress<L>, rng: &mut R) -> Self {
        let u = Uniform::new_inclusive(u8::min_value(), u8::max_value());
        format!(
            "{:X}:{:X}:{:X}:{:X}:{:X}:{:X}",
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
        )
    }
}

impl<L: Data> Dummy<Color<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &Color<L>, rng: &mut R) -> Self {
        let u = Uniform::new_inclusive(u8::min_value(), u8::max_value());
        format!(
            "#{:02X}{:02X}{:02X}",
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
        )
    }
}

impl<L: Data> Dummy<UserAgent<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &UserAgent<L>, rng: &mut R) -> Self {
        let s = *L::INTERNET_USER_AGENT.choose(rng).unwrap();
        s.into()
    }
}

impl<L: Data> Dummy<UserAgent<L>> for &str {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &UserAgent<L>, rng: &mut R) -> Self {
        let s = *L::INTERNET_USER_AGENT.choose(rng).unwrap();
        s
    }
}
<commit_msg>Fix MAC format<commit_after>use crate::faker::internet::raw::*;
use crate::faker::lorem::raw::Word;
use crate::faker::name::raw::FirstName;
use crate::locales::{Data, EN};
use crate::{Dummy, Fake, Faker};
use rand::distributions::{Distribution, Uniform};
use rand::seq::SliceRandom;
use rand::Rng;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};

impl<L: Data> Dummy<FreeEmailProvider<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &FreeEmailProvider<L>, rng: &mut R) -> Self {
        let s = *L::INTERNET_FREE_EMAIL_PROVIDER.choose(rng).unwrap();
        s.into()
    }
}

impl<L: Data> Dummy<FreeEmailProvider<L>> for &str {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &FreeEmailProvider<L>, rng: &mut R) -> Self {
        let s = *L::INTERNET_FREE_EMAIL_PROVIDER.choose(rng).unwrap();
        s
    }
}

impl<L: Data> Dummy<DomainSuffix<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &DomainSuffix<L>, rng: &mut R) -> Self {
        let s = *L::INTERNET_DOMAIN_SUFFIX.choose(rng).unwrap();
        s.into()
    }
}

impl<L: Data> Dummy<DomainSuffix<L>> for &str {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &DomainSuffix<L>, rng: &mut R) -> Self {
        let s = *L::INTERNET_DOMAIN_SUFFIX.choose(rng).unwrap();
        s
    }
}

impl<L: Data + Copy> Dummy<FreeEmail<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(c: &FreeEmail<L>, rng: &mut R) -> Self {
        let username: String = Username(c.0).fake_with_rng(rng);
        let provider: String = FreeEmailProvider(c.0).fake_with_rng(rng);
        format!("{}@{}", username, provider)
    }
}

impl<L: Data + Copy> Dummy<SafeEmail<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &SafeEmail<L>, rng: &mut R) -> Self {
        let username: String = FirstName(EN).fake_with_rng::<&str, _>(rng).to_lowercase();
        let domain = ["com", "net", "org"].choose(rng).unwrap();
        format!("{}@example.{}", username, domain)
    }
}

impl<L: Data> Dummy<Username<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &Username<L>, rng: &mut R) -> Self {
        match Faker.fake_with_rng::<u8, _>(rng) {
            0 => FirstName(EN).fake_with_rng::<&str, _>(rng).to_lowercase(),
            1 | 2 => format!(
                "{}.{}",
                Word(EN).fake_with_rng::<&str, _>(rng),
                FirstName(EN).fake_with_rng::<&str, _>(rng).to_lowercase()
            ),
            3 | 4 => format!(
                "{}{}",
                FirstName(EN).fake_with_rng::<&str, _>(rng).to_lowercase(),
                Faker.fake_with_rng::<u8, _>(rng)
            ),
            _ => format!(
                "{}_{}",
                FirstName(EN).fake_with_rng::<&str, _>(rng).to_lowercase(),
                Word(EN).fake_with_rng::<&str, _>(rng),
            ),
        }
    }
}

impl<L: Data> Dummy<Password<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(c: &Password<L>, rng: &mut R) -> Self {
        let len: usize = c.1.fake_with_rng(rng);
        let s: Option<String> = (0..len)
            .map(|_| Some(*L::INTERNET_PASSWORD_CHARS.choose(rng)?))
            .collect();
        s.unwrap_or_default()
    }
}

impl<L: Data> Dummy<IPv4<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &IPv4<L>, rng: &mut R) -> Self {
        let u = Uniform::new_inclusive(u8::min_value(), u8::max_value());
        format!(
            "{}.{}.{}.{}",
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
        )
    }
}

impl<L: Data> Dummy<IPv4<L>> for Ipv4Addr {
    #[inline]
    fn dummy_with_rng<R: Rng + ?Sized>(_: &IPv4<L>, rng: &mut R) -> Self {
        Faker.fake_with_rng::<Ipv4Addr, _>(rng)
    }
}

impl<L: Data> Dummy<IPv6<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &IPv6<L>, rng: &mut R) -> Self {
        let u = Uniform::new_inclusive(u16::min_value(), u16::max_value());
        format!(
            "{:X}:{:X}:{:X}:{:X}:{:X}:{:X}:{:X}:{:X}",
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
        )
    }
}

impl<L: Data> Dummy<IPv6<L>> for Ipv6Addr {
    #[inline]
    fn dummy_with_rng<R: Rng + ?Sized>(_: &IPv6<L>, rng: &mut R) -> Self {
        Faker.fake_with_rng::<Ipv6Addr, _>(rng)
    }
}

impl<L: Data> Dummy<IP<L>> for IpAddr {
    #[inline]
    fn dummy_with_rng<R: Rng + ?Sized>(_: &IP<L>, rng: &mut R) -> Self {
        Faker.fake_with_rng::<IpAddr, _>(rng)
    }
}

impl<L: Data> Dummy<MACAddress<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &MACAddress<L>, rng: &mut R) -> Self {
        let u = Uniform::new_inclusive(u8::min_value(), u8::max_value());
        format!(
            "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
        )
    }
}

impl<L: Data> Dummy<Color<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &Color<L>, rng: &mut R) -> Self {
        let u = Uniform::new_inclusive(u8::min_value(), u8::max_value());
        format!(
            "#{:02X}{:02X}{:02X}",
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
        )
    }
}

impl<L: Data> Dummy<UserAgent<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &UserAgent<L>, rng: &mut R) -> Self {
        let s = *L::INTERNET_USER_AGENT.choose(rng).unwrap();
        s.into()
    }
}

impl<L: Data> Dummy<UserAgent<L>> for &str {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &UserAgent<L>, rng: &mut R) -> Self {
        let s = *L::INTERNET_USER_AGENT.choose(rng).unwrap();
        s
    }
}
<|endoftext|>