<commit_before>#[macro_use]
extern crate bencher;
extern crate optional;

use optional::OptionBool;

fn bench_is_some_opt(bench: &mut bencher::Bencher) {
    fn is_some_optbool() {
        for o in [
            OptionBool::SomeTrue,
            OptionBool::SomeFalse,
            OptionBool::None,
        ].iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(o.is_some());
        }
    }

    bench.iter(is_some_optbool);
}

fn bench_is_some_std(bench: &mut bencher::Bencher) {
    fn is_some_stdopt() {
        for o in [Option::Some(true), Option::Some(false), Option::None]
            .iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(o.is_some());
        }
    }

    bench.iter(is_some_stdopt);
}

fn invert(b: bool) -> bool {
    !b
}

fn bench_map_invert_opt_bool(bench: &mut bencher::Bencher) {
    fn map_invert_opt_bool() {
        for o in [
            OptionBool::SomeTrue,
            OptionBool::SomeFalse,
            OptionBool::None,
        ].iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(o.map_bool(invert));
        }
    }

    bench.iter(map_invert_opt_bool);
}

fn bench_map_invert_opt(bench: &mut bencher::Bencher) {
    fn map_invert_opt() {
        for o in [
            OptionBool::SomeTrue,
            OptionBool::SomeFalse,
            OptionBool::None,
        ].iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(o.map(invert));
        }
    }

    bench.iter(map_invert_opt);
}

fn bench_map_invert_std(bench: &mut bencher::Bencher) {
    fn map_invert_std() {
        for o in [Option::Some(true), Option::Some(false), Option::None]
            .iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(o.map(invert));
        }
    }

    bench.iter(map_invert_std);
}

fn bench_unwrap_opt(bench: &mut bencher::Bencher) {
    fn unwrap_opt() {
        for o in [OptionBool::SomeTrue, OptionBool::SomeFalse]
            .iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(o.unwrap());
        }
    }

    bench.iter(unwrap_opt);
}

fn bench_unwrap_std(bench: &mut bencher::Bencher) {
    fn unwrap_std() {
        for o in [Option::Some(true), Option::Some(false)]
            .iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(o.unwrap());
        }
    }

    bench.iter(unwrap_std);
}

fn bench_unwrap_or_opt(bench: &mut bencher::Bencher) {
    fn unwrap_or_opt() {
        for o in [
            OptionBool::SomeTrue,
            OptionBool::SomeFalse,
            OptionBool::None,
        ].iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(o.unwrap_or(false));
        }
    }

    bench.iter(unwrap_or_opt);
}

fn bench_unwrap_or_std(bench: &mut bencher::Bencher) {
    fn unwrap_or_std() {
        for o in [Option::Some(true), Option::Some(false), Option::None]
            .iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(o.unwrap_or(false));
        }
    }

    bench.iter(unwrap_or_std);
}

fn oracle() -> bool {
    true
}

fn bench_unwrap_or_else_opt(bench: &mut bencher::Bencher) {
    fn unwrap_or_else_opt() {
        for o in [
            OptionBool::SomeTrue,
            OptionBool::SomeFalse,
            OptionBool::None,
        ].iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(o.unwrap_or_else(oracle));
        }
    }

    bench.iter(unwrap_or_else_opt);
}

fn bench_unwrap_or_else_std(bench: &mut bencher::Bencher) {
    fn unwrap_or_else_std() {
        for o in [Option::Some(true), Option::Some(false), Option::None]
            .iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(o.unwrap_or_else(oracle));
        }
    }

    bench.iter(unwrap_or_else_std);
}

fn bench_map_or_opt(bench: &mut bencher::Bencher) {
    fn map_or_opt() {
        for o in [
            OptionBool::SomeTrue,
            OptionBool::SomeFalse,
            OptionBool::None,
        ].iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(o.map_or(false, invert));
        }
    }

    bench.iter(map_or_opt);
}

fn bench_map_or_std(bench: &mut bencher::Bencher) {
    fn map_or_std() {
        for o in [Option::Some(true), Option::Some(false), Option::None]
            .iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(o.map_or(false, invert));
        }
    }

    bench.iter(map_or_std);
}

fn bench_map_or_else_opt(bench: &mut bencher::Bencher) {
    fn map_or_else_opt() {
        for o in [
            OptionBool::SomeTrue,
            OptionBool::SomeFalse,
            OptionBool::None,
        ].iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(o.map_or_else(oracle, invert));
        }
    }

    bench.iter(map_or_else_opt);
}

fn bench_map_or_else_std(bench: &mut bencher::Bencher) {
    fn map_or_else_std() {
        for o in [Option::Some(true), Option::Some(false), Option::None]
            .iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(o.map_or_else(oracle, invert));
        }
    }

    bench.iter(map_or_else_std);
}

fn bench_and_opt(bench: &mut bencher::Bencher) {
    fn and_opt() {
        for o1 in [
            OptionBool::SomeTrue,
            OptionBool::SomeFalse,
            OptionBool::None,
        ].iter()
            .cycle()
            .take(33)
        {
            for o2 in [Option::Some(true), Option::Some(false), Option::None]
                .iter()
                .cycle()
                .take(33)
            {
                bencher::black_box(o1.and(*o2));
            }
        }
    }

    bench.iter(and_opt);
}

fn bench_and_bool_opt(bench: &mut bencher::Bencher) {
    fn and_bool_opt() {
        for o1 in [
            OptionBool::SomeTrue,
            OptionBool::SomeFalse,
            OptionBool::None,
        ].iter()
            .cycle()
            .take(33)
        {
            for o2 in [
                OptionBool::SomeTrue,
                OptionBool::SomeFalse,
                OptionBool::None,
            ].iter()
                .cycle()
                .take(33)
            {
                bencher::black_box(o1.and_bool(*o2));
            }
        }
    }

    bench.iter(and_bool_opt);
}

fn bench_and_std(bench: &mut bencher::Bencher) {
    fn and_std() {
        for o1 in [Option::Some(true), Option::Some(false), Option::None]
            .iter()
            .cycle()
            .take(33)
        {
            for o2 in [Option::Some(true), Option::Some(false), Option::None]
                .iter()
                .cycle()
                .take(33)
            {
                bencher::black_box(o1.and(*o2));
            }
        }
    }

    bench.iter(and_std);
}

fn bench_or_opt(bench: &mut bencher::Bencher) {
    fn or_opt() {
        for o1 in [
            OptionBool::SomeTrue,
            OptionBool::SomeFalse,
            OptionBool::None,
        ].iter()
            .cycle()
            .take(33)
        {
            for o2 in [Option::Some(true), Option::Some(false), Option::None]
                .iter()
                .cycle()
                .take(33)
            {
                bencher::black_box(o1.or(*o2));
            }
        }
    }

    bench.iter(or_opt);
}

fn bench_or_bool_opt(bench: &mut bencher::Bencher) {
    fn or_bool_opt() {
        for o1 in [
            OptionBool::SomeTrue,
            OptionBool::SomeFalse,
            OptionBool::None,
        ].iter()
            .cycle()
            .take(33)
        {
            for o2 in [
                OptionBool::SomeTrue,
                OptionBool::SomeFalse,
                OptionBool::None,
            ].iter()
                .cycle()
                .take(33)
            {
                bencher::black_box(o1.or_bool(*o2));
            }
        }
    }

    bench.iter(or_bool_opt);
}

fn bench_or_std(bench: &mut bencher::Bencher) {
    fn or_std() {
        for o1 in [Option::Some(true), Option::Some(false), Option::None]
            .iter()
            .cycle()
            .take(33)
        {
            for o2 in [Option::Some(true), Option::Some(false), Option::None]
                .iter()
                .cycle()
                .take(33)
            {
                bencher::black_box(o1.or(*o2));
            }
        }
    }

    bench.iter(or_std);
}

fn create_std() -> Option<bool> {
    Some(false)
}

fn create_opt() -> OptionBool {
    OptionBool::SomeFalse
}

fn bench_or_else_opt(bench: &mut bencher::Bencher) {
    fn or_else_opt() {
        for o in [
            OptionBool::SomeTrue,
            OptionBool::SomeFalse,
            OptionBool::None,
        ].iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(o.or_else(create_std));
        }
    }

    bench.iter(or_else_opt);
}

fn bench_or_else_bool_opt(bench: &mut bencher::Bencher) {
    fn or_else_bool_opt() {
        for o in [
            OptionBool::SomeTrue,
            OptionBool::SomeFalse,
            OptionBool::None,
        ].iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(o.or_else_bool(create_opt));
        }
    }

    bench.iter(or_else_bool_opt);
}

fn bench_or_else_std(bench: &mut bencher::Bencher) {
    fn or_else_std() {
        for o in [Option::Some(true), Option::Some(false), Option::None]
            .iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(o.or_else(create_std));
        }
    }

    bench.iter(or_else_std);
}

fn bench_iter_opt(bench: &mut bencher::Bencher) {
    fn iter_opt() {
        for o in [
            OptionBool::SomeTrue,
            OptionBool::SomeFalse,
            OptionBool::None,
        ].iter()
            .cycle()
            .take(1200)
        {
            for b in o.iter() {
                bencher::black_box(b);
            }
        }
    }

    bench.iter(iter_opt);
}

fn bench_as_slice_iter_opt(bench: &mut bencher::Bencher) {
    fn as_slice_iter_opt() {
        for o in [
            OptionBool::SomeTrue,
            OptionBool::SomeFalse,
            OptionBool::None,
        ].iter()
            .cycle()
            .take(1200)
        {
            for b in o[..].iter() {
                bencher::black_box(b);
            }
        }
    }

    bench.iter(as_slice_iter_opt);
}

fn bench_iter_std(bench: &mut bencher::Bencher) {
    fn iter_std() {
        for o in [Option::Some(true), Option::Some(false), Option::None]
            .iter()
            .cycle()
            .take(1200)
        {
            for b in o.iter() {
                bencher::black_box(b);
            }
        }
    }

    bench.iter(iter_std);
}

fn bench_as_slice_opt(bench: &mut bencher::Bencher) {
    fn as_slice_opt() {
        for o in [
            OptionBool::SomeTrue,
            OptionBool::SomeFalse,
            OptionBool::None,
        ].iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(o);
        }
    }

    bench.iter(as_slice_opt);
}

fn bench_from_opt(bench: &mut bencher::Bencher) {
    fn from_opt() {
        for o in [Option::Some(true), Option::Some(false), Option::None]
            .iter()
            .cycle()
            .take(1200)
        {
            let o2: OptionBool = o.into();
            bencher::black_box(o2);
        }
    }

    bench.iter(from_opt);
}

