<commit_before>//! Tests for multiple `--target` flags to subcommands

use cargo_test_support::{basic_manifest, cross_compile, project, rustc_host};

#[cargo_test]
fn double_target_rejected() {
    let p = project()
        .file("Cargo.toml", &basic_manifest("foo", "1.0.0"))
        .file("src/main.rs", "fn main() {}")
        .build();

    p.cargo("build --target a --target b")
        .with_stderr("error: specifying multiple `--target` flags requires `-Zmultitarget`")
        .with_status(101)
        .run();
}

#[cargo_test]
fn simple_build() {
    if cross_compile::disabled() {
        return;
    }
    let t1 = cross_compile::alternate();
    let t2 = rustc_host();
    let p = project()
        .file("Cargo.toml", &basic_manifest("foo", "1.0.0"))
        .file("src/main.rs", "fn main() {}")
        .build();

    p.cargo("build -Z multitarget")
        .arg("--target")
        .arg(&t1)
        .arg("--target")
        .arg(&t2)
        .masquerade_as_nightly_cargo()
        .run();

    assert!(p.target_bin(t1, "foo").is_file());
    assert!(p.target_bin(t2, "foo").is_file());
}

#[cargo_test]
fn simple_test() {
    if !cross_compile::can_run_on_host() {
        return;
    }
    let t1 = cross_compile::alternate();
    let t2 = rustc_host();
    let p = project()
        .file("Cargo.toml", &basic_manifest("foo", "1.0.0"))
        .file("src/lib.rs", "fn main() {}")
        .build();

    p.cargo("test -Z multitarget")
        .arg("--target")
        .arg(&t1)
        .arg("--target")
        .arg(&t2)
        .masquerade_as_nightly_cargo()
        .with_stderr_contains(&format!("[RUNNING] [..]{}[..]", t1))
        .with_stderr_contains(&format!("[RUNNING] [..]{}[..]", t2))
        .run();
}

#[cargo_test]
fn simple_run() {
    let p = project()
        .file("Cargo.toml", &basic_manifest("foo", "1.0.0"))
        .file("src/main.rs", "fn main() {}")
        .build();

    p.cargo("run -Z multitarget --target a --target b")
        .with_stderr("error: only one `--target` argument is supported")
        .with_status(101)
        .masquerade_as_nightly_cargo()
        .run();
}

#[cargo_test]
fn simple_doc() {
    if cross_compile::disabled() {
        return;
    }
    let t1 = cross_compile::alternate();
    let t2 = rustc_host();
    let p = project()
        .file("Cargo.toml", &basic_manifest("foo", "1.0.0"))
        .file("src/lib.rs", "//! empty lib")
        .build();

    p.cargo("doc -Z multitarget")
        .arg("--target")
        .arg(&t1)
        .arg("--target")
        .arg(&t2)
        .masquerade_as_nightly_cargo()
        .run();

    assert!(p.build_dir().join(&t1).join("doc/foo/index.html").is_file());
    assert!(p.build_dir().join(&t2).join("doc/foo/index.html").is_file());
}

#[cargo_test]
fn simple_check() {
    if cross_compile::disabled() {
        return;
    }
    let t1 = cross_compile::alternate();
    let t2 = rustc_host();
    let p = project()
        .file("Cargo.toml", &basic_manifest("foo", "1.0.0"))
        .file("src/main.rs", "fn main() {}")
        .build();

    p.cargo("check -Z multitarget")
        .arg("--target")
        .arg(&t1)
        .arg("--target")
        .arg(&t2)
        .masquerade_as_nightly_cargo()
        .run();
}

#[cargo_test]
fn same_value_twice() {
    if cross_compile::disabled() {
        return;
    }
    let t = rustc_host();
    let p = project()
        .file("Cargo.toml", &basic_manifest("foo", "1.0.0"))
        .file("src/main.rs", "fn main() {}")
        .build();

    p.cargo("build -Z multitarget")
        .arg("--target")
        .arg(&t)
        .arg("--target")
        .arg(&t)
        .masquerade_as_nightly_cargo()
        .run();

    assert!(p.target_bin(t, "foo").is_file());
}
<commit_msg>Tests for setting multitarget in config<commit_after>//! Tests for multiple `--target` flags to subcommands

use cargo_test_support::{basic_manifest, cross_compile, project, rustc_host};

#[cargo_test]
fn double_target_rejected() {
    let p = project()
        .file("Cargo.toml", &basic_manifest("foo", "1.0.0"))
        .file("src/main.rs", "fn main() {}")
        .build();

    p.cargo("build --target a --target b")
        .with_stderr("[ERROR] specifying multiple `--target` flags requires `-Zmultitarget`")
        .with_status(101)
        .run();
}

#[cargo_test]
fn double_target_rejected_with_config() {
    let p = project()
        .file("Cargo.toml", &basic_manifest("foo", "1.0.0"))
        .file("src/main.rs", "fn main() {}")
        .file(
            ".cargo/config.toml",
            r#"
                [build]
                target = ["a", "b"]
            "#,
        )
        .build();

    p.cargo("build")
        .with_stderr("[ERROR] specifying multiple `--target` flags requires `-Zmultitarget`")
        .with_status(101)
        .run();
}

#[cargo_test]
fn simple_build() {
    if cross_compile::disabled() {
        return;
    }
    let t1 = cross_compile::alternate();
    let t2 = rustc_host();
    let p = project()
        .file("Cargo.toml", &basic_manifest("foo", "1.0.0"))
        .file("src/main.rs", "fn main() {}")
        .build();

    p.cargo("build -Z multitarget")
        .arg("--target")
        .arg(&t1)
        .arg("--target")
        .arg(&t2)
        .masquerade_as_nightly_cargo()
        .run();

    assert!(p.target_bin(t1, "foo").is_file());
    assert!(p.target_bin(t2, "foo").is_file());
}

#[cargo_test]
fn simple_build_with_config() {
    if cross_compile::disabled() {
        return;
    }
    let t1 = cross_compile::alternate();
    let t2 = rustc_host();
    let p = project()
        .file("Cargo.toml", &basic_manifest("foo", "1.0.0"))
        .file("src/main.rs", "fn main() {}")
        .file(
            ".cargo/config.toml",
            &format!(
                r#"
                    [unstable]
                    multitarget = true
                    [build]
                    target = ["{t1}", "{t2}"]
                "#
            ),
        )
        .build();

    p.cargo("build").masquerade_as_nightly_cargo().run();

    assert!(p.target_bin(t1, "foo").is_file());
    assert!(p.target_bin(t2, "foo").is_file());
}

#[cargo_test]
fn simple_test() {
    if !cross_compile::can_run_on_host() {
        return;
    }
    let t1 = cross_compile::alternate();
    let t2 = rustc_host();
    let p = project()
        .file("Cargo.toml", &basic_manifest("foo", "1.0.0"))
        .file("src/lib.rs", "fn main() {}")
        .build();

    p.cargo("test -Z multitarget")
        .arg("--target")
        .arg(&t1)
        .arg("--target")
        .arg(&t2)
        .masquerade_as_nightly_cargo()
        .with_stderr_contains(&format!("[RUNNING] [..]{}[..]", t1))
        .with_stderr_contains(&format!("[RUNNING] [..]{}[..]", t2))
        .run();
}

#[cargo_test]
fn simple_run() {
    let p = project()
        .file("Cargo.toml", &basic_manifest("foo", "1.0.0"))
        .file("src/main.rs", "fn main() {}")
        .build();

    p.cargo("run -Z multitarget --target a --target b")
        .with_stderr("[ERROR] only one `--target` argument is supported")
        .with_status(101)
        .masquerade_as_nightly_cargo()
        .run();
}

#[cargo_test]
fn simple_doc() {
    if cross_compile::disabled() {
        return;
    }
    let t1 = cross_compile::alternate();
    let t2 = rustc_host();
    let p = project()
        .file("Cargo.toml", &basic_manifest("foo", "1.0.0"))
        .file("src/lib.rs", "//! empty lib")
        .build();

    p.cargo("doc -Z multitarget")
        .arg("--target")
        .arg(&t1)
        .arg("--target")
        .arg(&t2)
        .masquerade_as_nightly_cargo()
        .run();

    assert!(p.build_dir().join(&t1).join("doc/foo/index.html").is_file());
    assert!(p.build_dir().join(&t2).join("doc/foo/index.html").is_file());
}

#[cargo_test]
fn simple_check() {
    if cross_compile::disabled() {
        return;
    }
    let t1 = cross_compile::alternate();
    let t2 = rustc_host();
    let p = project()
        .file("Cargo.toml", &basic_manifest("foo", "1.0.0"))
        .file("src/main.rs", "fn main() {}")
        .build();

    p.cargo("check -Z multitarget")
        .arg("--target")
        .arg(&t1)
        .arg("--target")
        .arg(&t2)
        .masquerade_as_nightly_cargo()
        .run();
}

#[cargo_test]
fn same_value_twice() {
    if cross_compile::disabled() {
        return;
    }
    let t = rustc_host();
    let p = project()
        .file("Cargo.toml", &basic_manifest("foo", "1.0.0"))
        .file("src/main.rs", "fn main() {}")
        .build();

    p.cargo("build -Z multitarget")
        .arg("--target")
        .arg(&t)
        .arg("--target")
        .arg(&t)
        .masquerade_as_nightly_cargo()
        .run();

    assert!(p.target_bin(t, "foo").is_file());
}

#[cargo_test]
fn same_value_twice_with_config() {
    if cross_compile::disabled() {
        return;
    }
    let t = rustc_host();
    let p = project()
        .file("Cargo.toml", &basic_manifest("foo", "1.0.0"))
        .file("src/main.rs", "fn main() {}")
        .file(
            ".cargo/config.toml",
            &format!(
                r#"
                    [unstable]
                    multitarget = true
                    [build]
                    target = ["{t}", "{t}"]
                "#
            ),
        )
        .build();

    p.cargo("build").masquerade_as_nightly_cargo().run();

    assert!(p.target_bin(t, "foo").is_file());
}

#[cargo_test]
fn works_with_config_in_both_string_or_list() {
    if cross_compile::disabled() {
        return;
    }
    let t = rustc_host();
    let p = project()
        .file("Cargo.toml", &basic_manifest("foo", "1.0.0"))
        .file("src/main.rs", "fn main() {}")
        .file(
            ".cargo/config.toml",
            &format!(
                r#"
                    [unstable]
                    multitarget = true
                    [build]
                    target = "{t}"
                "#
            ),
        )
        .build();

    p.cargo("build").masquerade_as_nightly_cargo().run();

    assert!(p.target_bin(t, "foo").is_file());

    p.cargo("clean").run();

    p.change_file(
        ".cargo/config.toml",
        &format!(
            r#"
                [unstable]
                multitarget = true
                [build]
                target = ["{t}"]
            "#
        ),
    );

    p.cargo("build").masquerade_as_nightly_cargo().run();

    assert!(p.target_bin(t, "foo").is_file());
}

#[cargo_test]
fn works_with_env() {
    let t = rustc_host();
    let p = project()
        .file("Cargo.toml", &basic_manifest("foo", "1.0.0"))
        .file("src/main.rs", "fn main() {}")
        .build();

    p.cargo("build")
        .env("CARGO_BUILD_TARGET", t)
        .masquerade_as_nightly_cargo()
        .run();

    assert!(p.target_bin(t, "foo").is_file());
}
<|endoftext|>


<commit_before>#![warn(clippy::needless_lifetimes)]
#![allow(dead_code, clippy::needless_pass_by_value, clippy::unnecessary_wraps)]

fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {}

fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) {}

// No error; same lifetime on two params.
fn same_lifetime_on_input<'a>(_x: &'a u8, _y: &'a u8) {}

// No error; static involved.
fn only_static_on_input(_x: &u8, _y: &u8, _z: &'static u8) {}

fn mut_and_static_input(_x: &mut u8, _y: &'static str) {}

fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 {
    x
}

// No error; multiple input refs.
fn multiple_in_and_out_1<'a>(x: &'a u8, _y: &'a u8) -> &'a u8 {
    x
}

// No error; multiple input refs.
fn multiple_in_and_out_2<'a, 'b>(x: &'a u8, _y: &'b u8) -> &'a u8 {
    x
}

// No error; static involved.
fn in_static_and_out<'a>(x: &'a u8, _y: &'static u8) -> &'a u8 {
    x
}

// No error.
fn deep_reference_1<'a, 'b>(x: &'a u8, _y: &'b u8) -> Result<&'a u8, ()> {
    Ok(x)
}