fn bench_to_opt(bench: &mut bencher::Bencher) {
    fn to_opt() {
        for o in [
            OptionBool::SomeTrue,
            OptionBool::SomeFalse,
            OptionBool::None,
        ].iter()
            .cycle()
            .take(1200)
        {
            let o2: Option<bool> = o.into();
            bencher::black_box(o2);
        }
    }

    bench.iter(to_opt);
}

benchmark_group!(
    bench,
    bench_is_some_opt,
    bench_is_some_std,
    bench_map_invert_opt_bool,
    bench_map_invert_opt,
    bench_map_invert_std,
    bench_unwrap_opt,
    bench_unwrap_std,
    bench_unwrap_or_opt,
    bench_unwrap_or_std,
    bench_unwrap_or_else_opt,
    bench_unwrap_or_else_std,
    bench_map_or_opt,
    bench_map_or_std,
    bench_map_or_else_opt,
    bench_map_or_else_std,
    bench_and_opt,
    bench_and_bool_opt,
    bench_and_std,
    bench_or_opt,
    bench_or_bool_opt,
    bench_or_std,
    bench_or_else_opt,
    bench_or_else_bool_opt,
    bench_or_else_std,
    bench_iter_opt,
    bench_as_slice_iter_opt,
    bench_iter_std,
    bench_as_slice_opt,
    bench_from_opt,
    bench_to_opt
);

benchmark_main!(bench);
<commit_msg>Update optbool benchmarks with appropriate black_boxes<commit_after>#[macro_use]
extern crate bencher;
extern crate optional;

use optional::OptionBool;

fn bench_is_some_opt(bench: &mut bencher::Bencher) {
    fn is_some_optbool() {
        for o in [
            OptionBool::SomeTrue,
            OptionBool::SomeFalse,
            OptionBool::None,
        ].iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(bencher::black_box(o).is_some());
        }
    }

    bench.iter(is_some_optbool);
}

fn bench_is_some_std(bench: &mut bencher::Bencher) {
    fn is_some_stdopt() {
        for o in [Option::Some(true), Option::Some(false), Option::None]
            .iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(bencher::black_box(o).is_some());
        }
    }

    bench.iter(is_some_stdopt);
}

fn invert(b: bool) -> bool {
    !b
}

fn bench_map_invert_opt_bool(bench: &mut bencher::Bencher) {
    fn map_invert_opt_bool() {
        for o in [
            OptionBool::SomeTrue,
            OptionBool::SomeFalse,
            OptionBool::None,
        ].iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(bencher::black_box(o).map_bool(invert));
        }
    }

    bench.iter(map_invert_opt_bool);
}

fn bench_map_invert_opt(bench: &mut bencher::Bencher) {
    fn map_invert_opt() {
        for o in [
            OptionBool::SomeTrue,
            OptionBool::SomeFalse,
            OptionBool::None,
        ].iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(bencher::black_box(o).map(invert));
        }
    }

    bench.iter(map_invert_opt);
}

fn bench_map_invert_std(bench: &mut bencher::Bencher) {
    fn map_invert_std() {
        for o in [Option::Some(true), Option::Some(false), Option::None]
            .iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(bencher::black_box(o).map(invert));
        }
    }

    bench.iter(map_invert_std);
}

fn bench_unwrap_opt(bench: &mut bencher::Bencher) {
    fn unwrap_opt() {
        for o in [OptionBool::SomeTrue, OptionBool::SomeFalse]
            .iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(bencher::black_box(o).unwrap());
        }
    }

    bench.iter(unwrap_opt);
}

fn bench_unwrap_std(bench: &mut bencher::Bencher) {
    fn unwrap_std() {
        for o in [Option::Some(true), Option::Some(false)]
            .iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(bencher::black_box(o).unwrap());
        }
    }

    bench.iter(unwrap_std);
}

fn bench_unwrap_or_opt(bench: &mut bencher::Bencher) {
    fn unwrap_or_opt() {
        for o in [
            OptionBool::SomeTrue,
            OptionBool::SomeFalse,
            OptionBool::None,
        ].iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(bencher::black_box(o).unwrap_or(false));
        }
    }

    bench.iter(unwrap_or_opt);
}

fn bench_unwrap_or_std(bench: &mut bencher::Bencher) {
    fn unwrap_or_std() {
        for o in [Option::Some(true), Option::Some(false), Option::None]
            .iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(bencher::black_box(o).unwrap_or(false));
        }
    }

    bench.iter(unwrap_or_std);
}

fn oracle() -> bool {
    true
}

fn bench_unwrap_or_else_opt(bench: &mut bencher::Bencher) {
    fn unwrap_or_else_opt() {
        for o in [
            OptionBool::SomeTrue,
            OptionBool::SomeFalse,
            OptionBool::None,
        ].iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(bencher::black_box(o).unwrap_or_else(oracle));
        }
    }

    bench.iter(unwrap_or_else_opt);
}

fn bench_unwrap_or_else_std(bench: &mut bencher::Bencher) {
    fn unwrap_or_else_std() {
        for o in [Option::Some(true), Option::Some(false), Option::None]
            .iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(bencher::black_box(o).unwrap_or_else(oracle));
        }
    }

    bench.iter(unwrap_or_else_std);
}

fn bench_map_or_opt(bench: &mut bencher::Bencher) {
    fn map_or_opt() {
        for o in [
            OptionBool::SomeTrue,
            OptionBool::SomeFalse,
            OptionBool::None,
        ].iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(bencher::black_box(o).map_or(false, invert));
        }
    }

    bench.iter(map_or_opt);
}

fn bench_map_or_std(bench: &mut bencher::Bencher) {
    fn map_or_std() {
        for o in [Option::Some(true), Option::Some(false), Option::None]
            .iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(bencher::black_box(o).map_or(false, invert));
        }
    }

    bench.iter(map_or_std);
}

fn bench_map_or_else_opt(bench: &mut bencher::Bencher) {
    fn map_or_else_opt() {
        for o in [
            OptionBool::SomeTrue,
            OptionBool::SomeFalse,
            OptionBool::None,
        ].iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(bencher::black_box(o).map_or_else(oracle, invert));
        }
    }

    bench.iter(map_or_else_opt);
}

fn bench_map_or_else_std(bench: &mut bencher::Bencher) {
    fn map_or_else_std() {
        for o in [Option::Some(true), Option::Some(false), Option::None]
            .iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(bencher::black_box(o).map_or_else(oracle, invert));
        }
    }

    bench.iter(map_or_else_std);
}

fn bench_and_opt(bench: &mut bencher::Bencher) {
    fn and_opt() {
        for o1 in [
            OptionBool::SomeTrue,
            OptionBool::SomeFalse,
            OptionBool::None,
        ].iter()
            .cycle()
            .take(33)
        {
            for o2 in [Option::Some(true), Option::Some(false), Option::None]
                .iter()
                .cycle()
                .take(33)
            {
                bencher::black_box(bencher::black_box(o1).and(bencher::black_box(*o2)));
            }
        }
    }

    bench.iter(and_opt);
}

fn bench_and_bool_opt(bench: &mut bencher::Bencher) {
    fn and_bool_opt() {
        for o1 in [
            OptionBool::SomeTrue,
            OptionBool::SomeFalse,
            OptionBool::None,
        ].iter()
            .cycle()
            .take(33)
        {
            for o2 in [
                OptionBool::SomeTrue,
                OptionBool::SomeFalse,
                OptionBool::None,
            ].iter()
                .cycle()
                .take(33)
            {
                bencher::black_box(bencher::black_box(o1).and_bool(bencher::black_box(*o2)));
            }
        }
    }

    bench.iter(and_bool_opt);
}

fn bench_and_std(bench: &mut bencher::Bencher) {
    fn and_std() {
        for o1 in [Option::Some(true), Option::Some(false), Option::None]
            .iter()
            .cycle()
            .take(33)
        {
            for o2 in [Option::Some(true), Option::Some(false), Option::None]
                .iter()
                .cycle()
                .take(33)
            {
                bencher::black_box(bencher::black_box(o1).and(bencher::black_box(*o2)));
            }
        }
    }

    bench.iter(and_std);
}

fn bench_or_opt(bench: &mut bencher::Bencher) {
    fn or_opt() {
        for o1 in [
            OptionBool::SomeTrue,
            OptionBool::SomeFalse,
            OptionBool::None,
        ].iter()
            .cycle()
            .take(33)
        {
            for o2 in [Option::Some(true), Option::Some(false), Option::None]
                .iter()
                .cycle()
                .take(33)
            {
                bencher::black_box(bencher::black_box(o1).or(bencher::black_box(*o2)));
            }
        }
    }

    bench.iter(or_opt);
}

fn bench_or_bool_opt(bench: &mut bencher::Bencher) {
    fn or_bool_opt() {
        for o1 in [
            OptionBool::SomeTrue,
            OptionBool::SomeFalse,
            OptionBool::None,
        ].iter()
            .cycle()
            .take(33)
        {
            for o2 in [
                OptionBool::SomeTrue,
                OptionBool::SomeFalse,
                OptionBool::None,
            ].iter()
                .cycle()
                .take(33)
            {
                bencher::black_box(bencher::black_box(o1).or_bool(bencher::black_box(*o2)));
            }
        }
    }

    bench.iter(or_bool_opt);
}

fn bench_or_std(bench: &mut bencher::Bencher) {
    fn or_std() {
        for o1 in [Option::Some(true), Option::Some(false), Option::None]
            .iter()
            .cycle()
            .take(33)
        {
            for o2 in [Option::Some(true), Option::Some(false), Option::None]
                .iter()
                .cycle()
                .take(33)
            {
                bencher::black_box(bencher::black_box(o1).or(bencher::black_box(*o2)));
            }
        }
    }

    bench.iter(or_std);
}

fn create_std() -> Option<bool> {
    Some(false)
}

fn create_opt() -> OptionBool {
    OptionBool::SomeFalse
}

fn bench_or_else_opt(bench: &mut bencher::Bencher) {
    fn or_else_opt() {
        for o in [
            OptionBool::SomeTrue,
            OptionBool::SomeFalse,
            OptionBool::None,
        ].iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(bencher::black_box(o).or_else(create_std));
        }
    }

    bench.iter(or_else_opt);
}

fn bench_or_else_bool_opt(bench: &mut bencher::Bencher) {
    fn or_else_bool_opt() {
        for o in [
            OptionBool::SomeTrue,
            OptionBool::SomeFalse,
            OptionBool::None,
        ].iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(bencher::black_box(o).or_else_bool(create_opt));
        }
    }

    bench.iter(or_else_bool_opt);
}

fn bench_or_else_std(bench: &mut bencher::Bencher) {
    fn or_else_std() {
        for o in [Option::Some(true), Option::Some(false), Option::None]
            .iter()
            .cycle()
            .take(1200)
        {
            bencher::black_box(bencher::black_box(o).or_else(create_std));
        }
    }

    bench.iter(or_else_std);
}

fn bench_iter_opt(bench: &mut bencher::Bencher) {
    fn iter_opt() {
        for o in [
            OptionBool::SomeTrue,
            OptionBool::SomeFalse,
            OptionBool::None,
        ].iter()
            .cycle()
            .take(1200)
        {
            for b in o.iter() {
                bencher::black_box(b);
            }
        }
    }

    bench.iter(iter_opt);
}

fn bench_as_slice_iter_opt(bench: &mut bencher::Bencher) {
    fn as_slice_iter_opt() {
        for o in [
            OptionBool::SomeTrue,
            OptionBool::SomeFalse,
            OptionBool::None,
        ].iter()
            .cycle()
            .take(1200)
        {
            for b in o[..].iter() {
                bencher::black_box(b);
            }
        }
    }

    bench.iter(as_slice_iter_opt);
}

fn bench_iter_std(bench: &mut bencher::Bencher) {
    fn iter_std() {
        for o in [Option::Some(true), Option::Some(false), Option::None]
            .iter()
            .cycle()
            .take(1200)
        {
            for b in o.iter() {
                bencher::black_box(b);
            }
        }
    }

    bench.iter(iter_std);
}

fn bench_from_opt(bench: &mut bencher::Bencher) {
    fn from_opt() {
        for o in [Option::Some(true), Option::Some(false), Option::None]
            .iter()
            .cycle()
            .take(1200)
        {
            let o2: OptionBool = o.into();
            bencher::black_box(o2);
        }
    }

    bench.iter(from_opt);
}

fn bench_to_opt(bench: &mut bencher::Bencher) {
    fn to_opt() {
        for o in [
            OptionBool::SomeTrue,
            OptionBool::SomeFalse,
            OptionBool::None,
        ].iter()
            .cycle()
            .take(1200)
        {
            let o2: Option<bool> = o.into();
            bencher::black_box(o2);
        }
    }

    bench.iter(to_opt);
}

benchmark_group!(
    bench,
    bench_is_some_opt,
    bench_is_some_std,
    bench_map_invert_opt_bool,
    bench_map_invert_opt,
    bench_map_invert_std,
    bench_unwrap_opt,
    bench_unwrap_std,
    bench_unwrap_or_opt,
    bench_unwrap_or_std,
    bench_unwrap_or_else_opt,
    bench_unwrap_or_else_std,
    bench_map_or_opt,
    bench_map_or_std,
    bench_map_or_else_opt,
    bench_map_or_else_std,
    bench_and_opt,
    bench_and_bool_opt,
    bench_and_std,
    bench_or_opt,
    bench_or_bool_opt,
    bench_or_std,
    bench_or_else_opt,
    bench_or_else_bool_opt,
    bench_or_else_std,
    bench_iter_opt,
    bench_as_slice_iter_opt,
    bench_iter_std,
    bench_from_opt,
    bench_to_opt
);

benchmark_main!(bench);
<|endoftext|>


<commit_before>use geometry::{BBox, Prim};
use material::Material;
use raytracer::{Ray, Intersection};
use vec3::Vec3;

#[allow(dead_code)]
// Plane is defined as N dot D
pub struct Plane {
    pub a: f64, // normal.x
    pub b: f64, // normal.y
    pub c: f64, // normal.z
    pub d: f64,
    pub material: Box<Material+Send+Share>
}

impl Prim for Plane {
    fn intersects<'a>(&'a self, ray: &Ray, t_min: f64, t_max: f64) -> Option<Intersection<'a>> {
        let n = Vec3 {x: self.a, y: self.b, z: self.c};
        let nrd = n.dot(&ray.direction);
        let nro = n.dot(&ray.origin);
        let t = (-self.d - nro) / nrd;

        if t < t_min || t > t_max {
            None
        } else {
            let intersection_point = ray.origin + ray.direction.scale(t);

            let u_axis = Vec3 {x: n.y, y: n.z, z: -n.x};
            let v_axis = u_axis.cross(&n);
            let u = intersection_point.dot(&u_axis);
            let v = intersection_point.dot(&v_axis);

            Some(Intersection {
                n: n,
                t: t,
                u: u,
                v: v,
                position: intersection_point,
                material: &self.material
            })
        }
    }

    fn bounding(&self) -> Option<BBox> {
        None // more infinite than infinityb
    }
}
<commit_msg>Add tests to Plane<commit_after>use geometry::{BBox, Prim};
use material::Material;
use raytracer::{Ray, Intersection};
use vec3::Vec3;

#[cfg(test)]
use material::materials::FlatMaterial;

#[allow(dead_code)]
// Plane is defined as N dot D
pub struct Plane {
    pub a: f64, // normal.x
    pub b: f64, // normal.y
    pub c: f64, // normal.z
    pub d: f64,
    pub material: Box<Material+Send+Share>
}

impl Prim for Plane {
    fn intersects<'a>(&'a self, ray: &Ray, t_min: f64, t_max: f64) -> Option<Intersection<'a>> {
        let n = Vec3 {x: self.a, y: self.b, z: self.c};
        let nrd = n.dot(&ray.direction);
        let nro = n.dot(&ray.origin);
        let t = (-self.d - nro) / nrd;

        if t < t_min || t > t_max {
            None
        } else {
            let intersection_point = ray.origin + ray.direction.scale(t);

            let u_axis = Vec3 {x: n.y, y: n.z, z: -n.x};
            let v_axis = u_axis.cross(&n);
            let u = intersection_point.dot(&u_axis);
            let v = intersection_point.dot(&v_axis);

            Some(Intersection {
                n: n,
                t: t,
                u: u,
                v: v,
                position: intersection_point,
                material: &self.material
            })
        }
    }

    fn bounding(&self) -> Option<BBox> {
        None // more infinite than infinityb
    }
}

#[test]
fn it_intersects() {
    let plane = Plane {a: 0.0, b: 1.0, c: 0.0, d: 0.0, material: box FlatMaterial {color: Vec3::one()}};

    // Tests actual intersection
    let intersecting_ray = Ray::new(Vec3 {x: 0.0, y: 1.0, z: 0.0}, Vec3 {x: 0.0, y: -1.0, z: 0.0});
    let intersection = plane.intersects(&intersecting_ray, 0.0, 10.0).unwrap();
    assert_eq!(intersection.position.x, 0.0);
    assert_eq!(intersection.position.y, 0.0);
    assert_eq!(intersection.position.z, 0.0);
    assert_eq!(intersection.n.x, 0.0);
    assert_eq!(intersection.n.y, 1.0);
    assert_eq!(intersection.n.z, 0.0);

    // Parallel ray
    let mut non_intersecting_ray = Ray::new(Vec3 {x: 0.0, y: 1.0, z: 0.0}, Vec3 {x: 1.0, y: 0.0, z: 1.0});
    let mut non_intersection = plane.intersects(&non_intersecting_ray, 0.0, 10000.0);
    assert!(non_intersection.is_none());

    // Ray in opposite direction
    non_intersecting_ray = Ray::new(Vec3 {x: 0.0, y: 1.0, z: 0.0}, Vec3 {x: 0.0, y: 1.0, z: 0.0});
    non_intersection = plane.intersects(&non_intersecting_ray, 0.0, 10.0);
    assert!(non_intersection.is_none());
}

#[test]
fn it_intersects_only_in_tmin_tmax() {
    let plane = Plane {a: 0.0, b: 1.0, c: 0.0, d: 0.0, material: box FlatMaterial {color: Vec3::one()}};

    // Tests tmin
    let intersecting_ray = Ray::new(Vec3 {x: 0.0, y: 1.0, z: 0.0}, Vec3 {x: 0.0, y: -1.0, z: 0.0});
    let mut non_intersection = plane.intersects(&intersecting_ray, 1000.0, 10000.0);
    assert!(non_intersection.is_none());

    // Tests tmax
    non_intersection = plane.intersects(&intersecting_ray, 0.0, 0.0001);
    assert!(non_intersection.is_none());
}
<|endoftext|>


<commit_before>/* diosix virtual CPU core management
 *
 * (c) Chris Williams, 2018-2019.
 *
 * See LICENSE for usage and copying.
 */

use super::error::Cause;
use super::capsule::CapsuleID;
use super::scheduler;
use platform::cpu::{SupervisorState, Entry};
use platform::physmem::PhysMemBase;
use platform::timer;

#[derive(Copy, Clone, Debug)]
pub enum Priority
{
    High,
    Normal
}

/* virtual core ID unique to its capsule */
pub type VirtualCoreID = usize;

/* pair a virtual core with its parent capsule using their ID numbers */
#[derive(PartialEq, Eq, Hash)]
pub struct VirtualCoreCanonicalID
{
    pub capsuleid: CapsuleID,
    pub vcoreid: VirtualCoreID
}

/* a virtual core is either in a waiting queue awaiting physical CPU time, or is running and held in a physical CPU core struct.
if you remove a virtual core object from the queue and don't place it back in a queue or Core structure,
then the vcpu will be dropped, deallocated and destroyed. */
pub struct VirtualCore
{
    id: VirtualCoreCanonicalID,
    priority: Priority,
    state: SupervisorState,
    timer_irq_at: Option<timer::TimerValue>
}

impl VirtualCore
{
    /* create a virtual CPU core for a supervisor capsule
       => capsule = ID of the capsule
          core = virtual core ID within the capsule
          entry = pointer to where to begin execution
          dtb = physical address of the device tree blob
                describing the virtual CPU's hardware environment
          priority = virtual core's priority
       <= OK for success, or error code */
    pub fn create(capsuleid: CapsuleID, core: VirtualCoreID, entry: Entry, dtb: PhysMemBase, priority: Priority) -> Result<(), Cause>
    {
        let new_vcore = VirtualCore
        {
            id: VirtualCoreCanonicalID
            {
                capsuleid,
                vcoreid: core
            },
            priority,
            state: platform::cpu::init_supervisor_state(core, entry, dtb),
            timer_irq_at: None
        };

        /* add virtual CPU core to the global waiting list queue */
        scheduler::queue(new_vcore);
        Ok(())
    }

    /* return reference to virtual CPU core's physical CPU state */
    pub fn state_as_ref(&self) -> &SupervisorState
    {
        &self.state
    }

    /* return this virtual core's ID within its capsule */
    pub fn get_id(&self) -> VirtualCoreID { self.id.vcoreid }

    /* return virtual CPU core capsule's ID */
    pub fn get_capsule_id(&self) -> CapsuleID { self.id.capsuleid }

    /* return virtual CPU core's priority */
    pub fn get_priority(&self) -> Priority { self.priority }

    /* define value the next timer IRQ should fire for this core.
    measured as value of the clock-on-the-wall for the system, or None for no IRQ */
    pub fn set_timer_irq_at(&mut self, target: Option<timer::TimerValue>)
    {
        self.timer_irq_at = target;
    }