// No error; two input refs.
fn deep_reference_2<'a>(x: Result<&'a u8, &'a u8>) -> &'a u8 {
    x.unwrap()
}

fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> {
    Ok(x)
}

// Where-clause, but without lifetimes.
fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()>
where
    T: Copy,
{
    Ok(x)
}

type Ref<'r> = &'r u8;

// No error; same lifetime on two params.
fn lifetime_param_1<'a>(_x: Ref<'a>, _y: &'a u8) {}

fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {}

// No error; bounded lifetime.
fn lifetime_param_3<'a, 'b: 'a>(_x: Ref<'a>, _y: &'b u8) {}

// No error; bounded lifetime.
fn lifetime_param_4<'a, 'b>(_x: Ref<'a>, _y: &'b u8)
where
    'b: 'a,
{
}

struct Lt<'a, I: 'static> {
    x: &'a I,
}

// No error; fn bound references `'a`.
fn fn_bound<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>
where
    F: Fn(Lt<'a, I>) -> Lt<'a, I>,
{
    unreachable!()
}

fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>
where
    for<'x> F: Fn(Lt<'x, I>) -> Lt<'x, I>,
{
    unreachable!()
}

// No error; see below.
fn fn_bound_3<'a, F: FnOnce(&'a i32)>(x: &'a i32, f: F) {
    f(x);
}

fn fn_bound_3_cannot_elide() {
    let x = 42;
    let p = &x;
    let mut q = &x;
    // This will fail if we elide lifetimes of `fn_bound_3`.
    fn_bound_3(p, |y| q = y);
}

// No error; multiple input refs.
fn fn_bound_4<'a, F: FnOnce() -> &'a ()>(cond: bool, x: &'a (), f: F) -> &'a () {
    if cond { x } else { f() }
}

struct X {
    x: u8,
}

impl X {
    fn self_and_out<'s>(&'s self) -> &'s u8 {
        &self.x
    }

    // No error; multiple input refs.
    fn self_and_in_out<'s, 't>(&'s self, _x: &'t u8) -> &'s u8 {
        &self.x
    }

    fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {}

    // No error; same lifetimes on two params.
    fn self_and_same_in<'s>(&'s self, _x: &'s u8) {}
}

struct Foo<'a>(&'a u8);

impl<'a> Foo<'a> {
    // No error; lifetime `'a` not defined in method.
    fn self_shared_lifetime(&self, _: &'a u8) {}
    // No error; bounds exist.
    fn self_bound_lifetime<'b: 'a>(&self, _: &'b u8) {}
}

fn already_elided<'a>(_: &u8, _: &'a u8) -> &'a u8 {
    unimplemented!()
}

fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str {
    unimplemented!()
}

// No warning; two input lifetimes (named on the reference, anonymous on `Foo`).
fn struct_with_lt2<'a>(_foo: &'a Foo) -> &'a str {
    unimplemented!()
}

// No warning; two input lifetimes (anonymous on the reference, named on `Foo`).
fn struct_with_lt3<'a>(_foo: &Foo<'a>) -> &'a str {
    unimplemented!()
}

// No warning; two input lifetimes.
fn struct_with_lt4<'a, 'b>(_foo: &'a Foo<'b>) -> &'a str {
    unimplemented!()
}

trait WithLifetime<'a> {}

type WithLifetimeAlias<'a> = dyn WithLifetime<'a>;

// Should not warn because it won't build without the lifetime.
fn trait_obj_elided<'a>(_arg: &'a dyn WithLifetime) -> &'a str {
    unimplemented!()
}

// Should warn because there is no lifetime on `Drop`, so this would be
// unambiguous if we elided the lifetime.
fn trait_obj_elided2<'a>(_arg: &'a dyn Drop) -> &'a str {
    unimplemented!()
}

type FooAlias<'a> = Foo<'a>;

fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str {
    unimplemented!()
}

// No warning; two input lifetimes (named on the reference, anonymous on `FooAlias`).
fn alias_with_lt2<'a>(_foo: &'a FooAlias) -> &'a str {
    unimplemented!()
}

// No warning; two input lifetimes (anonymous on the reference, named on `FooAlias`).
fn alias_with_lt3<'a>(_foo: &FooAlias<'a>) -> &'a str {
    unimplemented!()
}

// No warning; two input lifetimes.
fn alias_with_lt4<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'a str {
    unimplemented!()
}

fn named_input_elided_output<'a>(_arg: &'a str) -> &str {
    unimplemented!()
}

fn elided_input_named_output<'a>(_arg: &str) -> &'a str {
    unimplemented!()
}

fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) {
    unimplemented!()
}
fn trait_bound<'a, T: WithLifetime<'a>>(_: &'a u8, _: T) {
    unimplemented!()
}

// Don't warn on these; see issue #292.
fn trait_bound_bug<'a, T: WithLifetime<'a>>() {
    unimplemented!()
}

// See issue #740.
struct Test {
    vec: Vec<usize>,
}

impl Test {
    fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = usize> + 'a> {
        unimplemented!()
    }
}

trait LintContext<'a> {}

fn f<'a, T: LintContext<'a>>(_: &T) {}

fn test<'a>(x: &'a [u8]) -> u8 {
    let y: &'a u8 = &x[5];
    *y
}

// Issue #3284: give hint regarding lifetime in return type.
struct Cow<'a> {
    x: &'a str,
}
fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> {
    unimplemented!()
}

// Make sure we still warn on implementations
mod issue4291 {
    trait BadTrait {
        fn needless_lt<'a>(x: &'a u8) {}
    }

    impl BadTrait for () {
        fn needless_lt<'a>(_x: &'a u8) {}
    }
}

mod issue2944 {
    trait Foo {}
    struct Bar {}
    struct Baz<'a> {
        bar: &'a Bar,
    }

    impl<'a> Foo for Baz<'a> {}
    impl Bar {
        fn baz<'a>(&'a self) -> impl Foo + 'a {
            Baz { bar: self }
        }
    }
}

mod nested_elision_sites {
    // issue #issue2944

    // closure trait bounds subject to nested elision
    // don't lint because they refer to outer lifetimes
    fn trait_fn<'a>(i: &'a i32) -> impl Fn() -> &'a i32 {
        move || i
    }
    fn trait_fn_mut<'a>(i: &'a i32) -> impl FnMut() -> &'a i32 {
        move || i
    }
    fn trait_fn_once<'a>(i: &'a i32) -> impl FnOnce() -> &'a i32 {
        move || i
    }

    // don't lint
    fn impl_trait_in_input_position<'a>(f: impl Fn() -> &'a i32) -> &'a i32 {
        f()
    }
    fn impl_trait_in_output_position<'a>(i: &'a i32) -> impl Fn() -> &'a i32 {
        move || i
    }
    // lint
    fn impl_trait_elidable_nested_named_lifetimes<'a>(i: &'a i32, f: impl for<'b> Fn(&'b i32) -> &'b i32) -> &'a i32 {
        f(i)
    }
    fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 {
        f(i)
    }

    // don't lint
    fn generics_not_elidable<'a, T: Fn() -> &'a i32>(f: T) -> &'a i32 {
        f()
    }
    // lint
    fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 {
        f(i)
    }

    // don't lint
    fn where_clause_not_elidable<'a, T>(f: T) -> &'a i32
    where
        T: Fn() -> &'a i32,
    {
        f()
    }
    // lint
    fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32
    where
        T: Fn(&i32) -> &i32,
    {
        f(i)
    }

    // don't lint
    fn pointer_fn_in_input_position<'a>(f: fn(&'a i32) -> &'a i32, i: &'a i32) -> &'a i32 {
        f(i)
    }
    fn pointer_fn_in_output_position<'a>(_: &'a i32) -> fn(&'a i32) -> &'a i32 {
        |i| i
    }
    // lint
    fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 {
        f(i)
    }

    // don't lint
    fn nested_fn_pointer_1<'a>(_: &'a i32) -> fn(fn(&'a i32) -> &'a i32) -> i32 {
        |f| 42
    }
    fn nested_fn_pointer_2<'a>(_: &'a i32) -> impl Fn(fn(&'a i32)) {
        |f| ()
    }

    // lint
    fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 {
        |f| 42
    }
    fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) {
        |f| ()
    }
}

mod issue6159 {
    use std::ops::Deref;
    pub fn apply_deref<'a, T, F, R>(x: &'a T, f: F) -> R
    where
        T: Deref,
        F: FnOnce(&'a T::Target) -> R,
    {
        f(x.deref())
    }
}

fn main() {}
<commit_msg>fix(clippy): add missing allow(dyn_drop)<commit_after>#![warn(clippy::needless_lifetimes)]
#![allow(dead_code, clippy::needless_pass_by_value, clippy::unnecessary_wraps, dyn_drop)]

fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {}

fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) {}

// No error; same lifetime on two params.
fn same_lifetime_on_input<'a>(_x: &'a u8, _y: &'a u8) {}

// No error; static involved.
fn only_static_on_input(_x: &u8, _y: &u8, _z: &'static u8) {}

fn mut_and_static_input(_x: &mut u8, _y: &'static str) {}

fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 {
    x
}

// No error; multiple input refs.
fn multiple_in_and_out_1<'a>(x: &'a u8, _y: &'a u8) -> &'a u8 {
    x
}

// No error; multiple input refs.
fn multiple_in_and_out_2<'a, 'b>(x: &'a u8, _y: &'b u8) -> &'a u8 {
    x
}

// No error; static involved.
fn in_static_and_out<'a>(x: &'a u8, _y: &'static u8) -> &'a u8 {
    x
}

// No error.
fn deep_reference_1<'a, 'b>(x: &'a u8, _y: &'b u8) -> Result<&'a u8, ()> {
    Ok(x)
}

// No error; two input refs.
fn deep_reference_2<'a>(x: Result<&'a u8, &'a u8>) -> &'a u8 {
    x.unwrap()
}

fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> {
    Ok(x)
}

// Where-clause, but without lifetimes.
fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()>
where
    T: Copy,
{
    Ok(x)
}

type Ref<'r> = &'r u8;

// No error; same lifetime on two params.
fn lifetime_param_1<'a>(_x: Ref<'a>, _y: &'a u8) {}

fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {}

// No error; bounded lifetime.
fn lifetime_param_3<'a, 'b: 'a>(_x: Ref<'a>, _y: &'b u8) {}

// No error; bounded lifetime.
fn lifetime_param_4<'a, 'b>(_x: Ref<'a>, _y: &'b u8)
where
    'b: 'a,
{
}

struct Lt<'a, I: 'static> {
    x: &'a I,
}

// No error; fn bound references `'a`.
fn fn_bound<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>
where
    F: Fn(Lt<'a, I>) -> Lt<'a, I>,
{
    unreachable!()
}

fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>
where
    for<'x> F: Fn(Lt<'x, I>) -> Lt<'x, I>,
{
    unreachable!()
}

// No error; see below.
fn fn_bound_3<'a, F: FnOnce(&'a i32)>(x: &'a i32, f: F) {
    f(x);
}

fn fn_bound_3_cannot_elide() {
    let x = 42;
    let p = &x;
    let mut q = &x;
    // This will fail if we elide lifetimes of `fn_bound_3`.
    fn_bound_3(p, |y| q = y);
}

// No error; multiple input refs.
fn fn_bound_4<'a, F: FnOnce() -> &'a ()>(cond: bool, x: &'a (), f: F) -> &'a () {
    if cond { x } else { f() }
}

struct X {
    x: u8,
}

impl X {
    fn self_and_out<'s>(&'s self) -> &'s u8 {
        &self.x
    }

    // No error; multiple input refs.
    fn self_and_in_out<'s, 't>(&'s self, _x: &'t u8) -> &'s u8 {
        &self.x
    }

    fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {}

    // No error; same lifetimes on two params.
    fn self_and_same_in<'s>(&'s self, _x: &'s u8) {}
}

struct Foo<'a>(&'a u8);