    /* return timer value after which a per-CPU timer IRQ will fire for this core, or None for no IRQ */
    pub fn get_timer_irq_at(&mut self) -> Option<timer::TimerValue>
    {
        self.timer_irq_at
    }
}
<commit_msg>Keep track of a capsule's max vCPU count<commit_after>/* diosix virtual CPU core management
 *
 * (c) Chris Williams, 2018-2019.
 *
 * See LICENSE for usage and copying.
 */

use super::error::Cause;
use super::capsule::{self, CapsuleID};
use super::scheduler;
use platform::cpu::{SupervisorState, Entry};
use platform::physmem::PhysMemBase;
use platform::timer;

#[derive(Copy, Clone, Debug)]
pub enum Priority
{
    High,
    Normal
}

/* virtual core ID unique to its capsule */
pub type VirtualCoreID = usize;

/* pair a virtual core with its parent capsule using their ID numbers */
#[derive(PartialEq, Eq, Hash)]
pub struct VirtualCoreCanonicalID
{
    pub capsuleid: CapsuleID,
    pub vcoreid: VirtualCoreID
}

/* a virtual core is either in a waiting queue awaiting physical CPU time, or is running and held in a physical CPU core struct.
if you remove a virtual core object from the queue and don't place it back in a queue or Core structure,
then the vcpu will be dropped, deallocated and destroyed. */
pub struct VirtualCore
{
    id: VirtualCoreCanonicalID,
    priority: Priority,
    state: SupervisorState,
    timer_irq_at: Option<timer::TimerValue>
}

impl VirtualCore
{
    /* create a virtual CPU core for a supervisor capsule
       => capsule = ID of the capsule
          core = virtual core ID within the capsule
          entry = pointer to where to begin execution
          dtb = physical address of the device tree blob
                describing the virtual CPU's hardware environment
          priority = virtual core's priority
       <= OK for success, or error code */
    pub fn create(capsuleid: CapsuleID, core: VirtualCoreID, entry: Entry, dtb: PhysMemBase, priority: Priority) -> Result<(), Cause>
    {
        let max_vcores = capsule::get_max_vcores(capsuleid)?;

        let new_vcore = VirtualCore
        {
            id: VirtualCoreCanonicalID
            {
                capsuleid,
                vcoreid: core
            },
            priority,
            state: platform::cpu::init_supervisor_state(core, max_vcores, entry, dtb),
            timer_irq_at: None
        };

        /* add virtual CPU core to the global waiting list queue */
        scheduler::queue(new_vcore);
        Ok(())
    }

    /* return reference to virtual CPU core's physical CPU state */
    pub fn state_as_ref(&self) -> &SupervisorState
    {
        &self.state
    }

    /* return this virtual core's ID within its capsule */
    pub fn get_id(&self) -> VirtualCoreID { self.id.vcoreid }

    /* return virtual CPU core capsule's ID */
    pub fn get_capsule_id(&self) -> CapsuleID { self.id.capsuleid }

    /* return virtual CPU core's priority */
    pub fn get_priority(&self) -> Priority { self.priority }

    /* define value the next timer IRQ should fire for this core.
    measured as value of the clock-on-the-wall for the system, or None for no IRQ */
    pub fn set_timer_irq_at(&mut self, target: Option<timer::TimerValue>)
    {
        self.timer_irq_at = target;
    }

    /* return timer value after which a per-CPU timer IRQ will fire for this core, or None for no IRQ */
    pub fn get_timer_irq_at(&mut self) -> Option<timer::TimerValue>
    {
        self.timer_irq_at
    }
}
<|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/. */

use dom::bindings::js::JS;
use dom::bindings::utils::{Reflectable, Reflector};

use js::jsapi::{JSObject, JSTracer, JS_CallTracer, JSTRACE_OBJECT};
use js::jsval::JSVal;

use libc;
use std::cast;
use std::cell::{Cell, RefCell};
use serialize::{Encodable, Encoder};

// IMPORTANT: We rely on the fact that we never attempt to encode DOM objects using
//            any encoder but JSTracer. Since we derive trace hooks automatically,
//            we are unfortunately required to use generic types everywhere and
//            unsafely cast to the concrete JSTracer we actually require.

fn get_jstracer<'a, S: Encoder<E>, E>(s: &'a mut S) -> &'a mut JSTracer {
    unsafe {
        cast::transmute(s)
    }
}

impl<T: Reflectable+Encodable<S, E>, S: Encoder<E>, E> Encodable<S, E> for JS<T> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        trace_reflector(get_jstracer(s), "", self.reflector());
        Ok(())
    }
}

impl<S: Encoder<E>, E> Encodable<S, E> for Reflector {
    fn encode(&self, _s: &mut S) -> Result<(), E> {
        Ok(())
    }
}

pub trait JSTraceable {
    fn trace(&self, trc: *mut JSTracer);
}

pub fn trace_jsval(tracer: *mut JSTracer, description: &str, val: JSVal) {
    if !val.is_gcthing() {
        return;
    }

    unsafe {
        description.to_c_str().with_ref(|name| {
            (*tracer).debugPrinter = None;
            (*tracer).debugPrintIndex = -1;
            (*tracer).debugPrintArg = name as *libc::c_void;
            debug!("tracing value {:s}", description);
            JS_CallTracer(tracer, val.to_gcthing(), val.trace_kind());
        });
    }
}

pub fn trace_reflector(tracer: *mut JSTracer, description: &str, reflector: &Reflector) {
    trace_object(tracer, description, reflector.get_jsobject())
}

pub fn trace_object(tracer: *mut JSTracer, description: &str, obj: *mut JSObject) {
    unsafe {
        description.to_c_str().with_ref(|name| {
            (*tracer).debugPrinter = None;
            (*tracer).debugPrintIndex = -1;
            (*tracer).debugPrintArg = name as *libc::c_void;
            debug!("tracing {:s}", description);
            JS_CallTracer(tracer, obj as *mut libc::c_void, JSTRACE_OBJECT);
        });
    }
}

/// Encapsulates a type that cannot easily have Encodable derived automagically,
/// but also does not need to be made known to the SpiderMonkey garbage collector.
/// Use only with types that are not associated with a JS reflector and do not contain
/// fields of types associated with JS reflectors.
pub struct Untraceable<T> {
    inner: T,
}

impl<T> Untraceable<T> {
    pub fn new(val: T) -> Untraceable<T> {
        Untraceable {
            inner: val
        }
    }
}

impl<S: Encoder<E>, E, T> Encodable<S, E> for Untraceable<T> {
    fn encode(&self, _s: &mut S) -> Result<(), E> {
        Ok(())
    }
}

impl<T> Deref<T> for Untraceable<T> {
    fn deref<'a>(&'a self) -> &'a T {
        &self.inner
    }
}

impl<T> DerefMut<T> for Untraceable<T> {
    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
        &mut self.inner
    }
}

/// Encapsulates a type that can be traced but is boxed in a type we don't control
/// (such as RefCell). Wrap a field in Traceable and implement the Encodable trait
/// for that new concrete type to achieve magic compiler-derived trace hooks.
#[deriving(Eq, Clone)]
pub struct Traceable<T> {
    inner: T
}

impl<T> Traceable<T> {
    pub fn new(val: T) -> Traceable<T> {
        Traceable {
            inner: val
        }
    }
}

impl<T> Deref<T> for Traceable<T> {
    fn deref<'a>(&'a self) -> &'a T {
        &self.inner
    }
}

impl<T> DerefMut<T> for Traceable<T> {
    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
        &mut self.inner
    }
}

impl<S: Encoder<E>, E, T: Encodable<S, E>> Encodable<S, E> for Traceable<RefCell<T>> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        self.borrow().encode(s)
    }
}

impl<S: Encoder<E>, E, T: Encodable<S, E>+Copy> Encodable<S, E> for Traceable<Cell<T>> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        self.deref().get().encode(s)
    }
}

impl<S: Encoder<E>, E> Encodable<S, E> for Traceable<*mut JSObject> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        trace_object(get_jstracer(s), "object", **self);
        Ok(())
    }
}

impl<S: Encoder<E>, E> Encodable<S, E> for Traceable<JSVal> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        trace_jsval(get_jstracer(s), "val", **self);
        Ok(())
    }
}

/// for a field which contains DOMType
impl<T: Reflectable+Encodable<S, E>, S: Encoder<E>, E> Encodable<S, E> for Cell<JS<T>> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        self.get().encode(s)
    }
}

/// for a field which contains non-POD type contains DOMType
impl<T: Reflectable+Encodable<S, E>, S: Encoder<E>, E> Encodable<S, E> for RefCell<Vec<JS<T>>> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        self.borrow().encode(s)
    }
}
<commit_msg>Make 'Cell<Option<JS<T>>>' traceable.<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/. */

use dom::bindings::js::JS;
use dom::bindings::utils::{Reflectable, Reflector};

use js::jsapi::{JSObject, JSTracer, JS_CallTracer, JSTRACE_OBJECT};
use js::jsval::JSVal;

use libc;
use std::cast;
use std::cell::{Cell, RefCell};
use serialize::{Encodable, Encoder};

// IMPORTANT: We rely on the fact that we never attempt to encode DOM objects using
//            any encoder but JSTracer. Since we derive trace hooks automatically,
//            we are unfortunately required to use generic types everywhere and
//            unsafely cast to the concrete JSTracer we actually require.

fn get_jstracer<'a, S: Encoder<E>, E>(s: &'a mut S) -> &'a mut JSTracer {
    unsafe {
        cast::transmute(s)
    }
}

impl<T: Reflectable+Encodable<S, E>, S: Encoder<E>, E> Encodable<S, E> for JS<T> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        trace_reflector(get_jstracer(s), "", self.reflector());
        Ok(())
    }
}

impl<S: Encoder<E>, E> Encodable<S, E> for Reflector {
    fn encode(&self, _s: &mut S) -> Result<(), E> {
        Ok(())
    }
}

pub trait JSTraceable {
    fn trace(&self, trc: *mut JSTracer);
}

pub fn trace_jsval(tracer: *mut JSTracer, description: &str, val: JSVal) {
    if !val.is_gcthing() {
        return;
    }

    unsafe {
        description.to_c_str().with_ref(|name| {
            (*tracer).debugPrinter = None;
            (*tracer).debugPrintIndex = -1;
            (*tracer).debugPrintArg = name as *libc::c_void;
            debug!("tracing value {:s}", description);
            JS_CallTracer(tracer, val.to_gcthing(), val.trace_kind());
        });
    }
}

pub fn trace_reflector(tracer: *mut JSTracer, description: &str, reflector: &Reflector) {
    trace_object(tracer, description, reflector.get_jsobject())
}