impl<'a> Foo<'a> {
    // No error; lifetime `'a` not defined in method.
    fn self_shared_lifetime(&self, _: &'a u8) {}
    // No error; bounds exist.
    fn self_bound_lifetime<'b: 'a>(&self, _: &'b u8) {}
}

fn already_elided<'a>(_: &u8, _: &'a u8) -> &'a u8 {
    unimplemented!()
}

fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str {
    unimplemented!()
}

// No warning; two input lifetimes (named on the reference, anonymous on `Foo`).
fn struct_with_lt2<'a>(_foo: &'a Foo) -> &'a str {
    unimplemented!()
}

// No warning; two input lifetimes (anonymous on the reference, named on `Foo`).
fn struct_with_lt3<'a>(_foo: &Foo<'a>) -> &'a str {
    unimplemented!()
}

// No warning; two input lifetimes.
fn struct_with_lt4<'a, 'b>(_foo: &'a Foo<'b>) -> &'a str {
    unimplemented!()
}

trait WithLifetime<'a> {}

type WithLifetimeAlias<'a> = dyn WithLifetime<'a>;

// Should not warn because it won't build without the lifetime.
fn trait_obj_elided<'a>(_arg: &'a dyn WithLifetime) -> &'a str {
    unimplemented!()
}

// Should warn because there is no lifetime on `Drop`, so this would be
// unambiguous if we elided the lifetime.
fn trait_obj_elided2<'a>(_arg: &'a dyn Drop) -> &'a str {
    unimplemented!()
}

type FooAlias<'a> = Foo<'a>;

fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str {
    unimplemented!()
}

// No warning; two input lifetimes (named on the reference, anonymous on `FooAlias`).
fn alias_with_lt2<'a>(_foo: &'a FooAlias) -> &'a str {
    unimplemented!()
}

// No warning; two input lifetimes (anonymous on the reference, named on `FooAlias`).
fn alias_with_lt3<'a>(_foo: &FooAlias<'a>) -> &'a str {
    unimplemented!()
}

// No warning; two input lifetimes.
fn alias_with_lt4<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'a str {
    unimplemented!()
}

fn named_input_elided_output<'a>(_arg: &'a str) -> &str {
    unimplemented!()
}

fn elided_input_named_output<'a>(_arg: &str) -> &'a str {
    unimplemented!()
}

fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) {
    unimplemented!()
}
fn trait_bound<'a, T: WithLifetime<'a>>(_: &'a u8, _: T) {
    unimplemented!()
}

// Don't warn on these; see issue #292.
fn trait_bound_bug<'a, T: WithLifetime<'a>>() {
    unimplemented!()
}

// See issue #740.
struct Test {
    vec: Vec<usize>,
}

impl Test {
    fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = usize> + 'a> {
        unimplemented!()
    }
}

trait LintContext<'a> {}

fn f<'a, T: LintContext<'a>>(_: &T) {}

fn test<'a>(x: &'a [u8]) -> u8 {
    let y: &'a u8 = &x[5];
    *y
}

// Issue #3284: give hint regarding lifetime in return type.
struct Cow<'a> {
    x: &'a str,
}
fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> {
    unimplemented!()
}

// Make sure we still warn on implementations
mod issue4291 {
    trait BadTrait {
        fn needless_lt<'a>(x: &'a u8) {}
    }

    impl BadTrait for () {
        fn needless_lt<'a>(_x: &'a u8) {}
    }
}

mod issue2944 {
    trait Foo {}
    struct Bar {}
    struct Baz<'a> {
        bar: &'a Bar,
    }

    impl<'a> Foo for Baz<'a> {}
    impl Bar {
        fn baz<'a>(&'a self) -> impl Foo + 'a {
            Baz { bar: self }
        }
    }
}

mod nested_elision_sites {
    // issue #issue2944

    // closure trait bounds subject to nested elision
    // don't lint because they refer to outer lifetimes
    fn trait_fn<'a>(i: &'a i32) -> impl Fn() -> &'a i32 {
        move || i
    }
    fn trait_fn_mut<'a>(i: &'a i32) -> impl FnMut() -> &'a i32 {
        move || i
    }
    fn trait_fn_once<'a>(i: &'a i32) -> impl FnOnce() -> &'a i32 {
        move || i
    }

    // don't lint
    fn impl_trait_in_input_position<'a>(f: impl Fn() -> &'a i32) -> &'a i32 {
        f()
    }
    fn impl_trait_in_output_position<'a>(i: &'a i32) -> impl Fn() -> &'a i32 {
        move || i
    }
    // lint
    fn impl_trait_elidable_nested_named_lifetimes<'a>(i: &'a i32, f: impl for<'b> Fn(&'b i32) -> &'b i32) -> &'a i32 {
        f(i)
    }
    fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 {
        f(i)
    }

    // don't lint
    fn generics_not_elidable<'a, T: Fn() -> &'a i32>(f: T) -> &'a i32 {
        f()
    }
    // lint
    fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 {
        f(i)
    }

    // don't lint
    fn where_clause_not_elidable<'a, T>(f: T) -> &'a i32
    where
        T: Fn() -> &'a i32,
    {
        f()
    }
    // lint
    fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32
    where
        T: Fn(&i32) -> &i32,
    {
        f(i)
    }

    // don't lint
    fn pointer_fn_in_input_position<'a>(f: fn(&'a i32) -> &'a i32, i: &'a i32) -> &'a i32 {
        f(i)
    }
    fn pointer_fn_in_output_position<'a>(_: &'a i32) -> fn(&'a i32) -> &'a i32 {
        |i| i
    }
    // lint
    fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 {
        f(i)
    }

    // don't lint
    fn nested_fn_pointer_1<'a>(_: &'a i32) -> fn(fn(&'a i32) -> &'a i32) -> i32 {
        |f| 42
    }
    fn nested_fn_pointer_2<'a>(_: &'a i32) -> impl Fn(fn(&'a i32)) {
        |f| ()
    }

    // lint
    fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 {
        |f| 42
    }
    fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) {
        |f| ()
    }
}

mod issue6159 {
    use std::ops::Deref;
    pub fn apply_deref<'a, T, F, R>(x: &'a T, f: F) -> R
    where
        T: Deref,
        F: FnOnce(&'a T::Target) -> R,
    {
        f(x.deref())
    }
}

fn main() {}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate mio;

use context::SharedContext;
use dummy_adapter::DummyAdapter;
use events::*;
use http_server::HttpServer;
use mio::{ EventLoop, EventSet, Token };
use service::{ Service, ServiceAdapter };

pub struct Controler {
    sender: EventSender,
    context: SharedContext
}

impl Controler {
    /// Construct a new `Controler`.
    ///
    /// ```
    /// # use service_manager::Controler;
    /// let controler = Controller::new();
    /// ```
    pub fn new(sender: EventSender, context: SharedContext) -> Controler {
        Controler {
            sender: sender,
            context: context
        }
    }

    pub fn start(&self) {
        println!("Starting controller");

        // Start the http server.
        let http_server = HttpServer::new(self.context.clone());
        http_server.start();

        // Start the dummy adapter.
        let dummy_adapter = DummyAdapter::new(self.sender.clone(), self.context.clone());
        dummy_adapter.start();
    }
}

impl mio::Handler for Controler {
    type Timeout = ();
    type Message = EventData;

    fn ready(&mut self,
             event_loop: &mut EventLoop<Controler>,
             token: Token,
             events: EventSet) {
        println!("Receiving a fd event!");
    }

    fn notify(&mut self,
              event_loop: &mut EventLoop<Controler>,
              data: EventData) {
        println!("Receiving a notification! {}", data.description());

        let mut context = self.context.lock().unwrap();
        match data {
            EventData::ServiceStart { id } => {
                println!("ServiceStart {} We now have {} services.", id, context.services_count());
            }
            EventData::ServiceStop { id } => {
                context.remove_service(id.clone());
                println!("ServiceStop {} We now have {} services.", id, context.services_count());
            }
            _ => { }
        }
    }
}
<commit_msg>Clean up warnings in controler.rs<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate mio;

use context::SharedContext;
use dummy_adapter::DummyAdapter;
use events::*;
use http_server::HttpServer;
use mio::EventLoop;
use service::{ Service, ServiceAdapter };

pub struct Controler {
    sender: EventSender,
    context: SharedContext
}

impl Controler {
    /// Construct a new `Controler`.
    ///
    /// ```
    /// # use service_manager::Controler;
    /// let controler = Controller::new();
    /// ```
    pub fn new(sender: EventSender, context: SharedContext) -> Controler {
        Controler {
            sender: sender,
            context: context
        }
    }

    pub fn start(&self) {
        println!("Starting controller");

        // Start the http server.
        let http_server = HttpServer::new(self.context.clone());
        http_server.start();

        // Start the dummy adapter.
        let dummy_adapter = DummyAdapter::new(self.sender.clone(), self.context.clone());
        dummy_adapter.start();
    }
}

impl mio::Handler for Controler {
    type Timeout = ();
    type Message = EventData;

    fn notify(&mut self,
              _: &mut EventLoop<Controler>,
              data: EventData) {
        println!("Receiving a notification! {}", data.description());

        let mut context = self.context.lock().unwrap();
        match data {
            EventData::ServiceStart { id } => {
                println!("ServiceStart {} We now have {} services.", id, context.services_count());
            }
            EventData::ServiceStop { id } => {
                context.remove_service(id.clone());
                println!("ServiceStop {} We now have {} services.", id, context.services_count());
            }
            _ => { }
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::mem::transmute;

use dbus_serialize::types::{Value,BasicValue,Path,Signature,Struct,Variant,Array,Dictionary};

#[derive(Debug)]
pub enum DemarshalError {
    MessageTooShort,
    CorruptedMessage,
    BadUTF8,
    BadSignature,
    ElementTooBig,
    MismatchedParens,
}

pub fn get_alignment(sig: char) -> usize {
    match sig {
        'y' => 1,
        'b' => 1,
        'n' => 2,
        'q' => 2,
        'i' => 4,
        'u' => 4,
        'x' => 8,
        't' => 8,
        's' => 4,
        'o' => 4,
        'g' => 1,

        'a' => 4,
        '(' => 8,
        '{' => 8,
        'v' => 1,
        _ => panic!("Bogus type")
    }
}

fn demarshal_byte(buf: &mut Vec<u8>, offset: &mut usize) -> Result<Value,DemarshalError> {
    if buf.len() < 1 {
        return Err(DemarshalError::MessageTooShort);
    }
    let byte = buf.remove(0);
    *offset += 1;
    return Ok(Value::BasicValue(BasicValue::Byte(byte)))
}

fn align_to(buf: &mut Vec<u8>, offset: &mut usize, align: usize) -> Result<(),DemarshalError> {
    if *offset % align == 0 {
        return Ok(());
    }
    let delta = align - (*offset % align);
    if buf.len() < delta {
        return Err(DemarshalError::MessageTooShort);
    }
    for _ in 0..delta {
        buf.remove(0);
        *offset += 1;
    }
    Ok(())
}

fn demarshal_bool(buf: &mut Vec<u8>, offset: &mut usize) -> Result<Value,DemarshalError> {
    try!(align_to(buf, offset, 4));
    if buf.len() < 4 {
        return Err(DemarshalError::MessageTooShort);
    }
    let byte = buf.remove(0);
    *offset += 1;
    // XXX: assumes LE
    for _ in 0..3 {
        *offset += 1;
        // Only the first byte should have a non-zero value
        if buf.remove(0) != 0 {
            return Err(DemarshalError::CorruptedMessage);
        }
    }
    match byte {
        0 => Ok(Value::BasicValue(BasicValue::Boolean(false))),
        1 => Ok(Value::BasicValue(BasicValue::Boolean(true))),
        _ => Err(DemarshalError::CorruptedMessage)
    }
}

fn demarshal_int(buf: &mut Vec<u8>, offset: &mut usize, len: usize, is_signed: bool) -> Result<Value,DemarshalError> {
    try!(align_to(buf, offset, len));
    if buf.len() < len {
        return Err(DemarshalError::MessageTooShort);
    }
    let mut intbuf = [0; 8];
    for i in 0..len {
        intbuf[i] = buf.remove(0);
        *offset += 1;
    }
    // Check for sign-extension
    if is_signed && (intbuf[len-1] & 128 == 128) {
        for i in len..8 {
            intbuf[i] = 0xff;
        }
    }
    let val : u64 = unsafe { transmute(intbuf) };
    if is_signed {
        match len {
            2 => Ok(Value::BasicValue(BasicValue::Int16(val as i16))),
            4 => Ok(Value::BasicValue(BasicValue::Int32(val as i32))),
            8 => Ok(Value::BasicValue(BasicValue::Int64(val as i64))),
            _ => panic!("Bogus length {}", len)
        }
    } else {
        match len {
            1 => Ok(Value::BasicValue(BasicValue::Byte(val as u8))),
            2 => Ok(Value::BasicValue(BasicValue::Uint16(val as u16))),
            4 => Ok(Value::BasicValue(BasicValue::Uint32(val as u32))),
            8 => Ok(Value::BasicValue(BasicValue::Uint64(val))),
            _ => panic!("Bogus length {}", len)
        }
    }
}

fn demarshal_string(buf: &mut Vec<u8>, offset: &mut usize, count_size: usize, is_path: bool) -> Result<Value,DemarshalError> {
    // demarshal_int ensure we're correctly aligned with input
    let len = match demarshal_int(buf, offset, count_size, false) {
        Ok(Value::BasicValue(BasicValue::Uint32(x))) => x,
        Ok(Value::BasicValue(BasicValue::Byte(x))) => x as u32,
        _ => return Err(DemarshalError::CorruptedMessage),
    };
    let mut strbuf = Vec::new();
    for _ in 0..len {
        strbuf.push(buf.remove(0));
        *offset += 1
    }
    // Check the NUL byte
    if buf.remove(0) != 0 {
        return Err(DemarshalError::CorruptedMessage);
    }
    *offset += 1;
    let val = try!(String::from_utf8(strbuf).or(Err(DemarshalError::BadUTF8)));
    if is_path {
        Ok(Value::BasicValue(BasicValue::ObjectPath(Path(val))))
    } else {
        if count_size == 4 {
            Ok(Value::BasicValue(BasicValue::String(val)))
        } else {
            Ok(Value::BasicValue(BasicValue::Signature(Signature(val))))
        }
    }
}

fn demarshal_array(buf: &mut Vec<u8>, offset: &mut usize, sig: &mut String) -> Result<Value,DemarshalError> {
    if sig.len() < 1 {
        return Err(DemarshalError::BadSignature);
    }
    let typ = sig.chars().next().unwrap();
    let is_dict = if typ == '{' {
        true
    } else {
        false
    };
    // demarshal_int ensure we're correctly aligned with input
    let array_len = match demarshal_int(buf, offset, 4, false) {
        Ok(Value::BasicValue(BasicValue::Uint32(x))) => x,
        _ => return Err(DemarshalError::CorruptedMessage),
    };
    if array_len > 1 << 26 {
        return Err(DemarshalError::ElementTooBig);
    }
    try!(align_to(buf, offset, get_alignment(typ)));
    if buf.len() < (array_len as usize) {
        return Err(DemarshalError::MessageTooShort);
    }

    let mut vec = Vec::new();
    let start_offset = *offset;
    let mut sig_copy = "".to_owned();
    while *offset < start_offset+(array_len as usize) {
        // We want to pass the same signature to each call of demarshal
        sig_copy = sig.to_owned();
        vec.push(try!(demarshal(buf, offset, &mut sig_copy)));
    }
    // Now that we're done with our elements we can forget the elements consumed by demarshal
    let mut mysig = sig.clone();
    mysig.truncate(sig.len() - sig_copy.len());
    mysig.insert(0, 'a');
    *sig = sig_copy;

    if is_dict {
        let mut map : HashMap<BasicValue,Value> = HashMap::new();
        for x in vec {
            let mut s = match x {
                Value::Struct(x) => x,
                _ => panic!("Dictionaries should contain structs")
            };
            let val = s.objects.remove(1);
            let key = match s.objects[0] {
                Value::BasicValue(ref x) => x,
                _ => panic!("Dictionaries require BasicValue keys")
            };
            map.insert(key.clone(), val);
        }
        return Ok(Value::Dictionary(Dictionary::new_with_sig(map, mysig)));
    }

    Ok(Value::Array(Array::new_with_sig(vec, mysig)))
}

fn demarshal_struct(buf: &mut Vec<u8>, offset: &mut usize, sig: &mut String) -> Result<Value,DemarshalError> {
    if sig.len() < 1 {
        return Err(DemarshalError::BadSignature);
    }
    try!(align_to(buf, offset, 8));

    let mut vec = Vec::new();
    let mut mysig = sig.to_owned();
    loop {
        let typ = match sig.chars().next() {
            Some(x) => x,
            None => return Err(DemarshalError::MismatchedParens)
        };
        if typ == ')' {
            sig.remove(0);
            break;
        }
        vec.push(try!(demarshal(buf, offset, sig)));
    }
    // Only keep the characters that were consumed by demarshal
    let oldlen = mysig.len();
    mysig.truncate(oldlen - sig.len());
    mysig.insert(0, '(');

    Ok(Value::Struct(Struct{
        objects: vec,
        signature: Signature(mysig)
    }))
}

fn demarshal_variant(buf: &mut Vec<u8>, offset: &mut usize) -> Result<Value,DemarshalError> {
    let mut variant_sig = "g".to_owned();
    let sigval = try!(demarshal(buf, offset, &mut variant_sig));
    let sig = match sigval {
        Value::BasicValue(BasicValue::Signature(x)) => x,
        _ => return Err(DemarshalError::CorruptedMessage)
    };
    let mut s = sig.0.to_owned();
    let var = try!(demarshal(buf, offset, &mut s));
    Ok(Value::Variant(Variant{
        object: Box::new(var),
        signature: sig
    }))
}

pub fn demarshal(buf: &mut Vec<u8>, offset: &mut usize, sig: &mut String) -> Result<Value,DemarshalError> {
    let typ = sig.remove(0);
    match typ {
        'y' => demarshal_byte(buf, offset),
        'b' => demarshal_bool(buf, offset),
        'n' => demarshal_int(buf, offset, 2, true),
        'q' => demarshal_int(buf, offset, 2, false),
        'i' => demarshal_int(buf, offset, 4, true),
        'u' => demarshal_int(buf, offset, 4, false),
        'x' => demarshal_int(buf, offset, 8, true),
        't' => demarshal_int(buf, offset, 8, false),
        's' => demarshal_string(buf, offset, 4, false),
        'o' => demarshal_string(buf, offset, 4, true),
        'g' => demarshal_string(buf, offset, 1, false),

        'a' => demarshal_array(buf, offset, sig),
        '(' => demarshal_struct(buf, offset, sig),
        '{' => demarshal_struct(buf, offset, sig),
        'v' => demarshal_variant(buf, offset),
        _ => Err(DemarshalError::BadSignature)
    }
}

#[cfg(test)]
mod test {
    use marshal::Marshal;
    use demarshal::demarshal;
    use dbus_serialize::types::{Value,BasicValue,Signature};

    #[test]
    fn test_demarshal_u32() {
        let mut buf = Vec::new();
        let x = 16 as u32;
        let mut sig = x.get_type().to_string();
        x.dbus_encode(&mut buf);

        let mut offset = 0;
        let v = demarshal(&mut buf, &mut offset, &mut sig).unwrap();
        assert_eq!(v, Value::BasicValue(BasicValue::Uint32(16)));
        assert_eq!(buf.len(), 0);
        assert_eq!(sig, "");
    }

    #[test]
    fn test_demarshal_u32_offset() {
        let mut buf = Vec::new();
        buf.insert(0, 0);
        let x = 16 as u32;
        let mut sig = x.get_type();
        x.dbus_encode(&mut buf);

        buf.remove(0);
        let mut offset = 1;
        let v = demarshal(&mut buf, &mut offset, &mut sig).unwrap();
        assert_eq!(v, Value::BasicValue(BasicValue::Uint32(16)));
        assert_eq!(buf.len(), 0);
        assert_eq!(sig, "");
    }

    #[test]
    fn test_string() {
        let mut buf = Vec::new();
        let x = "swalter".to_string();
        let mut sig = x.get_type();
        x.dbus_encode(&mut buf);

        let mut offset = 0;
        let v = demarshal(&mut buf, &mut offset, &mut sig).unwrap();
        assert_eq!(v, Value::BasicValue(BasicValue::String("swalter".to_string())));
        assert_eq!(buf.len(), 0);
        assert_eq!(sig, "");
    }

    #[test]
    fn test_array() {
        let mut buf = Vec::new();
        let x = vec![1 as u32, 2 as u32, 3 as u32];
        let mut sig = "au".to_string();
        x.dbus_encode(&mut buf);

        let mut offset = 0;
        let v = demarshal(&mut buf, &mut offset, &mut sig).unwrap();
        let arr = match v {
            Value::Array(x) => x,
            _ => panic!("Bad return from demarshal {:?}", v)
        };
        let golden = vec![
            Value::BasicValue(BasicValue::Uint32(1)),
            Value::BasicValue(BasicValue::Uint32(2)),
            Value::BasicValue(BasicValue::Uint32(3)),
        ];
        assert_eq!(arr.objects, golden);
        assert_eq!(buf.len(), 0);
        assert_eq!(sig, "");
    }

    #[test]
    fn test_array_bytes() {
        let mut buf = Vec::new();
        let x = vec![1 as u8, 2 as u8, 3 as u8];
        let mut sig = "ay".to_string();
        x.dbus_encode(&mut buf);

        let mut offset = 0;
        let v = demarshal(&mut buf, &mut offset, &mut sig).unwrap();
        let arr = match v {
            Value::Array(x) => x,
            _ => panic!("Bad return from demarshal {:?}", v)
        };
        let golden = vec![
            Value::BasicValue(BasicValue::Byte(1)),
            Value::BasicValue(BasicValue::Byte(2)),
            Value::BasicValue(BasicValue::Byte(3)),
        ];
        assert_eq!(arr.objects, golden);
        assert_eq!(buf.len(), 0);
        assert_eq!(sig, "");
    }

    #[test]
    fn test_struct() {
        let mut buf = Vec::new();
        let x = "swalter".to_string();
        let mut sig = "(ss)".to_string();
        x.dbus_encode(&mut buf);
        x.dbus_encode(&mut buf);

        let mut offset = 0;
        let v = demarshal(&mut buf, &mut offset, &mut sig).unwrap();
        assert_eq!(buf.len(), 0);
        assert_eq!(sig, "");
        let s = match v {
            Value::Struct(x) => x,
            _ => panic!("Bad return from demarshal {:?}", v)
        };
        assert_eq!(s.signature, Signature("(ss)".to_string()));
    }
}
<commit_msg>clippy: address needless_return warning<commit_after>use std::collections::HashMap;
use std::mem::transmute;

use dbus_serialize::types::{Value,BasicValue,Path,Signature,Struct,Variant,Array,Dictionary};

#[derive(Debug)]
pub enum DemarshalError {
    MessageTooShort,
    CorruptedMessage,
    BadUTF8,
    BadSignature,
    ElementTooBig,
    MismatchedParens,
}

pub fn get_alignment(sig: char) -> usize {
    match sig {
        'y' => 1,
        'b' => 1,
        'n' => 2,
        'q' => 2,
        'i' => 4,
        'u' => 4,
        'x' => 8,
        't' => 8,
        's' => 4,
        'o' => 4,
        'g' => 1,

        'a' => 4,
        '(' => 8,
        '{' => 8,
        'v' => 1,
        _ => panic!("Bogus type")
    }
}

fn demarshal_byte(buf: &mut Vec<u8>, offset: &mut usize) -> Result<Value,DemarshalError> {
    if buf.len() < 1 {
        return Err(DemarshalError::MessageTooShort);
    }
    let byte = buf.remove(0);
    *offset += 1;
    Ok(Value::BasicValue(BasicValue::Byte(byte)))
}

fn align_to(buf: &mut Vec<u8>, offset: &mut usize, align: usize) -> Result<(),DemarshalError> {
    if *offset % align == 0 {
        return Ok(());
    }
    let delta = align - (*offset % align);
    if buf.len() < delta {
        return Err(DemarshalError::MessageTooShort);
    }
    for _ in 0..delta {
        buf.remove(0);
        *offset += 1;
    }
    Ok(())
}

fn demarshal_bool(buf: &mut Vec<u8>, offset: &mut usize) -> Result<Value,DemarshalError> {
    try!(align_to(buf, offset, 4));
    if buf.len() < 4 {
        return Err(DemarshalError::MessageTooShort);
    }
    let byte = buf.remove(0);
    *offset += 1;
    // XXX: assumes LE
    for _ in 0..3 {
        *offset += 1;
        // Only the first byte should have a non-zero value
        if buf.remove(0) != 0 {
            return Err(DemarshalError::CorruptedMessage);
        }
    }
    match byte {
        0 => Ok(Value::BasicValue(BasicValue::Boolean(false))),
        1 => Ok(Value::BasicValue(BasicValue::Boolean(true))),
        _ => Err(DemarshalError::CorruptedMessage)
    }
}

fn demarshal_int(buf: &mut Vec<u8>, offset: &mut usize, len: usize, is_signed: bool) -> Result<Value,DemarshalError> {
    try!(align_to(buf, offset, len));
    if buf.len() < len {
        return Err(DemarshalError::MessageTooShort);
    }
    let mut intbuf = [0; 8];
    for i in 0..len {
        intbuf[i] = buf.remove(0);
        *offset += 1;
    }
    // Check for sign-extension
    if is_signed && (intbuf[len-1] & 128 == 128) {
        for i in len..8 {
            intbuf[i] = 0xff;
        }
    }
    let val : u64 = unsafe { transmute(intbuf) };
    if is_signed {
        match len {
            2 => Ok(Value::BasicValue(BasicValue::Int16(val as i16))),
            4 => Ok(Value::BasicValue(BasicValue::Int32(val as i32))),
            8 => Ok(Value::BasicValue(BasicValue::Int64(val as i64))),
            _ => panic!("Bogus length {}", len)
        }
    } else {
        match len {
            1 => Ok(Value::BasicValue(BasicValue::Byte(val as u8))),
            2 => Ok(Value::BasicValue(BasicValue::Uint16(val as u16))),
            4 => Ok(Value::BasicValue(BasicValue::Uint32(val as u32))),
            8 => Ok(Value::BasicValue(BasicValue::Uint64(val))),
            _ => panic!("Bogus length {}", len)
        }
    }
}

fn demarshal_string(buf: &mut Vec<u8>, offset: &mut usize, count_size: usize, is_path: bool) -> Result<Value,DemarshalError> {
    // demarshal_int ensure we're correctly aligned with input
    let len = match demarshal_int(buf, offset, count_size, false) {
        Ok(Value::BasicValue(BasicValue::Uint32(x))) => x,
        Ok(Value::BasicValue(BasicValue::Byte(x))) => x as u32,
        _ => return Err(DemarshalError::CorruptedMessage),
    };
    let mut strbuf = Vec::new();
    for _ in 0..len {
        strbuf.push(buf.remove(0));
        *offset += 1
    }
    // Check the NUL byte
    if buf.remove(0) != 0 {
        return Err(DemarshalError::CorruptedMessage);
    }
    *offset += 1;
    let val = try!(String::from_utf8(strbuf).or(Err(DemarshalError::BadUTF8)));
    if is_path {
        Ok(Value::BasicValue(BasicValue::ObjectPath(Path(val))))
    } else {
        if count_size == 4 {
            Ok(Value::BasicValue(BasicValue::String(val)))
        } else {
            Ok(Value::BasicValue(BasicValue::Signature(Signature(val))))
        }
    }
}

fn demarshal_array(buf: &mut Vec<u8>, offset: &mut usize, sig: &mut String) -> Result<Value,DemarshalError> {
    if sig.len() < 1 {
        return Err(DemarshalError::BadSignature);
    }
    let typ = sig.chars().next().unwrap();
    let is_dict = if typ == '{' {
        true
    } else {
        false
    };
    // demarshal_int ensure we're correctly aligned with input
    let array_len = match demarshal_int(buf, offset, 4, false) {
        Ok(Value::BasicValue(BasicValue::Uint32(x))) => x,
        _ => return Err(DemarshalError::CorruptedMessage),
    };
    if array_len > 1 << 26 {
        return Err(DemarshalError::ElementTooBig);
    }
    try!(align_to(buf, offset, get_alignment(typ)));
    if buf.len() < (array_len as usize) {
        return Err(DemarshalError::MessageTooShort);
    }

    let mut vec = Vec::new();
    let start_offset = *offset;
    let mut sig_copy = "".to_owned();
    while *offset < start_offset+(array_len as usize) {
        // We want to pass the same signature to each call of demarshal
        sig_copy = sig.to_owned();
        vec.push(try!(demarshal(buf, offset, &mut sig_copy)));
    }
    // Now that we're done with our elements we can forget the elements consumed by demarshal
    let mut mysig = sig.clone();
    mysig.truncate(sig.len() - sig_copy.len());
    mysig.insert(0, 'a');
    *sig = sig_copy;

    if is_dict {
        let mut map : HashMap<BasicValue,Value> = HashMap::new();
        for x in vec {
            let mut s = match x {
                Value::Struct(x) => x,
                _ => panic!("Dictionaries should contain structs")
            };
            let val = s.objects.remove(1);
            let key = match s.objects[0] {
                Value::BasicValue(ref x) => x,
                _ => panic!("Dictionaries require BasicValue keys")
            };
            map.insert(key.clone(), val);
        }
        return Ok(Value::Dictionary(Dictionary::new_with_sig(map, mysig)));
    }

    Ok(Value::Array(Array::new_with_sig(vec, mysig)))
}

fn demarshal_struct(buf: &mut Vec<u8>, offset: &mut usize, sig: &mut String) -> Result<Value,DemarshalError> {
    if sig.len() < 1 {
        return Err(DemarshalError::BadSignature);
    }
    try!(align_to(buf, offset, 8));

    let mut vec = Vec::new();
    let mut mysig = sig.to_owned();
    loop {
        let typ = match sig.chars().next() {
            Some(x) => x,
            None => return Err(DemarshalError::MismatchedParens)
        };
        if typ == ')' {
            sig.remove(0);
            break;
        }
        vec.push(try!(demarshal(buf, offset, sig)));
    }
    // Only keep the characters that were consumed by demarshal
    let oldlen = mysig.len();
    mysig.truncate(oldlen - sig.len());
    mysig.insert(0, '(');

    Ok(Value::Struct(Struct{
        objects: vec,
        signature: Signature(mysig)
    }))
}

fn demarshal_variant(buf: &mut Vec<u8>, offset: &mut usize) -> Result<Value,DemarshalError> {
    let mut variant_sig = "g".to_owned();
    let sigval = try!(demarshal(buf, offset, &mut variant_sig));
    let sig = match sigval {
        Value::BasicValue(BasicValue::Signature(x)) => x,
        _ => return Err(DemarshalError::CorruptedMessage)
    };
    let mut s = sig.0.to_owned();
    let var = try!(demarshal(buf, offset, &mut s));
    Ok(Value::Variant(Variant{
        object: Box::new(var),
        signature: sig
    }))
}

pub fn demarshal(buf: &mut Vec<u8>, offset: &mut usize, sig: &mut String) -> Result<Value,DemarshalError> {
    let typ = sig.remove(0);
    match typ {
        'y' => demarshal_byte(buf, offset),
        'b' => demarshal_bool(buf, offset),
        'n' => demarshal_int(buf, offset, 2, true),
        'q' => demarshal_int(buf, offset, 2, false),
        'i' => demarshal_int(buf, offset, 4, true),
        'u' => demarshal_int(buf, offset, 4, false),
        'x' => demarshal_int(buf, offset, 8, true),
        't' => demarshal_int(buf, offset, 8, false),
        's' => demarshal_string(buf, offset, 4, false),
        'o' => demarshal_string(buf, offset, 4, true),
        'g' => demarshal_string(buf, offset, 1, false),

        'a' => demarshal_array(buf, offset, sig),
        '(' => demarshal_struct(buf, offset, sig),
        '{' => demarshal_struct(buf, offset, sig),
        'v' => demarshal_variant(buf, offset),
        _ => Err(DemarshalError::BadSignature)
    }
}

#[cfg(test)]
mod test {
    use marshal::Marshal;
    use demarshal::demarshal;
    use dbus_serialize::types::{Value,BasicValue,Signature};

    #[test]
    fn test_demarshal_u32() {
        let mut buf = Vec::new();
        let x = 16 as u32;
        let mut sig = x.get_type().to_string();
        x.dbus_encode(&mut buf);

        let mut offset = 0;
        let v = demarshal(&mut buf, &mut offset, &mut sig).unwrap();
        assert_eq!(v, Value::BasicValue(BasicValue::Uint32(16)));
        assert_eq!(buf.len(), 0);
        assert_eq!(sig, "");
    }

    #[test]
    fn test_demarshal_u32_offset() {
        let mut buf = Vec::new();
        buf.insert(0, 0);
        let x = 16 as u32;
        let mut sig = x.get_type();
        x.dbus_encode(&mut buf);

        buf.remove(0);
        let mut offset = 1;
        let v = demarshal(&mut buf, &mut offset, &mut sig).unwrap();
        assert_eq!(v, Value::BasicValue(BasicValue::Uint32(16)));
        assert_eq!(buf.len(), 0);
        assert_eq!(sig, "");
    }

    #[test]
    fn test_string() {
        let mut buf = Vec::new();
        let x = "swalter".to_string();
        let mut sig = x.get_type();
        x.dbus_encode(&mut buf);

        let mut offset = 0;
        let v = demarshal(&mut buf, &mut offset, &mut sig).unwrap();
        assert_eq!(v, Value::BasicValue(BasicValue::String("swalter".to_string())));
        assert_eq!(buf.len(), 0);
        assert_eq!(sig, "");
    }

    #[test]
    fn test_array() {
        let mut buf = Vec::new();
        let x = vec![1 as u32, 2 as u32, 3 as u32];
        let mut sig = "au".to_string();
        x.dbus_encode(&mut buf);

        let mut offset = 0;
        let v = demarshal(&mut buf, &mut offset, &mut sig).unwrap();
        let arr = match v {
            Value::Array(x) => x,
            _ => panic!("Bad return from demarshal {:?}", v)
        };
        let golden = vec![
            Value::BasicValue(BasicValue::Uint32(1)),
            Value::BasicValue(BasicValue::Uint32(2)),
            Value::BasicValue(BasicValue::Uint32(3)),
        ];
        assert_eq!(arr.objects, golden);
        assert_eq!(buf.len(), 0);
        assert_eq!(sig, "");
    }

    #[test]
    fn test_array_bytes() {
        let mut buf = Vec::new();
        let x = vec![1 as u8, 2 as u8, 3 as u8];
        let mut sig = "ay".to_string();
        x.dbus_encode(&mut buf);

        let mut offset = 0;
        let v = demarshal(&mut buf, &mut offset, &mut sig).unwrap();
        let arr = match v {
            Value::Array(x) => x,
            _ => panic!("Bad return from demarshal {:?}", v)
        };
        let golden = vec![
            Value::BasicValue(BasicValue::Byte(1)),
            Value::BasicValue(BasicValue::Byte(2)),
            Value::BasicValue(BasicValue::Byte(3)),
        ];
        assert_eq!(arr.objects, golden);
        assert_eq!(buf.len(), 0);
        assert_eq!(sig, "");
    }

    #[test]
    fn test_struct() {
        let mut buf = Vec::new();
        let x = "swalter".to_string();
        let mut sig = "(ss)".to_string();
        x.dbus_encode(&mut buf);
        x.dbus_encode(&mut buf);

        let mut offset = 0;
        let v = demarshal(&mut buf, &mut offset, &mut sig).unwrap();
        assert_eq!(buf.len(), 0);
        assert_eq!(sig, "");
        let s = match v {
            Value::Struct(x) => x,
            _ => panic!("Bad return from demarshal {:?}", v)
        };
        assert_eq!(s.signature, Signature("(ss)".to_string()));
    }
}
<|endoftext|>


<commit_before>extern crate crossbeam;
extern crate clap;
#[macro_use] extern crate version;
extern crate walkdir;

extern crate libimagrt;

use std::env;
use std::process::exit;
use std::process::Command;
use std::process::Stdio;
use std::io::ErrorKind;

use walkdir::WalkDir;
use crossbeam::*;
use clap::{Arg, SubCommand};

use libimagrt::runtime::Runtime;

fn help(cmds: Vec<String>) {
    println!(r#"

     _
    (_)_ __ ___   __ _  __ _
    | | '_ \` _ \/ _\`|/ _\`|
    | | | | | | | (_| | (_| |
    |_|_| |_| |_|\__,_|\__, |
                       |___/
    -------------------------

    Usage: imag [--version | --versions | -h | --help] <command> <args...>

    imag - the personal information management suite for the commandline

    imag is a PIM suite for the commandline. It consists of several commands,
    called "modules". Each module implements one PIM aspect and all of these
    modules can be used independently.

    Available commands:
    "#);

    for cmd in cmds.iter() {
        println!("\t{}", cmd);
    }

    println!(r#"

    Call a command with 'imag <command> <args>'
    Each command can be called with "--help" to get the respective helptext.

    Please visit https://github.com/matthiasbeyer/imag to view the source code,
    follow the development of imag or maybe even contribute to imag.

    imag is free software. It is released under the terms of LGPLv2.1

    (c) 2016 Matthias Beyer and contributors"#);
}

fn get_commands() -> Vec<String> {
    let path = env::var("PATH");
    if path.is_err() {
        println!("PATH error: {:?}", path);
        exit(1);
    }
    let pathelements = path.unwrap();
    let pathelements = pathelements.split(":");

    let joinhandles : Vec<ScopedJoinHandle<Vec<String>>> = pathelements
        .map(|elem| {
            crossbeam::scope(|scope| {
                scope.spawn(|| {
                    WalkDir::new(elem)
                        .max_depth(1)
                        .into_iter()
                        .filter(|path| {
                            match path {
                                &Ok(ref p) => p.file_name()
                                    .to_str()
                                    .map_or(false, |filename| filename.starts_with("imag-")),
                                &Err(_)   => false,
                            }
                        })
                        .filter_map(|x| x.ok())
                        .filter_map(|path| {
                           path.file_name()
                               .to_str()
                               .and_then(|s| s.splitn(2, "-").nth(1).map(|s| format!("imag {}", s)))
                        })
                        .collect()
                })
            })
        })
        .collect();

    let mut execs = vec![];
    for joinhandle in joinhandles.into_iter() {
        let mut v = joinhandle.join();
        execs.append(&mut v);
    }

    execs
}

fn main() {
    let appname = "imag";
    let version = &version!();
    let about   = "imag - the PIM suite for the commandline";
    let mut app = Runtime::get_default_cli_builder(appname, version, about);

    let commands = get_commands();

    for command in commands.iter() {
        let s = SubCommand::with_name(&command[..]);
        app = app.subcommand(s)
    }

    let app = app.arg(Arg::with_name("version")
                      .long("version")
                      .takes_value(false)
                      .required(false)
                      .multiple(false)
                      .help("Get the version of imag"))
                 .arg(Arg::with_name("versions")
                      .long("versions")
                      .takes_value(false)
                      .required(false)
                      .multiple(false)
                      .help("Get the versions of the imag commands"))
                 .arg(Arg::with_name("help")
                      .long("help")
                      .short("h")
                      .takes_value(false)
                      .required(false)
                      .multiple(false)
                      .help("Show help"));

    let matches = app.get_matches();

    if matches.is_present("help") {
        help(get_commands());
        exit(0);
    }

    if matches.is_present("version") {
        println!("imag {}", &version!()[..]);
        exit(0);
    }

    if matches.is_present("versions") {
        let mut result = vec![];
        for command in commands.iter() {
            result.push(crossbeam::scope(|scope| {
                scope.spawn(|| {
                    let v = Command::new(command).arg("--version").output();
                    match v {
                        Ok(v) => match String::from_utf8(v.stdout) {
                            Ok(s) => format!("{} -> {}", command, s),
                            Err(e) => format!("Failed calling {} -> {:?}", command, e),
                        },
                        Err(e) => format!("Failed calling {} -> {:?}", command, e),
                    }
                })
            }))
        }

        for versionstring in result.into_iter().map(|handle| handle.join()) {
            println!("{}", versionstring);
        }
    }

    matches.subcommand_name()
        .map(|subcommand| {

            let mut subcommand_args = vec![];

            for arg in Runtime::arg_names() {
                matches.value_of(arg)
                    .map(|value| {
                        subcommand_args.push(arg);
                        subcommand_args.push(value);
                    });
            }

            match Command::new(format!("imag-{}", subcommand))
                .stdin(Stdio::inherit())
                .stdout(Stdio::inherit())
                .stderr(Stdio::inherit())
                .arg(subcommand)
                .args(&subcommand_args[..])
                .spawn()
                .and_then(|mut handle| handle.wait())
            {
                Ok(exit_status) => {
                    if !exit_status.success() {
                        println!("{} exited with non-zero exit code", subcommand);
                        exit(exit_status.code().unwrap_or(42));
                    }
                },

                Err(e) => {
                    match e.kind() {
                        ErrorKind::NotFound => {
                            println!("No such command: 'imag-{}'", subcommand);
                            exit(2);
                        },
                        ErrorKind::PermissionDenied => {
                            println!("No permission to execute: 'imag-{}'", subcommand);
                            exit(1);
                        },
                        _ => {
                            println!("Error spawning: {:?}", e);
                            exit(1337);
                        }
                    }
                }
            }
        });
}
<commit_msg>Only return subcommand name<commit_after>extern crate crossbeam;
extern crate clap;
#[macro_use] extern crate version;
extern crate walkdir;

extern crate libimagrt;

use std::env;
use std::process::exit;
use std::process::Command;
use std::process::Stdio;
use std::io::ErrorKind;

use walkdir::WalkDir;
use crossbeam::*;
use clap::{Arg, SubCommand};

use libimagrt::runtime::Runtime;

fn help(cmds: Vec<String>) {
    println!(r#"

     _
    (_)_ __ ___   __ _  __ _
    | | '_ \` _ \/ _\`|/ _\`|
    | | | | | | | (_| | (_| |
    |_|_| |_| |_|\__,_|\__, |
                       |___/
    -------------------------

    Usage: imag [--version | --versions | -h | --help] <command> <args...>

    imag - the personal information management suite for the commandline

    imag is a PIM suite for the commandline. It consists of several commands,
    called "modules". Each module implements one PIM aspect and all of these
    modules can be used independently.

    Available commands:
    "#);

    for cmd in cmds.iter() {
        println!("\t{}", cmd);
    }

    println!(r#"

    Call a command with 'imag <command> <args>'
    Each command can be called with "--help" to get the respective helptext.

    Please visit https://github.com/matthiasbeyer/imag to view the source code,
    follow the development of imag or maybe even contribute to imag.

    imag is free software. It is released under the terms of LGPLv2.1

    (c) 2016 Matthias Beyer and contributors"#);
}

fn get_commands() -> Vec<String> {
    let path = env::var("PATH");
    if path.is_err() {
        println!("PATH error: {:?}", path);
        exit(1);
    }
    let pathelements = path.unwrap();
    let pathelements = pathelements.split(":");

    let joinhandles : Vec<ScopedJoinHandle<Vec<String>>> = pathelements
        .map(|elem| {
            crossbeam::scope(|scope| {
                scope.spawn(|| {
                    WalkDir::new(elem)
                        .max_depth(1)
                        .into_iter()
                        .filter(|path| {
                            match path {
                                &Ok(ref p) => p.file_name()
                                    .to_str()
                                    .map_or(false, |filename| filename.starts_with("imag-")),
                                &Err(_)   => false,
                            }
                        })
                        .filter_map(|x| x.ok())
                        .filter_map(|path| {
                           path.file_name()
                               .to_str()
                               .and_then(|s| s.splitn(2, "-").nth(1).map(String::from))
                        })
                        .collect()
                })
            })
        })
        .collect();

    let mut execs = vec![];
    for joinhandle in joinhandles.into_iter() {
        let mut v = joinhandle.join();
        execs.append(&mut v);
    }

    execs
}

fn main() {
    let appname = "imag";
    let version = &version!();
    let about   = "imag - the PIM suite for the commandline";
    let mut app = Runtime::get_default_cli_builder(appname, version, about);

    let commands = get_commands();

    for command in commands.iter() {
        let s = SubCommand::with_name(&command[..]);
        app = app.subcommand(s)
    }

    let app = app.arg(Arg::with_name("version")
                      .long("version")
                      .takes_value(false)
                      .required(false)
                      .multiple(false)
                      .help("Get the version of imag"))
                 .arg(Arg::with_name("versions")
                      .long("versions")
                      .takes_value(false)
                      .required(false)
                      .multiple(false)
                      .help("Get the versions of the imag commands"))
                 .arg(Arg::with_name("help")
                      .long("help")
                      .short("h")
                      .takes_value(false)
                      .required(false)
                      .multiple(false)
                      .help("Show help"));

    let matches = app.get_matches();

    if matches.is_present("help") {
        help(get_commands());
        exit(0);
    }

    if matches.is_present("version") {
        println!("imag {}", &version!()[..]);
        exit(0);
    }

    if matches.is_present("versions") {
        let mut result = vec![];
        for command in commands.iter() {
            result.push(crossbeam::scope(|scope| {
                scope.spawn(|| {
                    let v = Command::new(command).arg("--version").output();
                    match v {
                        Ok(v) => match String::from_utf8(v.stdout) {
                            Ok(s) => format!("{} -> {}", command, s),
                            Err(e) => format!("Failed calling {} -> {:?}", command, e),
                        },
                        Err(e) => format!("Failed calling {} -> {:?}", command, e),
                    }
                })
            }))
        }

        for versionstring in result.into_iter().map(|handle| handle.join()) {
            println!("{}", versionstring);
        }
    }

    matches.subcommand_name()
        .map(|subcommand| {

            let mut subcommand_args = vec![];

            for arg in Runtime::arg_names() {
                matches.value_of(arg)
                    .map(|value| {
                        subcommand_args.push(arg);
                        subcommand_args.push(value);
                    });
            }

            match Command::new(format!("imag-{}", subcommand))
                .stdin(Stdio::inherit())
                .stdout(Stdio::inherit())
                .stderr(Stdio::inherit())
                .arg(subcommand)
                .args(&subcommand_args[..])
                .spawn()
                .and_then(|mut handle| handle.wait())
            {
                Ok(exit_status) => {
                    if !exit_status.success() {
                        println!("{} exited with non-zero exit code", subcommand);
                        exit(exit_status.code().unwrap_or(42));
                    }
                },

                Err(e) => {
                    match e.kind() {
                        ErrorKind::NotFound => {
                            println!("No such command: 'imag-{}'", subcommand);
                            exit(2);
                        },
                        ErrorKind::PermissionDenied => {
                            println!("No permission to execute: 'imag-{}'", subcommand);
                            exit(1);
                        },
                        _ => {
                            println!("Error spawning: {:?}", e);
                            exit(1337);
                        }
                    }
                }
            }
        });
}
<|endoftext|>


<commit_before>pub struct Post {
    state: Option<Box<State>>,
    content: String
}

impl Post {
    pub fn new() -> Post {
        Post {
            state: Some(Box::new(Draft {})),
            content: String::new()
        }
    }

    pub fn add_text(&mut self, text: &str) {
        self.content.push_str(text);
    }

    pub fn content(&self) -> &str {
        ""
    }

    pub fn request_review(&mut self) {
        if let Some(s) = self.state.take() {
            self.state = Some(s.request_review())
        }
    }
}

trait State {
    fn request_review(self: Box<Self>) -> Box<State>;
}

struct Draft {}

impl State for Draft {
    fn request_review(self: Box<Self>) -> Box<State> {
        Box::new(PendingReview {})
    }
}

struct PendingReview {}

impl State for PendingReview {
    fn request_review(&self: Box<Self>) -> Box<State> {
        self
    }
}
<commit_msg>Implement method approve on post<commit_after>pub struct Post {
    state: Option<Box<State>>,
    content: String
}

impl Post {
    pub fn new() -> Post {
        Post {
            state: Some(Box::new(Draft {})),
            content: String::new()
        }
    }

    pub fn add_text(&mut self, text: &str) {
        self.content.push_str(text);
    }

    pub fn content(&self) -> &str {
        ""
    }

    pub fn request_review(&mut self) {
        if let Some(s) = self.state.take() {
            self.state = Some(s.request_review())
        }
    }

    pub fn approve(&mut self) {
        if let Some(s) = self.state.take() {
            self.state = Some(s.approve())
        }
    }
}

trait State {
    fn request_review(self: Box<Self>) -> Box<State>;
}

struct Draft {}

impl State for Draft {
    fn request_review(self: Box<Self>) -> Box<State> {
        Box::new(PendingReview {})
    }
}

struct PendingReview {}

impl State for PendingReview {
    fn request_review(&self: Box<Self>) -> Box<State> {
        self
    }
}
<|endoftext|>


<commit_before>//! #Introduction
//! This crate focuses on geting system information.
//!
//! For now it supports Linux, Mac OS X and Windows.
//! And now it can get information of kernel/cpu/memory/disk/load/hostname and so on.
//!

use std::ffi;
use std::io::Read;
use std::fs::File;

/// System load average value.
#[repr(C)]
pub struct LoadAvg {
    /// Average load within one minite.
    pub one: f64,
    /// Average load within five minites.
    pub five: f64,
    /// Average load within fifteen minites.
    pub fifteen: f64,
}

/// System memory information.
#[repr(C)]
pub struct MemInfo {
    /// Total physical memory.
    pub total: u64,
    pub free: u64,
    pub avail: u64,

    pub buffers: u64,
    pub cached: u64,

    /// Total swap memory.
    pub swap_total: u64,
    pub swap_free: u64,
}

/// System momory information.
#[repr(C)]
pub struct DiskInfo {
    pub total: u64,
    pub free: u64,
}

/// Error types
#[derive(Debug)]
pub enum Error {
    UnsupportedSystem,
    ExecFailed(String),
}

extern "C" {
    fn get_os_type() -> *const i8;
    fn get_os_release() -> *const i8;

    fn get_cpu_num() -> u32;
    fn get_cpu_speed() -> u64;

    fn get_loadavg() -> LoadAvg;
    fn get_proc_total() -> u64;

    fn get_mem_info() -> MemInfo;
    fn get_disk_info() -> DiskInfo;
}

/// Get operation system type.
///
/// Such as "Linux", "Darwin", "Windows".
pub fn os_type() -> Result<String, Error> {
    if cfg!(target_os = "linux") {
        let mut s = String::new();
        let mut f = File::open("/proc/sys/kernel/ostype").unwrap();
        let _ = f.read_to_string(&mut s).unwrap();
        s.pop();  // pop '\n'
        Ok(s)
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        unsafe {
            Ok(String::from_utf8_lossy(ffi::CStr::from_ptr(get_os_type()).to_bytes()).into_owned())
        }
    } else {
        Err(Error::UnsupportedSystem)
    }
}

/// Get operation system release version.
///
/// Such as "3.19.0-gentoo"
pub fn os_release() -> Result<String, Error> {
    if cfg!(target_os = "linux") {
        let mut f = File::open("/proc/sys/kernel/osrelease").unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s).unwrap();
        s.pop();
        Ok(s)
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        unsafe {
            Ok(String::from_utf8_lossy(ffi::CStr::from_ptr(get_os_release()).to_bytes())
                   .into_owned())
        }
    } else {
        Err(Error::UnsupportedSystem)
    }
}

/// Get cpu num quantity.
///
/// Notice, it returns the logical cpu quantity.
pub fn cpu_num() -> Result<u32, Error> {
    if cfg!(unix) || cfg!(windows) {
        unsafe { Ok(get_cpu_num()) }
    } else {
        Err(Error::UnsupportedSystem)
    }
}

/// Get cpu speed.
///
/// Such as 2500, that is 2500 MHz.
pub fn cpu_speed() -> Result<u64, Error> {
    if cfg!(target_os = "linux") {
        // /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq
        let mut f = File::open("/proc/cpuinfo").unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s).unwrap();
        let mut lines = s.split('\n');
        for _ in 0..7 {
            lines.next();
        }
        let mut words = lines.next().unwrap().split(':');
        words.next();
        let s = words.next().unwrap().trim().trim_right_matches('\n');
        Ok(s.parse::<f64>().unwrap() as u64)
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        unsafe { Ok(get_cpu_speed()) }
    } else {
        Err(Error::UnsupportedSystem)
    }
}

/// Get system load average value.
///
/// Notice, on windows, one/five/fifteen of the LoadAvg returned are the current load.
pub fn loadavg() -> Result<LoadAvg, Error> {
    if cfg!(target_os = "linux") {
        let mut f = File::open("/proc/loadavg").unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s).unwrap();
        let mut words = s.split(' ');
        let one = words.next().unwrap().parse::<f64>().unwrap();
        let five = words.next().unwrap().parse::<f64>().unwrap();
        let fifteen = words.next().unwrap().parse::<f64>().unwrap();
        Ok(LoadAvg {
            one: one,
            five: five,
            fifteen: fifteen,
        })
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_loadavg() })
    } else {
        Err(Error::UnsupportedSystem)
    }
}

/// Get current processes quantity.
///
/// Notice, it temporarily does not support Windows.
pub fn proc_total() -> Result<u64, Error> {
    if cfg!(target_os = "linux") {
        let mut f = File::open("/proc/loadavg").unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s).unwrap();
        Ok({
            let mut words = s.splitn(4, ' ');
            for _ in 0..3 {
                words.next();
            }
            let mut words = words.next().unwrap().split('/');
            words.next();
            let mut words = words.next().unwrap().split(' ');
            words.next().unwrap().parse::<u64>().unwrap()
        })
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_proc_total() })
    } else {
        Err(Error::UnsupportedSystem)
    }
}

// Analyse number from line.
fn get_mem_num(line: &str) -> u64 {
    let mut line = line.splitn(2, ' ');
    line.next();
    line.next()
        .unwrap()
        .trim_left()
        .split(' ')
        .next()
        .unwrap()
        .parse::<u64>()
        .unwrap()
}

/// Get memory information.
///
/// On Mac OS X and Windows, the buffers and cached variables of the MemInfo returned are zero.
pub fn mem_info() -> Result<MemInfo, Error> {
    if cfg!(target_os = "linux") {
        let mut f = File::open("/proc/meminfo").unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s).unwrap();
        let mut lines = s.split('\n');
        let total = get_mem_num(lines.next().unwrap());
        let free = get_mem_num(lines.next().unwrap());
        let avail = get_mem_num(lines.next().unwrap());
        let buffers = get_mem_num(lines.next().unwrap());
        let cached = get_mem_num(lines.next().unwrap());
        let swap_total = {
            for _ in 0..9 {
                lines.next();
            }
            get_mem_num(lines.next().unwrap())
        };
        let swap_free = get_mem_num(lines.next().unwrap());

        Ok(MemInfo {
            total: total,
            free: free,
            avail: avail,
            buffers: buffers,
            cached: cached,
            swap_total: swap_total,
            swap_free: swap_free,
        })
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_mem_info() })
    } else {
        Err(Error::UnsupportedSystem)
    }
}