pub fn trace_object(tracer: *mut JSTracer, description: &str, obj: *mut JSObject) {
    unsafe {
        description.to_c_str().with_ref(|name| {
            (*tracer).debugPrinter = None;
            (*tracer).debugPrintIndex = -1;
            (*tracer).debugPrintArg = name as *libc::c_void;
            debug!("tracing {:s}", description);
            JS_CallTracer(tracer, obj as *mut libc::c_void, JSTRACE_OBJECT);
        });
    }
}

/// Encapsulates a type that cannot easily have Encodable derived automagically,
/// but also does not need to be made known to the SpiderMonkey garbage collector.
/// Use only with types that are not associated with a JS reflector and do not contain
/// fields of types associated with JS reflectors.
pub struct Untraceable<T> {
    inner: T,
}

impl<T> Untraceable<T> {
    pub fn new(val: T) -> Untraceable<T> {
        Untraceable {
            inner: val
        }
    }
}

impl<S: Encoder<E>, E, T> Encodable<S, E> for Untraceable<T> {
    fn encode(&self, _s: &mut S) -> Result<(), E> {
        Ok(())
    }
}

impl<T> Deref<T> for Untraceable<T> {
    fn deref<'a>(&'a self) -> &'a T {
        &self.inner
    }
}

impl<T> DerefMut<T> for Untraceable<T> {
    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
        &mut self.inner
    }
}

/// Encapsulates a type that can be traced but is boxed in a type we don't control
/// (such as RefCell). Wrap a field in Traceable and implement the Encodable trait
/// for that new concrete type to achieve magic compiler-derived trace hooks.
#[deriving(Eq, Clone)]
pub struct Traceable<T> {
    inner: T
}

impl<T> Traceable<T> {
    pub fn new(val: T) -> Traceable<T> {
        Traceable {
            inner: val
        }
    }
}

impl<T> Deref<T> for Traceable<T> {
    fn deref<'a>(&'a self) -> &'a T {
        &self.inner
    }
}

impl<T> DerefMut<T> for Traceable<T> {
    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
        &mut self.inner
    }
}

impl<S: Encoder<E>, E, T: Encodable<S, E>> Encodable<S, E> for Traceable<RefCell<T>> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        self.borrow().encode(s)
    }
}

impl<S: Encoder<E>, E, T: Encodable<S, E>+Copy> Encodable<S, E> for Traceable<Cell<T>> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        self.deref().get().encode(s)
    }
}

impl<S: Encoder<E>, E> Encodable<S, E> for Traceable<*mut JSObject> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        trace_object(get_jstracer(s), "object", **self);
        Ok(())
    }
}

impl<S: Encoder<E>, E> Encodable<S, E> for Traceable<JSVal> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        trace_jsval(get_jstracer(s), "val", **self);
        Ok(())
    }
}

/// for a field which contains DOMType
impl<T: Reflectable+Encodable<S, E>, S: Encoder<E>, E> Encodable<S, E> for Cell<JS<T>> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        self.get().encode(s)
    }
}

impl<T: Reflectable+Encodable<S, E>, S: Encoder<E>, E> Encodable<S, E> for Cell<Option<JS<T>>> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        self.get().encode(s)
    }
}

/// for a field which contains non-POD type contains DOMType
impl<T: Reflectable+Encodable<S, E>, S: Encoder<E>, E> Encodable<S, E> for RefCell<Vec<JS<T>>> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        self.borrow().encode(s)
    }
}
<|endoftext|>


<commit_before>// Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

use std::fs::File;
use std::marker::PhantomData;
use std::os::unix::io::AsRawFd;

use io_uring::{
    operation::{Cqe, Operation},
    Error as IoUringError, IoUring,
};

use utils::eventfd::EventFd;
use vm_memory::{mark_dirty_mem, GuestAddress, GuestMemory, GuestMemoryMmap};

use crate::virtio::block::io::UserDataError;
use crate::virtio::block::IO_URING_NUM_ENTRIES;

#[derive(Debug)]
pub enum Error {
    IO(std::io::Error),
    IoUring(IoUringError),
    Submit(std::io::Error),
    SyncAll(std::io::Error),
    EventFd(std::io::Error),
    GuestMemory(vm_memory::GuestMemoryError),
}

pub struct AsyncFileEngine<T> {
    file: File,
    ring: IoUring,
    completion_evt: EventFd,
    phantom: PhantomData<T>,
}

pub struct WrappedUserData<T> {
    addr: Option<GuestAddress>,
    user_data: T,
}

impl<T> WrappedUserData<T> {
    fn new(user_data: T) -> Self {
        WrappedUserData {
            addr: None,
            user_data,
        }
    }

    fn new_with_dirty_tracking(addr: GuestAddress, user_data: T) -> Self {
        WrappedUserData {
            addr: Some(addr),
            user_data,
        }
    }

    fn mark_dirty_mem_and_unwrap(self, mem: &GuestMemoryMmap, count: u32) -> T {
        if let Some(addr) = self.addr {
            mark_dirty_mem(mem, addr, count as usize)
        }

        self.user_data
    }
}

impl<T> AsyncFileEngine<T> {
    #[allow(unused)]
    pub fn from_file(file: File) -> Result<AsyncFileEngine<T>, Error> {
        let completion_evt = EventFd::new(libc::EFD_NONBLOCK).map_err(Error::EventFd)?;
        let mut ring = IoUring::new(
            IO_URING_NUM_ENTRIES as u32,
            vec![&file],
            Some(completion_evt.as_raw_fd()),
        )
        .map_err(Error::IoUring)?;

        Ok(AsyncFileEngine {
            file,
            ring,
            completion_evt,
            phantom: PhantomData,
        })
    }

    pub fn file(&self) -> &File {
        &self.file
    }

    pub fn completion_evt(&self) -> &EventFd {
        &self.completion_evt
    }

    pub fn push_read(
        &mut self,
        offset: u64,
        mem: &GuestMemoryMmap,
        addr: GuestAddress,
        count: u32,
        user_data: T,
    ) -> Result<(), UserDataError<T, Error>> {
        let buf = match mem.get_slice(addr, count as usize) {
            Ok(slice) => slice.as_ptr(),
            Err(e) => {
                return Err(UserDataError {
                    user_data,
                    error: Error::GuestMemory(e),
                });
            }
        };

        let wrapped_user_data = WrappedUserData::new_with_dirty_tracking(addr, user_data);

        self.ring
            .push(Operation::read(
                0,
                buf as usize,
                count,
                offset,
                wrapped_user_data,
            ))
            .map_err(|err_tuple| UserDataError {
                user_data: err_tuple.1.user_data,
                error: Error::IoUring(err_tuple.0),
            })
    }

    pub fn push_write(
        &mut self,
        offset: u64,
        mem: &GuestMemoryMmap,
        addr: GuestAddress,
        count: u32,
        user_data: T,
    ) -> Result<(), UserDataError<T, Error>> {
        let buf = match mem.get_slice(addr, count as usize) {
            Ok(slice) => slice.as_ptr(),
            Err(e) => {
                return Err(UserDataError {
                    user_data,
                    error: Error::GuestMemory(e),
                });
            }
        };

        let wrapped_user_data = WrappedUserData::new(user_data);

        self.ring
            .push(Operation::write(
                0,
                buf as usize,
                count,
                offset,
                wrapped_user_data,
            ))
            .map_err(|err_tuple| UserDataError {
                user_data: err_tuple.1.user_data,
                error: Error::IoUring(err_tuple.0),
            })
    }

    pub fn push_flush(&mut self, user_data: T) -> Result<(), UserDataError<T, Error>> {
        let wrapped_user_data = WrappedUserData::new(user_data);

        self.ring
            .push(Operation::fsync(0, wrapped_user_data))
            .map_err(|err_tuple| UserDataError {
                user_data: err_tuple.1.user_data,
                error: Error::IoUring(err_tuple.0),
            })
    }

    pub fn kick_submission_queue(&mut self) -> Result<(), Error> {
        self.ring.submit().map(|_| ()).map_err(Error::IoUring)
    }

    pub fn drain(&mut self, flush: bool) -> Result<(), Error> {
        self.drain_submission_queue()?;

        // Drain the completion queue so that we may deallocate the user_data fields.
        while self.do_pop()?.is_some() {}

        if flush {
            // Sync data out to physical media on host.
            // We don't need to call flush first since all the ops are performed through io_uring
            // and Rust shouldn't manage any data in its internal buffers.
            self.file.sync_all().map_err(Error::SyncAll)
        } else {
            Ok(())
        }
    }

    pub fn drain_submission_queue(&mut self) -> Result<(), Error> {
        self.ring
            .submit_and_wait_all()
            .map(|_| ())
            .map_err(Error::IoUring)
    }

    fn do_pop(&mut self) -> Result<Option<Cqe<WrappedUserData<T>>>, Error> {
        self.ring
            .pop::<WrappedUserData<T>>()
            .map_err(Error::IoUring)
    }

    pub fn pop(&mut self, mem: &GuestMemoryMmap) -> Result<Option<Cqe<T>>, Error> {
        let cqe = self.do_pop()?.map(|cqe| {
            let count = cqe.count();
            cqe.map_user_data(|wrapped_user_data| {
                wrapped_user_data.mark_dirty_mem_and_unwrap(mem, count)
            })
        });

        Ok(cqe)
    }
}
<commit_msg>block: add io_uring restrictions<commit_after>// Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

use std::fs::File;
use std::marker::PhantomData;
use std::os::unix::io::AsRawFd;

use io_uring::{
    operation::{Cqe, OpCode, Operation},
    restriction::Restriction,
    Error as IoUringError, IoUring,
};

use utils::eventfd::EventFd;
use vm_memory::{mark_dirty_mem, GuestAddress, GuestMemory, GuestMemoryMmap};

use crate::virtio::block::io::UserDataError;
use crate::virtio::block::IO_URING_NUM_ENTRIES;

#[derive(Debug)]
pub enum Error {
    IO(std::io::Error),
    IoUring(IoUringError),
    Submit(std::io::Error),
    SyncAll(std::io::Error),
    EventFd(std::io::Error),
    GuestMemory(vm_memory::GuestMemoryError),
}

pub struct AsyncFileEngine<T> {
    file: File,
    ring: IoUring,
    completion_evt: EventFd,
    phantom: PhantomData<T>,
}

pub struct WrappedUserData<T> {
    addr: Option<GuestAddress>,
    user_data: T,
}

impl<T> WrappedUserData<T> {
    fn new(user_data: T) -> Self {
        WrappedUserData {
            addr: None,
            user_data,
        }
    }

    fn new_with_dirty_tracking(addr: GuestAddress, user_data: T) -> Self {
        WrappedUserData {
            addr: Some(addr),
            user_data,
        }
    }