/// Get disk information.
///
/// Notice, it just calculate current disk on Windows.
pub fn disk_info() -> Result<DiskInfo, Error> {
    if cfg!(target_os = "linux") || cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_disk_info() })
    } else {
        Err(Error::UnsupportedSystem)
    }
}

/// Get hostname.
pub fn hostname() -> Result<String, Error> {
    use std::process::Command;
    if cfg!(unix) {
        let output = match Command::new("hostname").output() {
            Ok(o) => o,
            Err(e) => return Err(Error::ExecFailed(format!("failed to execute process: {}", e))),
        };
        let mut s = String::from_utf8(output.stdout).unwrap();
        s.pop();  // pop '\n'
        Ok(s)
    } else if cfg!(windows) {
        let output = match Command::new("hostname").output() {
            Ok(o) => o,
            Err(e) => return Err(Error::ExecFailed(format!("failed to execute process: {}", e))),
        };
        let mut s = String::from_utf8(output.stdout).unwrap();
        s.pop();  // pop '\n'
        Ok(s)
    } else {
        Err(Error::UnsupportedSystem)
    }
}
<commit_msg>Changes for supporting ppc64le architecture<commit_after>//! #Introduction
//! This crate focuses on geting system information.
//!
//! For now it supports Linux, Mac OS X and Windows.
//! And now it can get information of kernel/cpu/memory/disk/load/hostname and so on.
//!

use std::ffi;
use std::io::Read;
use std::fs::File;
use std::os::raw::c_char;

/// System load average value.
#[repr(C)]
pub struct LoadAvg {
    /// Average load within one minite.
    pub one: f64,
    /// Average load within five minites.
    pub five: f64,
    /// Average load within fifteen minites.
    pub fifteen: f64,
}

/// System memory information.
#[repr(C)]
pub struct MemInfo {
    /// Total physical memory.
    pub total: u64,
    pub free: u64,
    pub avail: u64,

    pub buffers: u64,
    pub cached: u64,

    /// Total swap memory.
    pub swap_total: u64,
    pub swap_free: u64,
}

/// System momory information.
#[repr(C)]
pub struct DiskInfo {
    pub total: u64,
    pub free: u64,
}

/// Error types
#[derive(Debug)]
pub enum Error {
    UnsupportedSystem,
    ExecFailed(String),
}

extern "C" {
    fn get_os_type() -> *const i8;
    fn get_os_release() -> *const i8;

    fn get_cpu_num() -> u32;
    fn get_cpu_speed() -> u64;

    fn get_loadavg() -> LoadAvg;
    fn get_proc_total() -> u64;

    fn get_mem_info() -> MemInfo;
    fn get_disk_info() -> DiskInfo;
}