    fn mark_dirty_mem_and_unwrap(self, mem: &GuestMemoryMmap, count: u32) -> T {
        if let Some(addr) = self.addr {
            mark_dirty_mem(mem, addr, count as usize)
        }

        self.user_data
    }
}

impl<T> AsyncFileEngine<T> {
    #[allow(unused)]
    pub fn from_file(file: File) -> Result<AsyncFileEngine<T>, Error> {
        let completion_evt = EventFd::new(libc::EFD_NONBLOCK).map_err(Error::EventFd)?;
        let mut ring = IoUring::new(
            IO_URING_NUM_ENTRIES as u32,
            vec![&file],
            vec![
                // Make sure we only allow operations on pre-registered fds.
                Restriction::RequireFixedFds,
                // Allowlist of opcodes.
                Restriction::AllowOpCode(OpCode::Read),
                Restriction::AllowOpCode(OpCode::Write),
                Restriction::AllowOpCode(OpCode::Fsync),
            ],
            Some(completion_evt.as_raw_fd()),
        )
        .map_err(Error::IoUring)?;

        Ok(AsyncFileEngine {
            file,
            ring,
            completion_evt,
            phantom: PhantomData,
        })
    }

    pub fn file(&self) -> &File {
        &self.file
    }

    pub fn completion_evt(&self) -> &EventFd {
        &self.completion_evt
    }

    pub fn push_read(
        &mut self,
        offset: u64,
        mem: &GuestMemoryMmap,
        addr: GuestAddress,
        count: u32,
        user_data: T,
    ) -> Result<(), UserDataError<T, Error>> {
        let buf = match mem.get_slice(addr, count as usize) {
            Ok(slice) => slice.as_ptr(),
            Err(e) => {
                return Err(UserDataError {
                    user_data,
                    error: Error::GuestMemory(e),
                });
            }
        };

        let wrapped_user_data = WrappedUserData::new_with_dirty_tracking(addr, user_data);

        self.ring
            .push(Operation::read(
                0,
                buf as usize,
                count,
                offset,
                wrapped_user_data,
            ))
            .map_err(|err_tuple| UserDataError {
                user_data: err_tuple.1.user_data,
                error: Error::IoUring(err_tuple.0),
            })
    }

    pub fn push_write(
        &mut self,
        offset: u64,
        mem: &GuestMemoryMmap,
        addr: GuestAddress,
        count: u32,
        user_data: T,
    ) -> Result<(), UserDataError<T, Error>> {
        let buf = match mem.get_slice(addr, count as usize) {
            Ok(slice) => slice.as_ptr(),
            Err(e) => {
                return Err(UserDataError {
                    user_data,
                    error: Error::GuestMemory(e),
                });
            }
        };

        let wrapped_user_data = WrappedUserData::new(user_data);

        self.ring
            .push(Operation::write(
                0,
                buf as usize,
                count,
                offset,
                wrapped_user_data,
            ))
            .map_err(|err_tuple| UserDataError {
                user_data: err_tuple.1.user_data,
                error: Error::IoUring(err_tuple.0),
            })
    }

    pub fn push_flush(&mut self, user_data: T) -> Result<(), UserDataError<T, Error>> {
        let wrapped_user_data = WrappedUserData::new(user_data);

        self.ring
            .push(Operation::fsync(0, wrapped_user_data))
            .map_err(|err_tuple| UserDataError {
                user_data: err_tuple.1.user_data,
                error: Error::IoUring(err_tuple.0),
            })
    }

    pub fn kick_submission_queue(&mut self) -> Result<(), Error> {
        self.ring.submit().map(|_| ()).map_err(Error::IoUring)
    }

    pub fn drain(&mut self, flush: bool) -> Result<(), Error> {
        self.drain_submission_queue()?;

        // Drain the completion queue so that we may deallocate the user_data fields.
        while self.do_pop()?.is_some() {}

        if flush {
            // Sync data out to physical media on host.
            // We don't need to call flush first since all the ops are performed through io_uring
            // and Rust shouldn't manage any data in its internal buffers.
            self.file.sync_all().map_err(Error::SyncAll)
        } else {
            Ok(())
        }
    }

    pub fn drain_submission_queue(&mut self) -> Result<(), Error> {
        self.ring
            .submit_and_wait_all()
            .map(|_| ())
            .map_err(Error::IoUring)
    }

    fn do_pop(&mut self) -> Result<Option<Cqe<WrappedUserData<T>>>, Error> {
        self.ring
            .pop::<WrappedUserData<T>>()
            .map_err(Error::IoUring)
    }

    pub fn pop(&mut self, mem: &GuestMemoryMmap) -> Result<Option<Cqe<T>>, Error> {
        let cqe = self.do_pop()?.map(|cqe| {
            let count = cqe.count();
            cqe.map_user_data(|wrapped_user_data| {
                wrapped_user_data.mark_dirty_mem_and_unwrap(mem, count)
            })
        });

        Ok(cqe)
    }
}
<|endoftext|>


<commit_before>// OpenAOE: An open source reimplementation of Age of Empires (1997)
// Copyright (c) 2016 Kevin Fuller
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

use ecs::{TransformComponent, UnitComponent, VisibleUnitComponent};
use ecs::resource::ViewProjector;

use dat;
use media::MediaRef;
use resource::{DrsKey, ShapeKey, ShapeManagerRef};

use specs::{self, Join};

pub struct UnitRenderSystem {
    media: MediaRef,
    shape_manager: ShapeManagerRef,
    empires: dat::EmpiresDbRef,
}

impl UnitRenderSystem {
    pub fn new(media: MediaRef,
               shape_manager: ShapeManagerRef,
               empires: dat::EmpiresDbRef)
               -> UnitRenderSystem {
        UnitRenderSystem {
            media: media,
            shape_manager: shape_manager,
            empires: empires,
        }
    }

    pub fn render(&self, world: &mut specs::World, lerp: f32) {
        let (transforms, units, visible_units, projector) = (world.read::<TransformComponent>(),
                                                             world.read::<UnitComponent>(),
                                                             world.read::<VisibleUnitComponent>(),
                                                             world.read_resource::<ViewProjector>());
        let mut media = self.media.borrow_mut();
        let renderer = media.renderer();

        for (transform, unit, _visible_units) in (&transforms, &units, &visible_units).iter() {
            if let Some(graphic_id) = unit.graphic_id {
                if let Some(slp_id) = self.empires.graphic(graphic_id).slp_id {
                    let shape_key = ShapeKey::new(DrsKey::Graphics, slp_id, unit.player_id.into());
                    let position = projector.project(&transform.lerped_position(lerp));

                    // TODO: Render the unit's rotation as well
                    self.shape_manager
                        .borrow_mut()
                        .get(&shape_key, renderer)
                        .expect("failed to get shape for unit rendering")
                        .render_frame(renderer, unit.frame as usize, &position);
                }
            }
        }
    }
}
<commit_msg>Sort units by layer and Y-coord during rendering<commit_after>// OpenAOE: An open source reimplementation of Age of Empires (1997)
// Copyright (c) 2016 Kevin Fuller
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

use ecs::{TransformComponent, UnitComponent, VisibleUnitComponent};
use ecs::resource::ViewProjector;

use dat;
use media::MediaRef;
use resource::{DrsKey, ShapeKey, ShapeManagerRef};

use nalgebra::Vector2;
use specs::{self, Join};

struct RenderOp {
    layer: u8,
    position: Vector2<i32>,
    shape_key: ShapeKey,
    frame: u32,
}

pub struct UnitRenderSystem {
    media: MediaRef,
    shape_manager: ShapeManagerRef,
    empires: dat::EmpiresDbRef,
    render_ops: Vec<RenderOp>,
}

impl UnitRenderSystem {
    pub fn new(media: MediaRef,
               shape_manager: ShapeManagerRef,
               empires: dat::EmpiresDbRef)
               -> UnitRenderSystem {
        UnitRenderSystem {
            media: media,
            shape_manager: shape_manager,
            empires: empires,
            render_ops: Vec::new(),
        }
    }

    pub fn render(&mut self, world: &mut specs::World, lerp: f32) {
        let (transforms, units, visible_units, projector) = (world.read::<TransformComponent>(),
                                                             world.read::<UnitComponent>(),
                                                             world.read::<VisibleUnitComponent>(),
                                                             world.read_resource::<ViewProjector>());
        let mut media = self.media.borrow_mut();
        let renderer = media.renderer();

        for (transform, unit, _visible_units) in (&transforms, &units, &visible_units).iter() {
            if let Some(graphic_id) = unit.graphic_id {
                let graphic = self.empires.graphic(graphic_id);
                if let Some(slp_id) = graphic.slp_id {
                    self.render_ops.push(RenderOp {
                        layer: graphic.layer,
                        position: projector.project(&transform.lerped_position(lerp)),
                        shape_key: ShapeKey::new(DrsKey::Graphics, slp_id, unit.player_id.into()),
                        frame: unit.frame,
                    });
                }
            }
        }

        self.render_ops.sort_by(|left, right| {
            use std::cmp::Ordering::*;
            match left.layer.cmp(&right.layer) {
                Equal => left.position.y.cmp(&right.position.y),
                v @ _ => v,
            }
        });

        for render_op in &self.render_ops {
            // TODO: Render the unit's rotation as well
            self.shape_manager
                .borrow_mut()
                .get(&render_op.shape_key, renderer)
                .expect("failed to get shape for unit rendering")
                .render_frame(renderer, render_op.frame as usize, &render_op.position);
        }
        self.render_ops.clear();
    }
}
<|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/.

// Functions for dealing with devices.

use std::{collections::HashMap, fs::OpenOptions, path::Path};

use devicemapper::{devnode_to_devno, Device};

use crate::{
    engine::{
        strat_engine::backstore::{
            metadata::device_identifiers,
            udev::{block_enumerator, decide_ownership, UdevOwnership},
        },
        types::{DevUuid, PoolUuid},
    },
    stratis::{ErrorEnum, StratisError, StratisResult},
};

/// Resolve a list of Paths of some sort to a set of unique Devices.
/// Return an IOError if there was a problem resolving any particular device.
/// The set of devices maps each device to one of the paths passed.
/// Returns an error if any path does not correspond to a block device.
pub fn resolve_devices<'a>(paths: &'a [&Path]) -> StratisResult<HashMap<Device, &'a Path>> {
    let mut map = HashMap::new();
    for path in paths {
        match devnode_to_devno(path)? {
            Some(devno) => {
                let _ = map.insert(Device::from(devno), *path);
            }
            None => {
                let err_msg = format!("path {} does not refer to a block device", path.display());
                return Err(StratisError::Engine(ErrorEnum::Invalid, err_msg));
            }
        }
    }
    Ok(map)
}

#[derive(Debug, PartialEq, Eq)]
pub enum DevOwnership {
    Ours(PoolUuid, DevUuid),
    Unowned,
    // FIXME: Using a string for identification of specific subclasses of
    // ownership is a mistake, an enum would be better.
    Theirs(String), // A string that is supposed to give more description
}

impl DevOwnership {
    pub fn stratis_identifiers(&self) -> Option<(PoolUuid, DevUuid)> {
        match self {
            DevOwnership::Ours(pool_uuid, dev_uuid) => Some((*pool_uuid, *dev_uuid)),
            _ => None,
        }
    }
}

/// Determine what a block device is used for.
pub fn identify(devnode: &Path) -> StratisResult<DevOwnership> {
    let canonical = devnode.canonicalize()?;

    let context = libudev::Context::new()?;
    let mut enumerator = block_enumerator(&context)?;
    if let Some(udev_decision) = enumerator
        .scan_devices()?
        .filter(|dev| dev.is_initialized())
        .find(|x| x.devnode().map_or(false, |d| canonical == d))
        .map(|d| decide_ownership(&d))
    {
        match udev_decision {
            Ok(decision) => {
                match decision {
                    UdevOwnership::Unowned => {
                        // FIXME: It is possible that Stratis is running in
                        // an old environment without the necessary version of
                        // libblkid that would cause udev database to be
                        // populated with Stratis information. So, if the
                        // device appears unowned, attempt to read information
                        // from Stratis metadata. We believe that this block
                        // can be removed once Stratis is certainly runnng
                        // with libblkid 2.32 or above.
                        // https://github.com/stratis-storage/stratisd/issues/1656
                        if let Some((pool_uuid, device_uuid)) =
                            device_identifiers(&mut OpenOptions::new().read(true).open(&devnode)?)?
                        {
                            Ok(DevOwnership::Ours(pool_uuid, device_uuid))
                        } else {
                            Ok(DevOwnership::Unowned)
                        }
                    }
                    UdevOwnership::MultipathMember => {
                        Ok(DevOwnership::Theirs("multipath member".into()))
                    }
                    UdevOwnership::Stratis => {
                        // Udev information does not include pool UUID and
                        // device UUID so read these from Stratis metadata.
                        if let Some((pool_uuid, device_uuid)) =
                            device_identifiers(&mut OpenOptions::new().read(true).open(&devnode)?)?
                        {
                            Ok(DevOwnership::Ours(pool_uuid, device_uuid))
                        } else {
                            // FIXME: if udev says stratis but no stratis
                            // idenfiers on device, likely they were there
                            // recently, and udev has not yet caught up. It's
                            // just as likely that this device is unclaimed as
                            // that it belongs to some other entity.
                            Ok(DevOwnership::Theirs(
                                "Udev db says stratis, disk meta says no".into(),
                            ))
                        }
                    }
                    UdevOwnership::Theirs => Ok(DevOwnership::Theirs(
                             "udev properties for this device did not indicate that the devices was unowned".into()
                    )),
                }
            }
            Err(err) => Err(err),
        }
    } else {
        Err(StratisError::Engine(
            ErrorEnum::NotFound,
            format!(
                "We expected to find the block device {:?} \
                 in the udev db",
                devnode
            ),
        ))
    }
}

#[cfg(test)]
mod test {
    use std::path::Path;

    use crate::engine::strat_engine::{
        cmd,
        tests::{loopbacked, real},
    };

    use super::*;

    /// Verify that the device is not stratis by creating a device with XFS fs.
    fn test_other_ownership(paths: &[&Path]) {
        cmd::create_fs(paths[0], None).unwrap();
        cmd::udev_settle().unwrap();
        assert_matches!(identify(paths[0]).unwrap(), DevOwnership::Theirs(_))
    }

    /// Verify that identify() recognizes a blank device as unowned
    fn test_empty(paths: &[&Path]) {
        cmd::udev_settle().unwrap();
        assert_matches!(identify(paths[0]).unwrap(), DevOwnership::Unowned);
    }

    #[test]
    pub fn loop_test_device_other_ownership() {
        loopbacked::test_with_spec(
            &loopbacked::DeviceLimits::Range(1, 3, None),
            test_other_ownership,
        );
    }

    #[test]
    pub fn real_test_device_other_ownership() {
        real::test_with_spec(
            &real::DeviceLimits::AtLeast(1, None, None),
            test_other_ownership,
        );
    }

    #[test]
    pub fn loop_test_device_empty() {
        loopbacked::test_with_spec(&loopbacked::DeviceLimits::Range(1, 3, None), test_empty);
    }

    #[test]
    pub fn real_test_device_empty() {
        real::test_with_spec(&real::DeviceLimits::AtLeast(1, None, None), test_empty);
    }
}
<commit_msg>Factor code that obtains DevOwnership out of identify() method<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/.

// Functions for dealing with devices.

use std::{collections::HashMap, fs::OpenOptions, path::Path};

use devicemapper::{devnode_to_devno, Device};

use crate::{
    engine::{
        strat_engine::backstore::{
            metadata::device_identifiers,
            udev::{block_enumerator, decide_ownership, UdevOwnership},
        },
        types::{DevUuid, PoolUuid},
    },
    stratis::{ErrorEnum, StratisError, StratisResult},
};

/// Resolve a list of Paths of some sort to a set of unique Devices.
/// Return an IOError if there was a problem resolving any particular device.
/// The set of devices maps each device to one of the paths passed.
/// Returns an error if any path does not correspond to a block device.
pub fn resolve_devices<'a>(paths: &'a [&Path]) -> StratisResult<HashMap<Device, &'a Path>> {
    let mut map = HashMap::new();
    for path in paths {
        match devnode_to_devno(path)? {
            Some(devno) => {
                let _ = map.insert(Device::from(devno), *path);
            }
            None => {
                let err_msg = format!("path {} does not refer to a block device", path.display());
                return Err(StratisError::Engine(ErrorEnum::Invalid, err_msg));
            }
        }
    }
    Ok(map)
}

#[derive(Debug, PartialEq, Eq)]
pub enum DevOwnership {
    Ours(PoolUuid, DevUuid),
    Unowned,
    // FIXME: Using a string for identification of specific subclasses of
    // ownership is a mistake, an enum would be better.
    Theirs(String), // A string that is supposed to give more description
}

impl DevOwnership {
    pub fn stratis_identifiers(&self) -> Option<(PoolUuid, DevUuid)> {
        match self {
            DevOwnership::Ours(pool_uuid, dev_uuid) => Some((*pool_uuid, *dev_uuid)),
            _ => None,
        }
    }

    /// Given a udev assignment of ownership and the devnode for the device
    /// in question, do some additional work to determine DevOwnership.
    pub fn from_udev_ownership(
        ownership: &UdevOwnership,
        devnode: &Path,
    ) -> StratisResult<DevOwnership> {
        match ownership {
            UdevOwnership::Unowned => {
                // FIXME: It is possible that Stratis is running in
                // an old environment without the necessary version of
                // libblkid that would cause udev database to be
                // populated with Stratis information. So, if the
                // device appears unowned, attempt to read information
                // from Stratis metadata. We believe that this block
                // can be removed once Stratis is certainly runnng
                // with libblkid 2.32 or above.
                // https://github.com/stratis-storage/stratisd/issues/1656
                if let Some((pool_uuid, device_uuid)) =
                    device_identifiers(&mut OpenOptions::new().read(true).open(&devnode)?)?
                {
                    Ok(DevOwnership::Ours(pool_uuid, device_uuid))
                } else {
                    Ok(DevOwnership::Unowned)
                }
            }
            UdevOwnership::MultipathMember => Ok(DevOwnership::Theirs("multipath member".into())),
            UdevOwnership::Stratis => {
                // Udev information does not include pool UUID and
                // device UUID so read these from Stratis metadata.
                if let Some((pool_uuid, device_uuid)) =
                    device_identifiers(&mut OpenOptions::new().read(true).open(&devnode)?)?
                {
                    Ok(DevOwnership::Ours(pool_uuid, device_uuid))
                } else {
                    // FIXME: if udev says stratis but no stratis
                    // idenfiers on device, likely they were there
                    // recently, and udev has not yet caught up. It's
                    // just as likely that this device is unclaimed as
                    // that it belongs to some other entity.
                    Ok(DevOwnership::Theirs(
                        "Udev db says stratis, disk meta says no".into(),
                    ))
                }
            }
            UdevOwnership::Theirs => Ok(DevOwnership::Theirs(
                "udev properties for this device did not indicate that the device was unowned"
                    .into(),
            )),
        }
    }
}

/// Determine what a block device is used for.
pub fn identify(devnode: &Path) -> StratisResult<DevOwnership> {
    let canonical = devnode.canonicalize()?;

    let context = libudev::Context::new()?;
    let mut enumerator = block_enumerator(&context)?;
    if let Some(udev_decision) = enumerator
        .scan_devices()?
        .filter(|dev| dev.is_initialized())
        .find(|x| x.devnode().map_or(false, |d| canonical == d))
        .map(|d| decide_ownership(&d))
    {
        udev_decision.and_then(|decision| DevOwnership::from_udev_ownership(&decision, &canonical))
    } else {
        Err(StratisError::Engine(
            ErrorEnum::NotFound,
            format!(
                "We expected to find the block device {:?} \
                 in the udev db",
                devnode
            ),
        ))
    }
}

#[cfg(test)]
mod test {
    use std::path::Path;

    use crate::engine::strat_engine::{
        cmd,
        tests::{loopbacked, real},
    };

    use super::*;

    /// Verify that the device is not stratis by creating a device with XFS fs.
    fn test_other_ownership(paths: &[&Path]) {
        cmd::create_fs(paths[0], None).unwrap();
        cmd::udev_settle().unwrap();
        assert_matches!(identify(paths[0]).unwrap(), DevOwnership::Theirs(_))
    }

    /// Verify that identify() recognizes a blank device as unowned
    fn test_empty(paths: &[&Path]) {
        cmd::udev_settle().unwrap();
        assert_matches!(identify(paths[0]).unwrap(), DevOwnership::Unowned);
    }

    #[test]
    pub fn loop_test_device_other_ownership() {
        loopbacked::test_with_spec(
            &loopbacked::DeviceLimits::Range(1, 3, None),
            test_other_ownership,
        );
    }

    #[test]
    pub fn real_test_device_other_ownership() {
        real::test_with_spec(
            &real::DeviceLimits::AtLeast(1, None, None),
            test_other_ownership,
        );
    }

    #[test]
    pub fn loop_test_device_empty() {
        loopbacked::test_with_spec(&loopbacked::DeviceLimits::Range(1, 3, None), test_empty);
    }

    #[test]
    pub fn real_test_device_empty() {
        real::test_with_spec(&real::DeviceLimits::AtLeast(1, None, None), test_empty);
    }
}
<|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/.

// external
use svgdom::{
    Document,
    Length,
    Node,
    NodeType,
    ValueId,
};