/// Get operation system type.
///
/// Such as "Linux", "Darwin", "Windows".
pub fn os_type() -> Result<String, Error> {
    if cfg!(target_os = "linux") {
        let mut s = String::new();
        let mut f = File::open("/proc/sys/kernel/ostype").unwrap();
        let _ = f.read_to_string(&mut s).unwrap();
        s.pop();  // pop '\n'
        Ok(s)
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        unsafe {
            Ok(String::from_utf8_lossy(ffi::CStr::from_ptr(get_os_type() as *const c_char).to_bytes()).into_owned())
        }
    } else {
        Err(Error::UnsupportedSystem)
    }
}

/// Get operation system release version.
///
/// Such as "3.19.0-gentoo"
pub fn os_release() -> Result<String, Error> {
    if cfg!(target_os = "linux") {
        let mut f = File::open("/proc/sys/kernel/osrelease").unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s).unwrap();
        s.pop();
        Ok(s)
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        unsafe {
            Ok(String::from_utf8_lossy(ffi::CStr::from_ptr(get_os_release() as *const c_char).to_bytes())
                   .into_owned())
        }
    } else {
        Err(Error::UnsupportedSystem)
    }
}

/// Get cpu num quantity.
///
/// Notice, it returns the logical cpu quantity.
pub fn cpu_num() -> Result<u32, Error> {
    if cfg!(unix) || cfg!(windows) {
        unsafe { Ok(get_cpu_num()) }
    } else {
        Err(Error::UnsupportedSystem)
    }
}

/// Get cpu speed.
///
/// Such as 2500, that is 2500 MHz.
pub fn cpu_speed() -> Result<u64, Error> {
    if cfg!(target_os = "linux") {
        // /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq
        let mut f = File::open("/proc/cpuinfo").unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s).unwrap();
        let mut lines = s.split('\n');
        for _ in 0..7 {
            lines.next();
        }
        let mut words = lines.next().unwrap().split(':');
        words.next();
        let s = words.next().unwrap().trim().trim_right_matches('\n');
        Ok(s.parse::<f64>().unwrap() as u64)
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        unsafe { Ok(get_cpu_speed()) }
    } else {
        Err(Error::UnsupportedSystem)
    }
}

/// Get system load average value.
///
/// Notice, on windows, one/five/fifteen of the LoadAvg returned are the current load.
pub fn loadavg() -> Result<LoadAvg, Error> {
    if cfg!(target_os = "linux") {
        let mut f = File::open("/proc/loadavg").unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s).unwrap();
        let mut words = s.split(' ');
        let one = words.next().unwrap().parse::<f64>().unwrap();
        let five = words.next().unwrap().parse::<f64>().unwrap();
        let fifteen = words.next().unwrap().parse::<f64>().unwrap();
        Ok(LoadAvg {
            one: one,
            five: five,
            fifteen: fifteen,
        })
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_loadavg() })
    } else {
        Err(Error::UnsupportedSystem)
    }
}