// self
use short::{
    AId,
    AValue,
    Unit,
};
use traits::{
    FindAttribute,
};
use super::{
    DEFAULT_FONT_SIZE,
};

pub fn resolve_font_size(doc: &Document) {
    _resolve_font_size(&doc.root());
}

pub fn _resolve_font_size(parent: &Node) {
    for (_, mut node) in parent.children().svg() {
        // We have to resolve 'font-size' for all elements
        // and not only for 'text content' based,
        // because it will be used during 'em'/'ex' units conversion.
        //
        // https://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#propdef-font-size

        let font_size = match node.attributes().get(AId::FontSize) {
            Some(v) => {
                v.value.clone()
            }
            None => {
                // If not set - lookup in parent nodes or use default.
                let len = node.find_attribute(AId::FontSize)
                              .unwrap_or(Length::new_number(DEFAULT_FONT_SIZE));

                AValue::Length(len)
            }
        };

        let font_size = match font_size {
            AValue::Length(len) => {
                if len.unit == Unit::Percent {
                    process_percent_font_size(parent, len)
                } else {
                    len
                }
            }
            AValue::PredefValue(id) => {
                process_named_font_size(id, &font_size)
            }
            _ => {
                // Technically unreachable, because 'svgparser' should validate it.
                warn!("Invalid 'font-size' value: {}.", font_size);
                Length::new(DEFAULT_FONT_SIZE, Unit::None)
            }
        };

        let had_attr = node.has_attribute(AId::FontSize);

        node.set_attribute((AId::FontSize, font_size));

        // We have to mark this attribute as invisible,
        // otherwise it will break the 'use' resolving.
        if !had_attr {
            if let Some(ref mut attr) = node.attributes_mut().get_mut(AId::FontSize) {
                attr.visible = false;
            }
        }

        if node.has_children() {
            _resolve_font_size(&mut node);
        }
    }
}

// If 'font-size' has percent units that it's value
// is relative to the parent node 'font-size'.
fn process_percent_font_size(parent: &Node, len: Length) -> Length {
    if parent.node_type() == NodeType::Root {
        Length::new(DEFAULT_FONT_SIZE, Unit::None)
    } else {
        let parent_len = parent.find_attribute(AId::FontSize)
                               .unwrap_or(Length::new_number(DEFAULT_FONT_SIZE));

        let n = len.num * parent_len.num * 0.01;
        Length::new(n, Unit::None)
    }
}

fn process_named_font_size(id: ValueId, font_size: &AValue) -> Length {
    let factor = match id {
        ValueId::XxSmall => -3,
        ValueId::XSmall => -2,
        ValueId::Small => -1,
        ValueId::Medium => 0,
        ValueId::Large => 1,
        ValueId::XLarge => 2,
        ValueId::XxLarge => 3,
        ValueId::Smaller => -1,
        ValueId::Larger => 1,
        _ => {
            // Technically unreachable, because 'svgparser' should validate it.
            warn!("Invalid 'font-size' value: {}.", font_size);
            0
        }
    };

    // 'On a computer screen a scaling factor of 1.2
    // is suggested between adjacent indexes'
    let n = DEFAULT_FONT_SIZE * 1.2f64.powi(factor);
    Length::new(n, Unit::None)
}
<commit_msg>Fixed named font-size resolving.<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/.

// external
use svgdom::{
    Document,
    Length,
    Node,
    NodeType,
    ValueId,
};

// self
use short::{
    AId,
    AValue,
    Unit,
};
use traits::{
    FindAttribute,
};
use super::{
    DEFAULT_FONT_SIZE,
};

pub fn resolve_font_size(doc: &Document) {
    _resolve_font_size(&doc.root());
}

pub fn _resolve_font_size(parent: &Node) {
    for (_, mut node) in parent.children().svg() {
        // We have to resolve 'font-size' for all elements
        // and not only for 'text content' based,
        // because it will be used during 'em'/'ex' units conversion.
        //
        // https://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#propdef-font-size

        let font_size = match node.attributes().get(AId::FontSize) {
            Some(v) => {
                v.value.clone()
            }
            None => {
                // If not set - lookup in parent nodes or use default.
                let len = node.find_attribute(AId::FontSize)
                              .unwrap_or(Length::new_number(DEFAULT_FONT_SIZE));

                AValue::Length(len)
            }
        };

        let font_size = match font_size {
            AValue::Length(len) => {
                if len.unit == Unit::Percent {
                    process_percent_font_size(parent, len)
                } else {
                    len
                }
            }
            AValue::PredefValue(id) => {
                process_named_font_size(parent, id, &font_size)
            }
            _ => {
                // Technically unreachable, because 'svgparser' should validate it.
                warn!("Invalid 'font-size' value: {}.", font_size);
                Length::new(DEFAULT_FONT_SIZE, Unit::None)
            }
        };

        let had_attr = node.has_attribute(AId::FontSize);

        node.set_attribute((AId::FontSize, font_size));

        // We have to mark this attribute as invisible,
        // otherwise it will break the 'use' resolving.
        if !had_attr {
            if let Some(ref mut attr) = node.attributes_mut().get_mut(AId::FontSize) {
                attr.visible = false;
            }
        }

        if node.has_children() {
            _resolve_font_size(&mut node);
        }
    }
}

// If 'font-size' has percent units that it's value
// is relative to the parent node 'font-size'.
fn process_percent_font_size(parent: &Node, len: Length) -> Length {
    if parent.node_type() == NodeType::Root {
        Length::new(DEFAULT_FONT_SIZE, Unit::None)
    } else {
        let parent_len = parent.find_attribute(AId::FontSize)
                               .unwrap_or(Length::new_number(DEFAULT_FONT_SIZE));

        let n = len.num * parent_len.num * 0.01;
        Length::new(n, Unit::None)
    }
}

fn process_named_font_size(parent: &Node, id: ValueId, font_size: &AValue) -> Length {
    let factor = match id {
        ValueId::XxSmall => -3,
        ValueId::XSmall => -2,
        ValueId::Small => -1,
        ValueId::Medium => 0,
        ValueId::Large => 1,
        ValueId::XLarge => 2,
        ValueId::XxLarge => 3,
        ValueId::Smaller => -1,
        ValueId::Larger => 1,
        _ => {
            // Technically unreachable, because 'svgparser' should validate it.
            warn!("Invalid 'font-size' value: {}.", font_size);
            0
        }
    };

    let parent_len = parent.find_attribute(AId::FontSize)
                           .unwrap_or(Length::new_number(DEFAULT_FONT_SIZE));

    // 'On a computer screen a scaling factor of 1.2
    // is suggested between adjacent indexes'
    let n = parent_len.num * 1.2f64.powi(factor);
    Length::new(n, Unit::None)
}
<|endoftext|>


<commit_before>// Copyright (c) IxMilia.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.

mod entity_generator;
mod header_generator;
mod object_generator;
mod other_helpers;
mod table_generator;
mod test_helper_generator;
mod xml_helpers;

use std::env;
use std::error::Error;
use std::fmt::Debug;
use std::fs::{self, File};
use std::io::Write;
use std::path::Path;

include!("../src/expected_type.rs");

fn main() -> Result<(), Box<Error>> {
    // watch everything under the `build/` and `spec/` directories and also one specific file
    rerun_if_changed("src/expected_type.rs");
    let dirs_to_watch = vec!["build/", "spec/"];
    for sub_dir in dirs_to_watch {
        rerun_if_changed(sub_dir);
        let path = Path::new(&sub_dir);
        for entry in fs::read_dir(path)? {
            let entry = entry?;
            if entry.file_type()?.is_file() {
                rerun_if_changed(&entry.path().as_os_str());
            }
        }
    }

    let out_dir = env::var("OUT_DIR").unwrap();
    let generated_dir = Path::new(&out_dir).join("generated");
    let _ = std::fs::create_dir(&generated_dir); // might fail if it's already there

    let mut file = File::create(generated_dir.join("mod.rs")).ok().unwrap();
    file.write_all("// The contents of this file are automatically generated and should not be modified directly.  See the `build` directory.

pub mod entities;
pub mod header;
pub mod objects;
pub mod tables;
".as_bytes()).ok().unwrap();

    entity_generator::generate_entities(&generated_dir);
    header_generator::generate_header(&generated_dir);
    object_generator::generate_objects(&generated_dir);
    table_generator::generate_tables(&generated_dir);

    test_helper_generator::generate_test_helpers(&generated_dir);

    Ok(())
}

fn rerun_if_changed<S: Debug + ?Sized>(s: &S) {
    let s = format!("{:?}", s)
        .replace("\\\\", "/") // normalize directory separators
        .replace("\"", ""); // ignore surrounding quotes
    println!("cargo:rerun-if-changed={}", s);
}
<commit_msg>return trait object in builder<commit_after>// Copyright (c) IxMilia.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.

mod entity_generator;
mod header_generator;
mod object_generator;
mod other_helpers;
mod table_generator;
mod test_helper_generator;
mod xml_helpers;

use std::env;
use std::error::Error;
use std::fmt::Debug;
use std::fs::{self, File};
use std::io::Write;
use std::path::Path;

include!("../src/expected_type.rs");

fn main() -> Result<(), Box<dyn Error>> {
    // watch everything under the `build/` and `spec/` directories and also one specific file
    rerun_if_changed("src/expected_type.rs");
    let dirs_to_watch = vec!["build/", "spec/"];
    for sub_dir in dirs_to_watch {
        rerun_if_changed(sub_dir);
        let path = Path::new(&sub_dir);
        for entry in fs::read_dir(path)? {
            let entry = entry?;
            if entry.file_type()?.is_file() {
                rerun_if_changed(&entry.path().as_os_str());
            }
        }
    }

    let out_dir = env::var("OUT_DIR").unwrap();
    let generated_dir = Path::new(&out_dir).join("generated");
    let _ = std::fs::create_dir(&generated_dir); // might fail if it's already there

    let mut file = File::create(generated_dir.join("mod.rs")).ok().unwrap();
    file.write_all("// The contents of this file are automatically generated and should not be modified directly.  See the `build` directory.

pub mod entities;
pub mod header;
pub mod objects;
pub mod tables;
".as_bytes()).ok().unwrap();

    entity_generator::generate_entities(&generated_dir);
    header_generator::generate_header(&generated_dir);
    object_generator::generate_objects(&generated_dir);
    table_generator::generate_tables(&generated_dir);

    test_helper_generator::generate_test_helpers(&generated_dir);

    Ok(())
}

fn rerun_if_changed<S: Debug + ?Sized>(s: &S) {
    let s = format!("{:?}", s)
        .replace("\\\\", "/") // normalize directory separators
        .replace("\"", ""); // ignore surrounding quotes
    println!("cargo:rerun-if-changed={}", s);
}
<|endoftext|>