/// Get current processes quantity.
///
/// Notice, it temporarily does not support Windows.
pub fn proc_total() -> Result<u64, Error> {
    if cfg!(target_os = "linux") {
        let mut f = File::open("/proc/loadavg").unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s).unwrap();
        Ok({
            let mut words = s.splitn(4, ' ');
            for _ in 0..3 {
                words.next();
            }
            let mut words = words.next().unwrap().split('/');
            words.next();
            let mut words = words.next().unwrap().split(' ');
            words.next().unwrap().parse::<u64>().unwrap()
        })
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_proc_total() })
    } else {
        Err(Error::UnsupportedSystem)
    }
}

// Analyse number from line.
fn get_mem_num(line: &str) -> u64 {
    let mut line = line.splitn(2, ' ');
    line.next();
    line.next()
        .unwrap()
        .trim_left()
        .split(' ')
        .next()
        .unwrap()
        .parse::<u64>()
        .unwrap()
}

/// Get memory information.
///
/// On Mac OS X and Windows, the buffers and cached variables of the MemInfo returned are zero.
pub fn mem_info() -> Result<MemInfo, Error> {
    if cfg!(target_os = "linux") {
        let mut f = File::open("/proc/meminfo").unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s).unwrap();
        let mut lines = s.split('\n');
        let total = get_mem_num(lines.next().unwrap());
        let free = get_mem_num(lines.next().unwrap());
        let avail = get_mem_num(lines.next().unwrap());
        let buffers = get_mem_num(lines.next().unwrap());
        let cached = get_mem_num(lines.next().unwrap());
        let swap_total = {
            for _ in 0..9 {
                lines.next();
            }
            get_mem_num(lines.next().unwrap())
        };
        let swap_free = get_mem_num(lines.next().unwrap());

        Ok(MemInfo {
            total: total,
            free: free,
            avail: avail,
            buffers: buffers,
            cached: cached,
            swap_total: swap_total,
            swap_free: swap_free,
        })
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_mem_info() })
    } else {
        Err(Error::UnsupportedSystem)
    }
}

/// Get disk information.
///
/// Notice, it just calculate current disk on Windows.
pub fn disk_info() -> Result<DiskInfo, Error> {
    if cfg!(target_os = "linux") || cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_disk_info() })
    } else {
        Err(Error::UnsupportedSystem)
    }
}

/// Get hostname.
pub fn hostname() -> Result<String, Error> {
    use std::process::Command;
    if cfg!(unix) {
        let output = match Command::new("hostname").output() {
            Ok(o) => o,
            Err(e) => return Err(Error::ExecFailed(format!("failed to execute process: {}", e))),
        };
        let mut s = String::from_utf8(output.stdout).unwrap();
        s.pop();  // pop '\n'
        Ok(s)
    } else if cfg!(windows) {
        let output = match Command::new("hostname").output() {
            Ok(o) => o,
            Err(e) => return Err(Error::ExecFailed(format!("failed to execute process: {}", e))),
        };
        let mut s = String::from_utf8(output.stdout).unwrap();
        s.pop();  // pop '\n'
        Ok(s)
    } else {
        Err(Error::UnsupportedSystem)
    }
}
<|endoftext|>


<commit_before>use crate::pagecache::*;
use crate::*;

pub(crate) fn read_blob(
    blob_ptr: Lsn,
    config: &Config,
) -> Result<(MessageKind, Vec<u8>)> {
    let path = config.blob_path(blob_ptr);
    let f_res = std::fs::OpenOptions::new().read(true).open(&path);

    if let Err(e) = &f_res {
        debug!("failed to open file for blob read at {}: {:?}", blob_ptr, e);
    }

    let mut f = f_res?;

    let mut crc_expected_bytes = [0_u8; std::mem::size_of::<u32>()];

    if let Err(e) = f.read_exact(&mut crc_expected_bytes) {
        debug!(
            "failed to read the initial CRC bytes in the blob at {}: {:?}",
            blob_ptr, e,
        );
        return Err(e.into());
    }

    let crc_expected = arr_to_u32(&crc_expected_bytes);

    let mut kind_byte = [0_u8];

    if let Err(e) = f.read_exact(&mut kind_byte) {
        debug!(
            "failed to read the initial CRC bytes in the blob at {}: {:?}",
            blob_ptr, e,
        );
        return Err(e.into());
    }

    let mut buf = vec![];

    if let Err(e) = f.read_to_end(&mut buf) {
        debug!(
            "failed to read data after the CRC bytes in blob at {}: {:?}",
            blob_ptr, e,
        );
        return Err(e.into());
    }

    let mut hasher = crc32fast::Hasher::new();
    hasher.update(&kind_byte);
    hasher.update(&buf);
    let crc_actual = hasher.finalize();

    if crc_expected == crc_actual {
        let buf =
            if config.use_compression { maybe_decompress(buf)? } else { buf };
        Ok((MessageKind::from(kind_byte[0]), buf))
    } else {
        warn!("blob {} failed crc check!", blob_ptr);

        Err(Error::Corruption { at: DiskPtr::Blob(0, blob_ptr) })
    }
}

pub(crate) fn write_blob<T: Serialize>(
    config: &Config,
    kind: MessageKind,
    id: Lsn,
    item: &T,
) -> Result<()> {
    let path = config.blob_path(id);
    let mut f =
        std::fs::OpenOptions::new().write(true).create_new(true).open(&path)?;

    let kind_buf = &[kind.into()];

    let mut hasher = crc32fast::Hasher::new();
    hasher.update(kind_buf);

    let data = {
        let _ = Measure::new(&M.serialize);
        item.serialize()
    };

    hasher.update(&data);
    let crc = u32_to_arr(hasher.finalize());

    io_fail!(config, "write_blob write crc");
    f.write_all(&crc)?;
    io_fail!(config, "write_blob write kind_byte");
    f.write_all(kind_buf)?;
    io_fail!(config, "write_blob write buf");
    f.write_all(&data)
        .map(|r| {
            trace!("successfully wrote blob at {:?}", path);
            r
        })
        .map_err(|e| e.into())
}

pub(crate) fn gc_blobs(config: &Config, stable_lsn: Lsn) -> Result<()> {
    let stable = config.blob_path(stable_lsn);
    let blob_dir = stable.parent().unwrap();
    let blobs = std::fs::read_dir(blob_dir)?;

    debug!("gc_blobs removing any blob with an lsn above {}", stable_lsn);

    let mut to_remove = vec![];
    for blob in blobs {
        let path = blob?.path();
        let lsn_str = path.file_name().unwrap().to_str().unwrap();
        let lsn_res: std::result::Result<Lsn, _> = lsn_str.parse();

        if let Err(e) = lsn_res {
            return Err(Error::Unsupported(format!(
                "blobs directory contains \
                 unparsable path ({:?}): {}",
                path, e
            )));
        }

        let lsn = lsn_res.unwrap();

        if lsn > stable_lsn {
            to_remove.push(path);
        }
    }

    if !to_remove.is_empty() {
        warn!(
            "removing {} blobs that have \
             a higher lsn than our stable log: {:?}",
            to_remove.len(),
            stable
        );
    }

    for path in to_remove {
        std::fs::remove_file(&path)?;
    }

    Ok(())
}

pub(crate) fn remove_blob(id: Lsn, config: &Config) -> Result<()> {
    let path = config.blob_path(id);
    if let Err(e) = std::fs::remove_file(&path) {
        debug!("removing blob at {:?} failed: {}", path, e);
    } else {
        trace!("successfully removed blob at {:?}", path);
    }

    // TODO return a future
    Ok(())
}
<commit_msg>Continue with blob gc if an unexpected file is discovered<commit_after>use crate::pagecache::*;
use crate::*;

pub(crate) fn read_blob(
    blob_ptr: Lsn,
    config: &Config,
) -> Result<(MessageKind, Vec<u8>)> {
    let path = config.blob_path(blob_ptr);
    let f_res = std::fs::OpenOptions::new().read(true).open(&path);

    if let Err(e) = &f_res {
        debug!("failed to open file for blob read at {}: {:?}", blob_ptr, e);
    }

    let mut f = f_res?;

    let mut crc_expected_bytes = [0_u8; std::mem::size_of::<u32>()];

    if let Err(e) = f.read_exact(&mut crc_expected_bytes) {
        debug!(
            "failed to read the initial CRC bytes in the blob at {}: {:?}",
            blob_ptr, e,
        );
        return Err(e.into());
    }

    let crc_expected = arr_to_u32(&crc_expected_bytes);

    let mut kind_byte = [0_u8];

    if let Err(e) = f.read_exact(&mut kind_byte) {
        debug!(
            "failed to read the initial CRC bytes in the blob at {}: {:?}",
            blob_ptr, e,
        );
        return Err(e.into());
    }

    let mut buf = vec![];

    if let Err(e) = f.read_to_end(&mut buf) {
        debug!(
            "failed to read data after the CRC bytes in blob at {}: {:?}",
            blob_ptr, e,
        );
        return Err(e.into());
    }

    let mut hasher = crc32fast::Hasher::new();
    hasher.update(&kind_byte);
    hasher.update(&buf);
    let crc_actual = hasher.finalize();

    if crc_expected == crc_actual {
        let buf =
            if config.use_compression { maybe_decompress(buf)? } else { buf };
        Ok((MessageKind::from(kind_byte[0]), buf))
    } else {
        warn!("blob {} failed crc check!", blob_ptr);

        Err(Error::Corruption { at: DiskPtr::Blob(0, blob_ptr) })
    }
}

pub(crate) fn write_blob<T: Serialize>(
    config: &Config,
    kind: MessageKind,
    id: Lsn,
    item: &T,
) -> Result<()> {
    let path = config.blob_path(id);
    let mut f =
        std::fs::OpenOptions::new().write(true).create_new(true).open(&path)?;

    let kind_buf = &[kind.into()];

    let mut hasher = crc32fast::Hasher::new();
    hasher.update(kind_buf);

    let data = {
        let _ = Measure::new(&M.serialize);
        item.serialize()
    };

    hasher.update(&data);
    let crc = u32_to_arr(hasher.finalize());

    io_fail!(config, "write_blob write crc");
    f.write_all(&crc)?;
    io_fail!(config, "write_blob write kind_byte");
    f.write_all(kind_buf)?;
    io_fail!(config, "write_blob write buf");
    f.write_all(&data)
        .map(|r| {
            trace!("successfully wrote blob at {:?}", path);
            r
        })
        .map_err(|e| e.into())
}

pub(crate) fn gc_blobs(config: &Config, stable_lsn: Lsn) -> Result<()> {
    let mut base_dir = config.get_path();
    base_dir.push("blobs");
    let blob_dir = base_dir;
    let blobs = std::fs::read_dir(blob_dir)?;

    debug!("gc_blobs removing any blob with an lsn above {}", stable_lsn);

    let mut to_remove = vec![];
    for blob in blobs {
        let path = blob?.path();
        let lsn_str = path.file_name().unwrap().to_str().unwrap();
        let lsn_res: std::result::Result<Lsn, _> = lsn_str.parse();

        if let Err(e) = lsn_res {
            warn!(
                "blobs directory contains \
                 unparsable path ({:?}): {}",
                path, e
            );
            continue;
        }

        let lsn = lsn_res.unwrap();

        if lsn > stable_lsn {
            to_remove.push(path);
        }
    }

    if !to_remove.is_empty() {
        warn!(
            "removing {} blobs that have \
             a higher lsn than our stable log: {:?}",
            to_remove.len(),
            stable_lsn
        );
    }

    for path in to_remove {
        std::fs::remove_file(&path)?;
    }

    Ok(())
}

pub(crate) fn remove_blob(id: Lsn, config: &Config) -> Result<()> {
    let path = config.blob_path(id);
    if let Err(e) = std::fs::remove_file(&path) {
        debug!("removing blob at {:?} failed: {}", path, e);
    } else {
        trace!("successfully removed blob at {:?}", path);
    }

    // TODO return a future
    Ok(())
}
<|endoftext|>