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

use std::os::raw;

include!(concat!(env!("OUT_DIR"), "/test_gen_symbols.rs"));

pub fn compile_test_gl() {
    unsafe {
        gl::Clear(gl::COLOR_BUFFER_BIT);
        let _: raw::c_uint = gl::CreateProgram();
        gl::CompileShader(5);
        gl::GetActiveUniformBlockiv(
            0,
            0,
            gl::UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER,
            std::ptr::null_mut(),
        );

        let _: *mut raw::c_void = gl::MapBuffer(0, 0);
    }
}

pub fn compile_test_gles1() {
    unsafe {
        gles1::Clear(gles1::COLOR_BUFFER_BIT);
    }
}

pub fn compile_test_gles2() {
    unsafe {
        gles2::Clear(gles2::COLOR_BUFFER_BIT);
        let _: raw::c_uint = gles2::CreateProgram();
        gles2::CompileShader(5);
    }
}

pub fn compile_test_glsc2() {
    unsafe {
        glsc2::Clear(glsc2::COLOR_BUFFER_BIT);
    }
}

pub fn compile_test_glx() {
    unsafe {
        let _ = glx::GetProcAddress(std::mem::uninitialized());
        glx::SwapBuffers(std::mem::uninitialized(), std::mem::uninitialized());
    }
}

pub fn compile_test_wgl() {
    unsafe {
        let _: wgl::types::HGLRC = wgl::CreateContext(std::mem::uninitialized());
    }
}

pub fn compile_test_egl() {
    unsafe {
        let _ = [
            egl::SURFACE_TYPE,
            egl::WINDOW_BIT,
            egl::BLUE_SIZE,
            8,
            egl::GREEN_SIZE,
            8,
            egl::RED_SIZE,
            8,
            egl::NONE,
        ];

        let _ = egl::GetDisplay(egl::DEFAULT_DISPLAY);
        egl::Terminate(std::mem::uninitialized());
    }
}
<commit_msg>Fix use of deprecated item 'std::mem::uninitialized' warnings<commit_after>// Copyright 2015 Brendan Zabarauskas and the gl-rs developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::os::raw;

include!(concat!(env!("OUT_DIR"), "/test_gen_symbols.rs"));

pub fn compile_test_gl() {
    unsafe {
        gl::Clear(gl::COLOR_BUFFER_BIT);
        let _: raw::c_uint = gl::CreateProgram();
        gl::CompileShader(5);
        gl::GetActiveUniformBlockiv(
            0,
            0,
            gl::UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER,
            std::ptr::null_mut(),
        );

        let _: *mut raw::c_void = gl::MapBuffer(0, 0);
    }
}

pub fn compile_test_gles1() {
    unsafe {
        gles1::Clear(gles1::COLOR_BUFFER_BIT);
    }
}

pub fn compile_test_gles2() {
    unsafe {
        gles2::Clear(gles2::COLOR_BUFFER_BIT);
        let _: raw::c_uint = gles2::CreateProgram();
        gles2::CompileShader(5);
    }
}

pub fn compile_test_glsc2() {
    unsafe {
        glsc2::Clear(glsc2::COLOR_BUFFER_BIT);
    }
}

pub fn compile_test_glx() {
    unsafe {
        let _ = glx::GetProcAddress(std::mem::MaybeUninit::uninit().assume_init());
        glx::SwapBuffers(
            std::mem::MaybeUninit::uninit().assume_init(),
            std::mem::MaybeUninit::uninit().assume_init(),
        );
    }
}

pub fn compile_test_wgl() {
    unsafe {
        let _: wgl::types::HGLRC =
            wgl::CreateContext(std::mem::MaybeUninit::uninit().assume_init());
    }
}

pub fn compile_test_egl() {
    unsafe {
        let _ = [
            egl::SURFACE_TYPE,
            egl::WINDOW_BIT,
            egl::BLUE_SIZE,
            8,
            egl::GREEN_SIZE,
            8,
            egl::RED_SIZE,
            8,
            egl::NONE,
        ];

        let _ = egl::GetDisplay(egl::DEFAULT_DISPLAY);
        egl::Terminate(std::mem::MaybeUninit::uninit().assume_init());
    }
}
<|endoftext|>


<commit_before>use support::rustc_host;
use support::{basic_lib_manifest, execs, project, path2url};
use support::hamcrest::assert_that;

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

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

    assert_that(
        foo.cargo("build").arg("--verbose"),
        execs().with_stderr(&format!(
            "\
[COMPILING] foo v0.5.0 ({url})
[RUNNING] `rustc [..] -C ar=nonexistent-ar -C linker=nonexistent-linker [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
            url = foo.url()
        )),
    )
}

#[test]
fn absolute_tools() {
    let target = rustc_host();
    let root = if cfg!(windows) { r#"C:\\"# } else { "/" };

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

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

    assert_that(
        foo.cargo("build").arg("--verbose"),
        execs().with_stderr(&format!(
            "\
[COMPILING] foo v0.5.0 ({url})
[RUNNING] `rustc [..] -C ar={root}bogus/nonexistent-ar -C linker={root}bogus/nonexistent-linker [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
            url = foo.url(),
            root = root,
        )),
    )
}

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

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

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

    let foo_path = p.root().join("bar");
    let foo_url = path2url(&foo_path);
    let prefix = p.root().into_os_string().into_string().unwrap();

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

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

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

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

    assert_that(
        p.cargo("test --test test --verbose -- --param"),
        execs().with_status(101).with_stderr_contains(&format!(
            "\
[COMPILING] foo v0.0.1 ({url})
[RUNNING] `rustc [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
[RUNNING] `nonexistent-runner -r [..]/target/debug/deps/test-[..][EXE] --param`
",
            url = p.url()
        )),
    );

    assert_that(
        p.cargo("bench --bench bench --verbose -- --param"),
        execs().with_status(101).with_stderr_contains(&format!(
            "\
[COMPILING] foo v0.0.1 ({url})
[RUNNING] `rustc [..]`
[RUNNING] `rustc [..]`
[FINISHED] release [optimized] target(s) in [..]
[RUNNING] `nonexistent-runner -r [..]/target/release/deps/bench-[..][EXE] --param --bench`
",
            url = p.url()
        )),
    );
}
<commit_msg>Single slash root on Windows<commit_after>use support::rustc_host;
use support::{basic_lib_manifest, execs, project, path2url};
use support::hamcrest::assert_that;

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

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

    assert_that(
        foo.cargo("build").arg("--verbose"),
        execs().with_stderr(&format!(
            "\
[COMPILING] foo v0.5.0 ({url})
[RUNNING] `rustc [..] -C ar=nonexistent-ar -C linker=nonexistent-linker [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
            url = foo.url()
        )),
    )
}

#[test]
fn absolute_tools() {
    let target = rustc_host();
    let root = if cfg!(windows) { r#"C:\"# } else { "/" };

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

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

    assert_that(
        foo.cargo("build").arg("--verbose"),
        execs().with_stderr(&format!(
            "\
[COMPILING] foo v0.5.0 ({url})
[RUNNING] `rustc [..] -C ar={root}bogus/nonexistent-ar -C linker={root}bogus/nonexistent-linker [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
            url = foo.url(),
            root = root,
        )),
    )
}

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

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

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

    let foo_path = p.root().join("bar");
    let foo_url = path2url(&foo_path);
    let prefix = p.root().into_os_string().into_string().unwrap();

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

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

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

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

    assert_that(
        p.cargo("test --test test --verbose -- --param"),
        execs().with_status(101).with_stderr_contains(&format!(
            "\
[COMPILING] foo v0.0.1 ({url})
[RUNNING] `rustc [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
[RUNNING] `nonexistent-runner -r [..]/target/debug/deps/test-[..][EXE] --param`
",
            url = p.url()
        )),
    );

    assert_that(
        p.cargo("bench --bench bench --verbose -- --param"),
        execs().with_status(101).with_stderr_contains(&format!(
            "\
[COMPILING] foo v0.0.1 ({url})
[RUNNING] `rustc [..]`
[RUNNING] `rustc [..]`
[FINISHED] release [optimized] target(s) in [..]
[RUNNING] `nonexistent-runner -r [..]/target/release/deps/bench-[..][EXE] --param --bench`
",
            url = p.url()
        )),
    );
}
<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::*;
use rand::{Rng, SeedableRng};
use std::{
    io::{self, Write},
    process,
};
use structopt::{clap::arg_enum, StructOpt};
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
// TODO going to remove random seed once cluster deployment supports re-run genesis
use rand::rngs::OsRng;

#[derive(Debug, StructOpt)]
#[structopt(about = "Forged in Fire")]
pub struct Options {
    /// The FILTER string is tested against the name of all tests, and only those tests whose names
    /// contain the filter are run.
    filter: Option<String>,
    #[structopt(long = "exact")]
    /// Exactly match filters rather than by substring
    filter_exact: bool,
    #[structopt(short = "q", long)]
    /// Output minimal information
    quiet: bool,
    #[structopt(long)]
    /// List all tests
    list: bool,
    #[structopt(long)]
    /// List or run ignored tests
    ignored: bool,
    #[structopt(long)]
    /// Include ignored tests when listing or running tests
    include_ignored: bool,
    /// Configure formatting of output:
    ///   pretty = Print verbose output;
    ///   terse = Display one character per test;
    ///   (json is unsupported, exists for compatibility with the default test harness)
    #[structopt(long, possible_values = &Format::variants(), default_value, case_insensitive = true)]
    format: Format,
}

impl Options {
    pub fn from_args() -> Self {
        StructOpt::from_args()
    }
}

arg_enum! {
    #[derive(Debug, Eq, PartialEq)]
    pub enum Format {
        Pretty,
        Terse,
        Json,
    }
}

impl Default for Format {
    fn default() -> Self {
        Format::Pretty
    }
}

pub fn forge_main<F: Factory>(tests: ForgeConfig<'_>, factory: F, options: &Options) -> Result<()> {
    let forge = Forge::new(options, tests, factory);

    if options.list {
        forge.list()?;

        return Ok(());
    }

    forge.run()
}

pub struct ForgeConfig<'cfg> {
    pub public_usage_tests: &'cfg [&'cfg dyn PublicUsageTest],
    pub admin_tests: &'cfg [&'cfg dyn AdminTest],
    pub network_tests: &'cfg [&'cfg dyn NetworkTest],
}

impl<'cfg> ForgeConfig<'cfg> {
    pub fn number_of_tests(&self) -> usize {
        self.public_usage_tests.len() + self.admin_tests.len() + self.network_tests.len()
    }

    pub fn all_tests(&self) -> impl Iterator<Item = &'cfg dyn Test> + 'cfg {
        self.public_usage_tests
            .iter()
            .map(|t| t as &dyn Test)
            .chain(self.admin_tests.iter().map(|t| t as &dyn Test))
            .chain(self.network_tests.iter().map(|t| t as &dyn Test))
    }
}

pub struct Forge<'cfg, F> {
    options: &'cfg Options,
    tests: ForgeConfig<'cfg>,
    factory: F,
}

impl<'cfg, F: Factory> Forge<'cfg, F> {
    pub fn new(options: &'cfg Options, tests: ForgeConfig<'cfg>, factory: F) -> Self {
        Self {
            options,
            tests,
            factory,
        }
    }

    pub fn list(&self) -> Result<()> {
        for test in self.tests.all_tests() {
            println!("{}: test", test.name());
        }

        if self.options.format == Format::Pretty {
            println!();
            println!("{} tests", self.tests.all_tests().count());
        }

        Ok(())
    }

    pub fn run(&self) -> Result<()> {
        let mut summary = TestSummary::new(self.filter_tests(self.tests.all_tests()).count(), 0);
        summary.write_starting_msg()?;

        let mut rng = ::rand::rngs::StdRng::from_seed(OsRng.gen());
        let mut swarm = self.factory.launch_swarm(1);

        // Run PublicUsageTests
        for test in self.filter_tests(self.tests.public_usage_tests.iter()) {
            let mut public_ctx = PublicUsageContext::new(
                CoreContext::from_rng(&mut rng),
                swarm.chain_info().into_public_info(),
            );
            let result = run_test(|| test.run(&mut public_ctx));
            summary.handle_result(test.name().to_owned(), result)?;
        }

        // Run AdminTests
        for test in self.filter_tests(self.tests.admin_tests.iter()) {
            let mut admin_ctx =
                AdminContext::new(CoreContext::from_rng(&mut rng), swarm.chain_info());
            let result = run_test(|| test.run(&mut admin_ctx));
            summary.handle_result(test.name().to_owned(), result)?;
        }

        for test in self.filter_tests(self.tests.network_tests.iter()) {
            let report = TestReport::new();
            let mut network_ctx =
                NetworkContext::new(CoreContext::from_rng(&mut rng), &mut *swarm, report);
            let result = run_test(|| test.run(&mut network_ctx));
            summary.handle_result(test.name().to_owned(), result)?;
        }

        summary.write_summary()?;

        if !summary.success() {
            process::exit(101);
        }

        Ok(())
    }

    fn filter_tests<'a, T: Test, I: Iterator<Item = T> + 'a>(
        &'a self,
        tests: I,
    ) -> impl Iterator<Item = T> + 'a {
        tests.filter(move |test| {
            if let Some(filter) = &self.options.filter {
                if self.options.filter_exact {
                    test.name() == &filter[..]
                } else {
                    test.name().contains(&filter[..])
                }
            } else {
                true
            }
        })
    }
}

enum TestResult {
    Ok,
    Failed,
    FailedWithMsg(String),
}

fn run_test<F: FnOnce() -> Result<()>>(f: F) -> TestResult {
    match ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(f)) {
        Ok(Ok(())) => TestResult::Ok,
        Ok(Err(e)) => TestResult::FailedWithMsg(format!("{:?}", e)),
        Err(_) => TestResult::Failed,
    }
}

struct TestSummary {
    stdout: StandardStream,
    total: usize,
    filtered_out: usize,
    passed: usize,
    failed: Vec<String>,
}

impl TestSummary {
    fn new(total: usize, filtered_out: usize) -> Self {
        Self {
            stdout: StandardStream::stdout(ColorChoice::Auto),
            total,
            filtered_out,
            passed: 0,
            failed: Vec::new(),
        }
    }

    fn handle_result(&mut self, name: String, result: TestResult) -> io::Result<()> {
        write!(self.stdout, "test {} ... ", name)?;
        match result {
            TestResult::Ok => {
                self.passed += 1;
                self.write_ok()?;
            }
            TestResult::Failed => {
                self.failed.push(name);
                self.write_failed()?;
            }
            TestResult::FailedWithMsg(msg) => {
                self.failed.push(name);
                self.write_failed()?;
                writeln!(self.stdout)?;

                write!(self.stdout, "Error: {}", msg)?;
            }
        }
        writeln!(self.stdout)?;
        Ok(())
    }

    fn write_ok(&mut self) -> io::Result<()> {
        self.stdout
            .set_color(ColorSpec::new().set_fg(Some(Color::Green)))?;
        write!(self.stdout, "ok")?;
        self.stdout.reset()?;
        Ok(())
    }

    fn write_failed(&mut self) -> io::Result<()> {
        self.stdout
            .set_color(ColorSpec::new().set_fg(Some(Color::Red)))?;
        write!(self.stdout, "FAILED")?;
        self.stdout.reset()?;
        Ok(())
    }

    fn write_starting_msg(&mut self) -> io::Result<()> {
        writeln!(self.stdout)?;
        writeln!(
            self.stdout,
            "running {} tests",
            self.total - self.filtered_out
        )?;
        Ok(())
    }

    fn write_summary(&mut self) -> io::Result<()> {
        // Print out the failing tests
        if !self.failed.is_empty() {
            writeln!(self.stdout)?;
            writeln!(self.stdout, "failures:")?;
            for name in &self.failed {
                writeln!(self.stdout, "    {}", name)?;
            }
        }

        writeln!(self.stdout)?;
        write!(self.stdout, "test result: ")?;
        if self.failed.is_empty() {
            self.write_ok()?;
        } else {
            self.write_failed()?;
        }
        writeln!(
            self.stdout,
            ". {} passed; {} failed; {} filtered out",
            self.passed,
            self.failed.len(),
            self.filtered_out
        )?;
        writeln!(self.stdout)?;
        Ok(())
    }

    fn success(&self) -> bool {
        self.failed.is_empty()
    }
}
<commit_msg>forge: properly cleanup resources in the presence of test failures<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::*;
use rand::{Rng, SeedableRng};
use std::{
    io::{self, Write},
    process,
};
use structopt::{clap::arg_enum, StructOpt};
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
// TODO going to remove random seed once cluster deployment supports re-run genesis
use rand::rngs::OsRng;

#[derive(Debug, StructOpt)]
#[structopt(about = "Forged in Fire")]
pub struct Options {
    /// The FILTER string is tested against the name of all tests, and only those tests whose names
    /// contain the filter are run.
    filter: Option<String>,
    #[structopt(long = "exact")]
    /// Exactly match filters rather than by substring
    filter_exact: bool,
    #[structopt(short = "q", long)]
    /// Output minimal information
    quiet: bool,
    #[structopt(long)]
    /// List all tests
    list: bool,
    #[structopt(long)]
    /// List or run ignored tests
    ignored: bool,
    #[structopt(long)]
    /// Include ignored tests when listing or running tests
    include_ignored: bool,
    /// Configure formatting of output:
    ///   pretty = Print verbose output;
    ///   terse = Display one character per test;
    ///   (json is unsupported, exists for compatibility with the default test harness)
    #[structopt(long, possible_values = &Format::variants(), default_value, case_insensitive = true)]
    format: Format,
}

impl Options {
    pub fn from_args() -> Self {
        StructOpt::from_args()
    }
}

arg_enum! {
    #[derive(Debug, Eq, PartialEq)]
    pub enum Format {
        Pretty,
        Terse,
        Json,
    }
}

impl Default for Format {
    fn default() -> Self {
        Format::Pretty
    }
}

pub fn forge_main<F: Factory>(tests: ForgeConfig<'_>, factory: F, options: &Options) -> Result<()> {
    let forge = Forge::new(options, tests, factory);

    if options.list {
        forge.list()?;

        return Ok(());
    }

    match forge.run() {
        Ok(()) => Ok(()),
        Err(_) => process::exit(101), // Exit with a non-zero exit code if tests failed
    }
}

pub struct ForgeConfig<'cfg> {
    pub public_usage_tests: &'cfg [&'cfg dyn PublicUsageTest],
    pub admin_tests: &'cfg [&'cfg dyn AdminTest],
    pub network_tests: &'cfg [&'cfg dyn NetworkTest],
}

impl<'cfg> ForgeConfig<'cfg> {
    pub fn number_of_tests(&self) -> usize {
        self.public_usage_tests.len() + self.admin_tests.len() + self.network_tests.len()
    }

    pub fn all_tests(&self) -> impl Iterator<Item = &'cfg dyn Test> + 'cfg {
        self.public_usage_tests
            .iter()
            .map(|t| t as &dyn Test)
            .chain(self.admin_tests.iter().map(|t| t as &dyn Test))
            .chain(self.network_tests.iter().map(|t| t as &dyn Test))
    }
}

pub struct Forge<'cfg, F> {
    options: &'cfg Options,
    tests: ForgeConfig<'cfg>,
    factory: F,
}

impl<'cfg, F: Factory> Forge<'cfg, F> {
    pub fn new(options: &'cfg Options, tests: ForgeConfig<'cfg>, factory: F) -> Self {
        Self {
            options,
            tests,
            factory,
        }
    }

    pub fn list(&self) -> Result<()> {
        for test in self.tests.all_tests() {
            println!("{}: test", test.name());
        }

        if self.options.format == Format::Pretty {
            println!();
            println!("{} tests", self.tests.all_tests().count());
        }

        Ok(())
    }

    pub fn run(&self) -> Result<()> {
        let mut summary = TestSummary::new(self.filter_tests(self.tests.all_tests()).count(), 0);
        summary.write_starting_msg()?;

        let mut rng = ::rand::rngs::StdRng::from_seed(OsRng.gen());
        let mut swarm = self.factory.launch_swarm(1);

        // Run PublicUsageTests
        for test in self.filter_tests(self.tests.public_usage_tests.iter()) {
            let mut public_ctx = PublicUsageContext::new(
                CoreContext::from_rng(&mut rng),
                swarm.chain_info().into_public_info(),
            );
            let result = run_test(|| test.run(&mut public_ctx));
            summary.handle_result(test.name().to_owned(), result)?;
        }

        // Run AdminTests
        for test in self.filter_tests(self.tests.admin_tests.iter()) {
            let mut admin_ctx =
                AdminContext::new(CoreContext::from_rng(&mut rng), swarm.chain_info());
            let result = run_test(|| test.run(&mut admin_ctx));
            summary.handle_result(test.name().to_owned(), result)?;
        }

        for test in self.filter_tests(self.tests.network_tests.iter()) {
            let report = TestReport::new();
            let mut network_ctx =
                NetworkContext::new(CoreContext::from_rng(&mut rng), &mut *swarm, report);
            let result = run_test(|| test.run(&mut network_ctx));
            summary.handle_result(test.name().to_owned(), result)?;
        }

        summary.write_summary()?;

        if summary.success() {
            Ok(())
        } else {
            Err(anyhow::anyhow!("Tests Failed"))
        }
    }

    fn filter_tests<'a, T: Test, I: Iterator<Item = T> + 'a>(
        &'a self,
        tests: I,
    ) -> impl Iterator<Item = T> + 'a {
        tests.filter(move |test| {
            if let Some(filter) = &self.options.filter {
                if self.options.filter_exact {
                    test.name() == &filter[..]
                } else {
                    test.name().contains(&filter[..])
                }
            } else {
                true
            }
        })
    }
}

enum TestResult {
    Ok,
    Failed,
    FailedWithMsg(String),
}

fn run_test<F: FnOnce() -> Result<()>>(f: F) -> TestResult {
    match ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(f)) {
        Ok(Ok(())) => TestResult::Ok,
        Ok(Err(e)) => TestResult::FailedWithMsg(format!("{:?}", e)),
        Err(_) => TestResult::Failed,
    }
}

struct TestSummary {
    stdout: StandardStream,
    total: usize,
    filtered_out: usize,
    passed: usize,
    failed: Vec<String>,
}

impl TestSummary {
    fn new(total: usize, filtered_out: usize) -> Self {
        Self {
            stdout: StandardStream::stdout(ColorChoice::Auto),
            total,
            filtered_out,
            passed: 0,
            failed: Vec::new(),
        }
    }

    fn handle_result(&mut self, name: String, result: TestResult) -> io::Result<()> {
        write!(self.stdout, "test {} ... ", name)?;
        match result {
            TestResult::Ok => {
                self.passed += 1;
                self.write_ok()?;
            }
            TestResult::Failed => {
                self.failed.push(name);
                self.write_failed()?;
            }
            TestResult::FailedWithMsg(msg) => {
                self.failed.push(name);
                self.write_failed()?;
                writeln!(self.stdout)?;

                write!(self.stdout, "Error: {}", msg)?;
            }
        }
        writeln!(self.stdout)?;
        Ok(())
    }

    fn write_ok(&mut self) -> io::Result<()> {
        self.stdout
            .set_color(ColorSpec::new().set_fg(Some(Color::Green)))?;
        write!(self.stdout, "ok")?;
        self.stdout.reset()?;
        Ok(())
    }

    fn write_failed(&mut self) -> io::Result<()> {
        self.stdout
            .set_color(ColorSpec::new().set_fg(Some(Color::Red)))?;
        write!(self.stdout, "FAILED")?;
        self.stdout.reset()?;
        Ok(())
    }

    fn write_starting_msg(&mut self) -> io::Result<()> {
        writeln!(self.stdout)?;
        writeln!(
            self.stdout,
            "running {} tests",
            self.total - self.filtered_out
        )?;
        Ok(())
    }

    fn write_summary(&mut self) -> io::Result<()> {
        // Print out the failing tests
        if !self.failed.is_empty() {
            writeln!(self.stdout)?;
            writeln!(self.stdout, "failures:")?;
            for name in &self.failed {
                writeln!(self.stdout, "    {}", name)?;
            }
        }

        writeln!(self.stdout)?;
        write!(self.stdout, "test result: ")?;
        if self.failed.is_empty() {
            self.write_ok()?;
        } else {
            self.write_failed()?;
        }
        writeln!(
            self.stdout,
            ". {} passed; {} failed; {} filtered out",
            self.passed,
            self.failed.len(),
            self.filtered_out
        )?;
        writeln!(self.stdout)?;
        Ok(())
    }

    fn success(&self) -> bool {
        self.failed.is_empty()
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use move_lang::test_utils::*;
use std::{collections::HashSet, path::Path};

#[test]
fn test_ir_test_coverage() {
    for completed_directory in COMPLETED_DIRECTORIES {
        let dir = format!("{}/{}", PATH_TO_IR_TESTS, completed_directory);
        let p = Path::new(&dir);
        if !p.is_dir() {
            panic!("Invalid completed directory. '{}' does not exist", dir)
        }
    }
    let completed_directories: HashSet<String> = COMPLETED_DIRECTORIES
        .iter()
        .map(|s| (*s).to_owned())
        .collect();

    let not_migrated = ir_tests()
        .filter(|(subdir, name)| {
            completed_directories.contains(subdir) && !translated_test_exists(subdir, name)
        })
        .map(|(subdir, name)| format!("{}/{}/{}", PATH_TO_IR_TESTS, subdir, name))
        .collect::<Vec<_>>();
    if !not_migrated.is_empty() {
        let mut msg = "\nThe following tests have not been migrated:\n".to_owned();
        for path in not_migrated {
            msg.push_str(&format!("{}\n", path));
        }
        panic!(msg)
    }
}

fn translated_test_exists(subdir: &str, name_str: &str) -> bool {
    let mut stem = name_str.to_owned();
    (0..=IR_EXTENSION.len()).for_each(|_| {
        stem.pop().unwrap();
    });
    let stem_str = &stem;
    translated_ir_test_name(false, subdir, stem_str).is_none()
}
<commit_msg>[move source language] Added help to ir_test_coverage<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use move_lang::test_utils::*;
use std::{collections::HashSet, path::Path};

#[test]
fn test_ir_test_coverage() {
    for completed_directory in COMPLETED_DIRECTORIES {
        let dir = format!("{}/{}", PATH_TO_IR_TESTS, completed_directory);
        let p = Path::new(&dir);
        if !p.is_dir() {
            panic!("Invalid completed directory. '{}' does not exist", dir)
        }
    }
    let completed_directories: HashSet<String> = COMPLETED_DIRECTORIES
        .iter()
        .map(|s| (*s).to_owned())
        .collect();

    let not_migrated = ir_tests()
        .filter(|(subdir, name)| {
            completed_directories.contains(subdir) && !translated_test_exists(subdir, name)
        })
        .map(|(subdir, name)| format!("{}/{}/{}", PATH_TO_IR_TESTS, subdir, name))
        .collect::<Vec<_>>();
    if !not_migrated.is_empty() {
        let mut msg = "\n\nThe following tests have not been migrated:\n".to_owned();
        for path in not_migrated {
            msg.push_str(&format!("{}\n", path));
        }
        msg.push_str("\nA corresponding test needs to be added:\n");
        msg.push_str(&format!(
            "    {}/{}/<dir name>/<test name>.{}\n",
            MOVE_CHECK_DIR, STD_LIB_TRANSACTION_SCRIPTS_DIR, MOVE_EXTENSION
        ));
        msg.push_str("  or\n");
        msg.push_str(&format!(
            "    {}/{}/<dir name>/<test name>.{}\n",
            FUNCTIONAL_TEST_DIR, STD_LIB_TRANSACTION_SCRIPTS_DIR, MOVE_EXTENSION
        ));
        msg.push_str(&format!(
            "Replace the extension '.{}' with '.{}' to mark the test as present, but it will not \
            be run.\n\n",
            MOVE_EXTENSION, TODO_EXTENSION
        ));
        msg.push_str("Running the following tool may help with the migration:\n");
        msg.push_str("  cargo run -p move-lang --bin ir-test-translation -- -d <dir_name>\n\n");
        panic!(msg)
    }
}

fn translated_test_exists(subdir: &str, name_str: &str) -> bool {
    let mut stem = name_str.to_owned();
    (0..=IR_EXTENSION.len()).for_each(|_| {
        stem.pop().unwrap();
    });
    let stem_str = &stem;
    translated_ir_test_name(false, subdir, stem_str).is_none()
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! SOS memory allocation library
//!
//! This is in its own crate so it can be used by kernel-space and user-space
//! OS components.
#![crate_name = "alloc"]
#![crate_type = "lib"]

// The compiler needs to be instructed that this crate is an allocator in order
// to realize that when this is linked in another allocator like jemalloc
// should not be linked in
#![cfg_attr( feature = "as_system", feature(allocator) )]
#![cfg_attr( feature = "as_system", allocator )]

#![cfg_attr( feature = "buddy", feature(unique))]

#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]

// Allocators are not allowed to depend on the standard library which in turn
// requires an allocator in order to avoid circular dependencies. This crate,
// however, can use all of libcore.
#![no_std]

#![feature( const_fn )]

#[cfg(feature = "buddy")]
extern crate sos_intrusive as intrusive;
#[cfg(feature = "buddy_as_system")]
extern crate spin;
extern crate memory;

#[macro_use]
extern crate log;

#[cfg(test)] #[macro_use]
extern crate std;

/// Trait for something that is like a frame.
///
/// Various allocation strategies use different data structures for
/// representing frames. For example, frames may be stored as frame numbers or
/// as nodes in a linked list. To be `Framesque`, an object need only provide
/// a function to convert the frame data to a pointer to the frame in memory.
pub trait Framesque {
    /// Return a pointer to the frame in memory.
    fn as_ptr(&self) -> *mut u8;
}

#[cfg(feature = "buddy")]
pub mod buddy;
<commit_msg>[alloc] more trying to fix alloc tests on CI<commit_after>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! SOS memory allocation library
//!
//! This is in its own crate so it can be used by kernel-space and user-space
//! OS components.
#![crate_name = "alloc"]
#![crate_type = "lib"]

// The compiler needs to be instructed that this crate is an allocator in order
// to realize that when this is linked in another allocator like jemalloc
// should not be linked in
#![cfg_attr( feature = "as_system", feature(allocator) )]
#![cfg_attr( feature = "as_system", allocator )]

#![cfg_attr( feature = "buddy", feature(unique))]

#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]

// Allocators are not allowed to depend on the standard library which in turn
// requires an allocator in order to avoid circular dependencies. This crate,
// however, can use all of libcore.
#![no_std]

#![feature( const_fn )]

#[cfg(feature = "buddy")]
extern crate sos_intrusive as intrusive;
#[cfg(feature = "buddy_as_system")]
extern crate spin;
extern crate memory;

#[macro_use]
extern crate log;

/// Trait for something that is like a frame.
///
/// Various allocation strategies use different data structures for
/// representing frames. For example, frames may be stored as frame numbers or
/// as nodes in a linked list. To be `Framesque`, an object need only provide
/// a function to convert the frame data to a pointer to the frame in memory.
pub trait Framesque {
    /// Return a pointer to the frame in memory.
    fn as_ptr(&self) -> *mut u8;
}

#[cfg(feature = "buddy")]
pub mod buddy;
<|endoftext|>


<commit_before>// This file is part of rgtk.
//
// rgtk is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// rgtk is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with rgtk.  If not, see <http://www.gnu.org/licenses/>.

//! A box with a centered child

// FIXME: add missing methods (3.12)

use gtk::cast::{GTK_HEADER_BAR};
use gtk::ffi;
use gtk::traits;
use std::string;

/// GtkHeaderBar — A box with a centered child
struct_Widget!(HeaderBar)

impl HeaderBar {
    pub fn new() -> Option<HeaderBar> {
        let tmp_pointer = unsafe { ffi::gtk_header_bar_new() };
        check_pointer!(tmp_pointer, HeaderBar)
    }

    pub fn set_title(&mut self, title: &str) {
        unsafe {
            title.with_c_str(|c_str| {
                ffi::gtk_header_bar_set_title(GTK_HEADER_BAR(self.pointer), c_str)
            })
        }
    }

    pub fn get_title(&self) -> Option<String> {
        let c_title = unsafe { ffi::gtk_header_bar_get_title(GTK_HEADER_BAR(self.pointer)) };
        if c_title.is_null() {
            None
        } else {
            Some(unsafe { string::raw::from_buf(c_title as *const u8) })
        }
    }

    pub fn set_subtitle(&mut self, subtitle: &str) {
        unsafe {
            subtitle.with_c_str(|c_str| {
                ffi::gtk_header_bar_set_subtitle(GTK_HEADER_BAR(self.pointer), c_str)
            })
        }
    }

    pub fn get_subtitle(&self) -> Option<String> {
        let c_subtitle = unsafe { ffi::gtk_header_bar_get_title(GTK_HEADER_BAR(self.pointer)) };
        if c_subtitle.is_null() {
            None
        } else {
            Some(unsafe { string::raw::from_buf(c_subtitle as *const u8) })
        }
    }

    pub fn set_custom_title<T: traits::Widget>(&mut self, title_widget: Option<&T>) {
        unsafe {
            ffi::gtk_header_bar_set_custom_title(GTK_HEADER_BAR(self.pointer),
                                                 get_widget!(title_widget))
        }
    }

    pub fn get_custom_title<T: traits::Widget>(&self) -> Option<T> {
        let tmp_pointer = unsafe {
            ffi::gtk_header_bar_get_custom_title(GTK_HEADER_BAR(self.pointer))
        };
        if tmp_pointer.is_null() {
            None
        } else {
            Some(ffi::FFIWidget::wrap(tmp_pointer))
        }
    }

    pub fn pack_start<T: traits::Widget>(&mut self, child: &T) {
        unsafe {
            ffi::gtk_header_bar_pack_start(GTK_HEADER_BAR(self.pointer),
                                           child.get_widget())
        }
    }

    pub fn pack_end<T: traits::Widget>(&mut self, child: &T) {
        unsafe {
            ffi::gtk_header_bar_pack_end(GTK_HEADER_BAR(self.pointer),
                                         child.get_widget())
        }
    }

    pub fn is_close_button_show(&self) -> bool {
        unsafe {
            ffi::to_bool(ffi::gtk_header_bar_get_show_close_button(GTK_HEADER_BAR(self.pointer)))
        }
    }

    pub fn set_close_button_show(&mut self, setting: bool) {
        unsafe {
            ffi::gtk_header_bar_set_show_close_button(GTK_HEADER_BAR(self.pointer),
                                                      ffi::to_gboolean(setting))
        }
    }
}

impl_drop!(HeaderBar)
impl_TraitWidget!(HeaderBar)

impl traits::Container for HeaderBar {}
<commit_msg>rename close_button_show to show_close_button to match gtk naming<commit_after>// This file is part of rgtk.
//
// rgtk is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// rgtk is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with rgtk.  If not, see <http://www.gnu.org/licenses/>.

//! A box with a centered child

// FIXME: add missing methods (3.12)

use gtk::cast::{GTK_HEADER_BAR};
use gtk::ffi;
use gtk::traits;
use std::string;

/// GtkHeaderBar — A box with a centered child
struct_Widget!(HeaderBar)

impl HeaderBar {
    pub fn new() -> Option<HeaderBar> {
        let tmp_pointer = unsafe { ffi::gtk_header_bar_new() };
        check_pointer!(tmp_pointer, HeaderBar)
    }

    pub fn set_title(&mut self, title: &str) {
        unsafe {
            title.with_c_str(|c_str| {
                ffi::gtk_header_bar_set_title(GTK_HEADER_BAR(self.pointer), c_str)
            })
        }
    }

    pub fn get_title(&self) -> Option<String> {
        let c_title = unsafe { ffi::gtk_header_bar_get_title(GTK_HEADER_BAR(self.pointer)) };
        if c_title.is_null() {
            None
        } else {
            Some(unsafe { string::raw::from_buf(c_title as *const u8) })
        }
    }

    pub fn set_subtitle(&mut self, subtitle: &str) {
        unsafe {
            subtitle.with_c_str(|c_str| {
                ffi::gtk_header_bar_set_subtitle(GTK_HEADER_BAR(self.pointer), c_str)
            })
        }
    }

    pub fn get_subtitle(&self) -> Option<String> {
        let c_subtitle = unsafe { ffi::gtk_header_bar_get_title(GTK_HEADER_BAR(self.pointer)) };
        if c_subtitle.is_null() {
            None
        } else {
            Some(unsafe { string::raw::from_buf(c_subtitle as *const u8) })
        }
    }

    pub fn set_custom_title<T: traits::Widget>(&mut self, title_widget: Option<&T>) {
        unsafe {
            ffi::gtk_header_bar_set_custom_title(GTK_HEADER_BAR(self.pointer),
                                                 get_widget!(title_widget))
        }
    }

    pub fn get_custom_title<T: traits::Widget>(&self) -> Option<T> {
        let tmp_pointer = unsafe {
            ffi::gtk_header_bar_get_custom_title(GTK_HEADER_BAR(self.pointer))
        };
        if tmp_pointer.is_null() {
            None
        } else {
            Some(ffi::FFIWidget::wrap(tmp_pointer))
        }
    }

    pub fn pack_start<T: traits::Widget>(&mut self, child: &T) {
        unsafe {
            ffi::gtk_header_bar_pack_start(GTK_HEADER_BAR(self.pointer),
                                           child.get_widget())
        }
    }

    pub fn pack_end<T: traits::Widget>(&mut self, child: &T) {
        unsafe {
            ffi::gtk_header_bar_pack_end(GTK_HEADER_BAR(self.pointer),
                                         child.get_widget())
        }
    }

    pub fn is_show_close_button(&self) -> bool {
        unsafe {
            ffi::to_bool(ffi::gtk_header_bar_get_show_close_button(GTK_HEADER_BAR(self.pointer)))
        }
    }

    pub fn set_show_close_button(&mut self, setting: bool) {
        unsafe {
            ffi::gtk_header_bar_set_show_close_button(GTK_HEADER_BAR(self.pointer),
                                                      ffi::to_gboolean(setting))
        }
    }
}

impl_drop!(HeaderBar)
impl_TraitWidget!(HeaderBar)

impl traits::Container for HeaderBar {}
<|endoftext|>


<commit_before>use super::*;
use byteorder::{BigEndian, WriteBytesExt};
use std::io::{self, Write};
use std::cmp;

#[derive(Debug)]
pub enum PacketEncodingError {
    //Not enough space in the buffer.
    TooLarge,
    //Data didn't validate.
    Invalid,
}

pub struct PacketWriter<'a> {
    slice: &'a mut[u8],
    index: usize,
}

impl<'a> PacketWriter<'a> {
    pub fn new(destination: &'a mut[u8])->PacketWriter {
        PacketWriter{slice: destination, index: 0}
    }

    pub fn written(&self)->usize {
        self.index
    }

    pub fn available(&self)->usize {
        self.slice.len()-self.index
    }
}

impl<'a> Write for PacketWriter<'a> {
    fn write(&mut self, buf: &[u8])->io::Result<usize> {
        let available = self.slice.len()-self.index;
        let willWrite = cmp::min(available, buf.len());
        for i in 0..willWrite {
            self.slice[self.index+i] = buf[i];
        }
        self.index += willWrite;
        Ok(willWrite)
    }

    fn flush(&mut self)->io::Result<()> {
        Ok(())
    }
}

pub trait Encodable {
    fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError>;
}

impl Encodable for Packet {
    fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> {
        use self::PacketEncodingError::*;
        match *self {
            Packet::StatusRequest(ref req) => {
                try!(CONNECTION_CHANNEL.encode(destination));
                try!(0u8.encode(destination));
                try!(req.encode(destination));
            },
            Packet::StatusResponse(ref resp) => {
                try!(CONNECTION_CHANNEL.encode(destination));
                try!(1u8.encode(destination));
                try!(resp.encode(destination));
            },
            Packet::Connect => {
                try!(CONNECTION_CHANNEL.encode(destination));
                try!(2u8.encode(destination));
            },
            Packet::Connected(id) => {
                try!(CONNECTION_CHANNEL.encode(destination));
                try!(3u8.encode(destination));
                try!(id.encode(destination));
            },
            Packet::Aborted(ref msg) => {
                try!(CONNECTION_CHANNEL.encode(destination));
                try!(4.encode(destination));
                try!(msg.encode(destination));
            },
            Packet::Heartbeat(value) => {
                try!(HEARTBEAT_CHANNEL.encode(destination));
                try!(value.encode(destination));
            },
            Packet::ResetMTUCount{channel: chan} => {
                if chan != MTU_CLIENT_ESTIMATION_CHANNEL || chan != MTU_SERVER_ESTIMATION_CHANNEL {return Err(Invalid)};
                try!(chan.encode(destination));
                try!(0u8.encode(destination));
            },
            Packet::MTUCountWasReset{channel: chan} => {
                if chan != MTU_CLIENT_ESTIMATION_CHANNEL || chan != MTU_SERVER_ESTIMATION_CHANNEL {return Err(Invalid)};
                try!(chan.encode(destination));
                try!(1u8.encode(destination));
            },
            Packet::MTUEstimate{channel: chan, payload: ref p} => {
                if chan != MTU_CLIENT_ESTIMATION_CHANNEL || chan != MTU_SERVER_ESTIMATION_CHANNEL {return Err(Invalid)};
                try!(chan.encode(destination));
                try!(2u8.encode(destination));
                try!(destination.write_all(p).or(Err(TooLarge)));
            },
            Packet::MTUResponse{channel: chan, count: c} => {
                if chan != MTU_CLIENT_ESTIMATION_CHANNEL || chan != MTU_SERVER_ESTIMATION_CHANNEL {return Err(Invalid)};
                try!(chan.encode(destination));
                try!(3u8.encode(destination));
                try!(c.encode(destination));
            },
        }
    Ok(())
    }
}

impl Encodable for StatusRequest {
    fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> {
        use self::PacketEncodingError::*;
        match *self {
            StatusRequest::FastnetQuery => {
                try!(0u8.encode(destination));
            },
            StatusRequest::VersionQuery => {
                try!(1u8.encode(destination));
            },
            StatusRequest::ExtensionQuery(ref name) => {
                try!(2u8.encode(destination));
                try!(name.encode(destination));
            },
        }
        Ok(())
    }
}

impl Encodable for StatusResponse {
    fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> {
        use self::PacketEncodingError::*;
        match *self {
            StatusResponse::FastnetResponse(value) => {
                try!(0u8.encode(destination));
                try!(value.encode(destination));
            },
            StatusResponse::VersionResponse(ref version) => {
                try!(1u8.encode(destination));
                try!(version.encode(destination));
            },
            StatusResponse::ExtensionResponse{ref name, supported} => {
                try!(2u8.encode(destination));
                try!(name.encode(destination));
                try!(supported.encode(destination));
            },
        }
        Ok(())
    }
}

//Encoding integer types:

impl Encodable for i8 {
    fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> {
        try!(destination.write_i8(*self).or(Err(PacketEncodingError::TooLarge)));
        Ok(())
    }
}

impl Encodable for u8 {
    fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> {
        try!(destination.write_u8(*self).or(Err(PacketEncodingError::TooLarge)));
        Ok(())
    }
}

impl Encodable for i16 {
    fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> {
        try!(destination.write_i16::<BigEndian>(*self).or(Err(PacketEncodingError::TooLarge)));
        Ok(())
    }
}

impl Encodable for u16 {
    fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> {
        try!(destination.write_u16::<BigEndian>(*self).or(Err(PacketEncodingError::TooLarge)));
        Ok(())
    }
}

impl Encodable for i32 {
    fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> {
        try!(destination.write_i32::<BigEndian>(*self).or(Err(PacketEncodingError::TooLarge)));
        return Ok(())
    }
}

impl Encodable for u32 {
    fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> {
        try!(destination.write_u32::<BigEndian>(*self).or(Err(PacketEncodingError::TooLarge)));
        Ok(())
    }
}

//These are the two string types.
//The Fastnet spec requires null-termination.  Rust strings are not null terminated.

fn encode_string_slice(data: &[u8], destination: &mut PacketWriter)->Result<(), PacketEncodingError> {
    use self::PacketEncodingError::*;
    if data.iter().any(|&x| x == 0) {return Err(Invalid)};
    try!(destination.write_all(data).or(Err(TooLarge)));
    try!(0u8.encode(destination));
    Ok(())
}

impl Encodable for str {
    fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> {
        encode_string_slice(self.as_bytes(), destination)
    }
}

impl Encodable for String {
    fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> {
        encode_string_slice(self.as_bytes(), destination)
    }
}

<commit_msg>Slices of encodable things are encodable.<commit_after>use super::*;
use byteorder::{BigEndian, WriteBytesExt};
use std::io::{self, Write};
use std::cmp;

#[derive(Debug)]
pub enum PacketEncodingError {
    //Not enough space in the buffer.
    TooLarge,
    //Data didn't validate.
    Invalid,
}

pub struct PacketWriter<'a> {
    slice: &'a mut[u8],
    index: usize,
}

impl<'a> PacketWriter<'a> {
    pub fn new(destination: &'a mut[u8])->PacketWriter {
        PacketWriter{slice: destination, index: 0}
    }

    pub fn written(&self)->usize {
        self.index
    }

    pub fn available(&self)->usize {
        self.slice.len()-self.index
    }
}

impl<'a> Write for PacketWriter<'a> {
    fn write(&mut self, buf: &[u8])->io::Result<usize> {
        let available = self.slice.len()-self.index;
        let willWrite = cmp::min(available, buf.len());
        for i in 0..willWrite {
            self.slice[self.index+i] = buf[i];
        }
        self.index += willWrite;
        Ok(willWrite)
    }

    fn flush(&mut self)->io::Result<()> {
        Ok(())
    }
}

pub trait Encodable {
    fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError>;
}

impl Encodable for Packet {
    fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> {
        use self::PacketEncodingError::*;
        match *self {
            Packet::StatusRequest(ref req) => {
                try!(CONNECTION_CHANNEL.encode(destination));
                try!(0u8.encode(destination));
                try!(req.encode(destination));
            },
            Packet::StatusResponse(ref resp) => {
                try!(CONNECTION_CHANNEL.encode(destination));
                try!(1u8.encode(destination));
                try!(resp.encode(destination));
            },
            Packet::Connect => {
                try!(CONNECTION_CHANNEL.encode(destination));
                try!(2u8.encode(destination));
            },
            Packet::Connected(id) => {
                try!(CONNECTION_CHANNEL.encode(destination));
                try!(3u8.encode(destination));
                try!(id.encode(destination));
            },
            Packet::Aborted(ref msg) => {
                try!(CONNECTION_CHANNEL.encode(destination));
                try!(4.encode(destination));
                try!(msg.encode(destination));
            },
            Packet::Heartbeat(value) => {
                try!(HEARTBEAT_CHANNEL.encode(destination));
                try!(value.encode(destination));
            },
            Packet::ResetMTUCount{channel: chan} => {
                if chan != MTU_CLIENT_ESTIMATION_CHANNEL || chan != MTU_SERVER_ESTIMATION_CHANNEL {return Err(Invalid)};
                try!(chan.encode(destination));
                try!(0u8.encode(destination));
            },
            Packet::MTUCountWasReset{channel: chan} => {
                if chan != MTU_CLIENT_ESTIMATION_CHANNEL || chan != MTU_SERVER_ESTIMATION_CHANNEL {return Err(Invalid)};
                try!(chan.encode(destination));
                try!(1u8.encode(destination));
            },
            Packet::MTUEstimate{channel: chan, payload: ref p} => {
                if chan != MTU_CLIENT_ESTIMATION_CHANNEL || chan != MTU_SERVER_ESTIMATION_CHANNEL {return Err(Invalid)};
                try!(chan.encode(destination));
                try!(2u8.encode(destination));
                try!(destination.write_all(p).or(Err(TooLarge)));
            },
            Packet::MTUResponse{channel: chan, count: c} => {
                if chan != MTU_CLIENT_ESTIMATION_CHANNEL || chan != MTU_SERVER_ESTIMATION_CHANNEL {return Err(Invalid)};
                try!(chan.encode(destination));
                try!(3u8.encode(destination));
                try!(c.encode(destination));
            },
        }
    Ok(())
    }
}

impl Encodable for StatusRequest {
    fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> {
        use self::PacketEncodingError::*;
        match *self {
            StatusRequest::FastnetQuery => {
                try!(0u8.encode(destination));
            },
            StatusRequest::VersionQuery => {
                try!(1u8.encode(destination));
            },
            StatusRequest::ExtensionQuery(ref name) => {
                try!(2u8.encode(destination));
                try!(name.encode(destination));
            },
        }
        Ok(())
    }
}

impl Encodable for StatusResponse {
    fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> {
        use self::PacketEncodingError::*;
        match *self {
            StatusResponse::FastnetResponse(value) => {
                try!(0u8.encode(destination));
                try!(value.encode(destination));
            },
            StatusResponse::VersionResponse(ref version) => {
                try!(1u8.encode(destination));
                try!(version.encode(destination));
            },
            StatusResponse::ExtensionResponse{ref name, supported} => {
                try!(2u8.encode(destination));
                try!(name.encode(destination));
                try!(supported.encode(destination));
            },
        }
        Ok(())
    }
}

//Encoding integer types:

impl Encodable for i8 {
    fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> {
        try!(destination.write_i8(*self).or(Err(PacketEncodingError::TooLarge)));
        Ok(())
    }
}

impl Encodable for u8 {
    fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> {
        try!(destination.write_u8(*self).or(Err(PacketEncodingError::TooLarge)));
        Ok(())
    }
}

impl Encodable for i16 {
    fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> {
        try!(destination.write_i16::<BigEndian>(*self).or(Err(PacketEncodingError::TooLarge)));
        Ok(())
    }
}

impl Encodable for u16 {
    fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> {
        try!(destination.write_u16::<BigEndian>(*self).or(Err(PacketEncodingError::TooLarge)));
        Ok(())
    }
}

impl Encodable for i32 {
    fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> {
        try!(destination.write_i32::<BigEndian>(*self).or(Err(PacketEncodingError::TooLarge)));
        return Ok(())
    }
}

impl Encodable for u32 {
    fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> {
        try!(destination.write_u32::<BigEndian>(*self).or(Err(PacketEncodingError::TooLarge)));
        Ok(())
    }
}

//These are the two string types.
//The Fastnet spec requires null-termination.  Rust strings are not null terminated.

fn encode_string_slice(data: &[u8], destination: &mut PacketWriter)->Result<(), PacketEncodingError> {
    use self::PacketEncodingError::*;
    if data.iter().any(|&x| x == 0) {return Err(Invalid)};
    try!(data.encode(destination));
    try!(0u8.encode(destination));
    Ok(())
}

impl Encodable for str {
    fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> {
        encode_string_slice(self.as_bytes(), destination)
    }
}

impl Encodable for String {
    fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> {
        encode_string_slice(self.as_bytes(), destination)
    }
}

//We can write an impl for slices of encodable things, if we want.

impl<T> Encodable for [T] where T: Encodable {
    fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> {
        for i in self {
            try!(i.encode(destination));
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>use super::ParallelIterator;
use super::len::*;
use super::internal::*;

/// Specifies a "reduce operator". This is the combination of a start
/// value and a reduce function. The reduce function takes two items
/// and computes a reduced version. The start value `S` is a kind of
/// "zero" or "identity" value that may be intermingled as needed;
/// ideally, `reduce(S, X)` for any item `X` yields `X`.
///
/// Example: to sum up the values, use a `start_value` of `0` and a
/// reduce function of `reduce(a, b) = a + b`.
///
/// The order in which the reduce function will be applied is not
/// specified. For example, the input `[ 0 1 2 ]` might be reduced in a
/// sequential fashion:
///
/// ```ignore
/// reduce(reduce(reduce(S, 0), 1), 2)
/// ```
///
/// or it might be reduced in a tree-like way:
///
/// ```ignore
/// reduce(reduce(0, 1), reduce(S, 2))
/// ```
///
/// etc.
pub trait ReduceOp<T>: Sync {
    fn start_value(&self) -> T;
    fn reduce(&self, value1: T, value2: T) -> T;
}

pub fn reduce<PAR_ITER, REDUCE_OP, T>(pi: PAR_ITER, reduce_op: &REDUCE_OP) -> T
    where PAR_ITER: ParallelIterator<Item = T>,
          REDUCE_OP: ReduceOp<T>,
          T: Send
{
    let consumer = ReduceConsumer { reduce_op: reduce_op };
    pi.drive_unindexed(consumer)
}

struct ReduceConsumer<'r, REDUCE_OP: 'r> {
    reduce_op: &'r REDUCE_OP,
}

impl<'r, REDUCE_OP> Copy for ReduceConsumer<'r, REDUCE_OP> {}

impl<'r, REDUCE_OP> Clone for ReduceConsumer<'r, REDUCE_OP> {
    fn clone(&self) -> Self {
        *self
    }
}

impl<'r, REDUCE_OP, ITEM> Consumer<ITEM> for ReduceConsumer<'r, REDUCE_OP>
    where REDUCE_OP: ReduceOp<ITEM>,
          ITEM: Send
{
    type Folder = ReduceFolder<'r, REDUCE_OP, ITEM>;
    type Reducer = Self;
    type Result = ITEM;

    fn cost(&mut self, cost: f64) -> f64 {
        // This isn't quite right, as we will do more than O(n) reductions, but whatever.
        cost * FUNC_ADJUSTMENT
    }

    fn split_at(self, _index: usize) -> (Self, Self, Self) {
        (self, self, self)
    }

    fn into_folder(self) -> ReduceFolder<'r, REDUCE_OP, ITEM> {
        ReduceFolder {
            reduce_op: self.reduce_op,
            item: self.reduce_op.start_value(),
        }
    }
}

impl<'r, REDUCE_OP, ITEM> UnindexedConsumer<ITEM> for ReduceConsumer<'r, REDUCE_OP>
    where REDUCE_OP: ReduceOp<ITEM>,
          ITEM: Send
{
    fn split_off(&self) -> Self {
        ReduceConsumer { reduce_op: self.reduce_op }
    }

    fn to_reducer(&self) -> Self::Reducer {
        *self
    }
}

impl<'r, REDUCE_OP, ITEM> Reducer<ITEM> for ReduceConsumer<'r, REDUCE_OP>
    where REDUCE_OP: ReduceOp<ITEM>
{
    fn reduce(self, left: ITEM, right: ITEM) -> ITEM {
        self.reduce_op.reduce(left, right)
    }
}

pub struct ReduceFolder<'r, REDUCE_OP: 'r, ITEM> {
    reduce_op: &'r REDUCE_OP,
    item: ITEM,
}

impl<'r, REDUCE_OP, ITEM> Folder<ITEM> for ReduceFolder<'r, REDUCE_OP, ITEM>
    where REDUCE_OP: ReduceOp<ITEM>
{
    type Result = ITEM;

    fn consume(self, item: ITEM) -> Self {
        let item = self.reduce_op.reduce(self.item, item);
        ReduceFolder {
            reduce_op: self.reduce_op,
            item: item,
        }
    }

    fn complete(self) -> ITEM {
        self.item
    }
}

/// ////////////////////////////////////////////////////////////////////////
/// Specific operations

pub struct SumOp;

pub const SUM: &'static SumOp = &SumOp;

macro_rules! sum_rule {
    ($i:ty, $z:expr) => {
        impl ReduceOp<$i> for SumOp {
            fn start_value(&self) -> $i {
                $z
            }
            fn reduce(&self, value1: $i, value2: $i) -> $i {
                value1 + value2
            }
        }
    }
}

sum_rule!(i8, 0);
sum_rule!(i16, 0);
sum_rule!(i32, 0);
sum_rule!(i64, 0);
sum_rule!(isize, 0);
sum_rule!(u8, 0);
sum_rule!(u16, 0);
sum_rule!(u32, 0);
sum_rule!(u64, 0);
sum_rule!(usize, 0);
sum_rule!(f32, 0.0);
sum_rule!(f64, 0.0);

pub struct ProductOp;

pub const PRODUCT: &'static ProductOp = &ProductOp;

macro_rules! product_rule {
    ($i:ty, $z:expr) => {
        impl ReduceOp<$i> for ProductOp {
            fn start_value(&self) -> $i {
                $z
            }
            fn reduce(&self, value1: $i, value2: $i) -> $i {
                value1 * value2
            }
        }
    }
}

product_rule!(i8, 1);
product_rule!(i16, 1);
product_rule!(i32, 1);
product_rule!(i64, 1);
product_rule!(isize, 1);
product_rule!(u8, 1);
product_rule!(u16, 1);
product_rule!(u32, 1);
product_rule!(u64, 1);
product_rule!(usize, 1);
product_rule!(f32, 1.0);
product_rule!(f64, 1.0);

pub struct ReduceWithIdentityOp<'r, IDENTITY: 'r, OP: 'r> {
    identity: &'r IDENTITY,
    op: &'r OP,
}

impl<'r, IDENTITY, OP> ReduceWithIdentityOp<'r, IDENTITY, OP> {
    pub fn new(identity: &'r IDENTITY, op: &'r OP) -> ReduceWithIdentityOp<'r, IDENTITY, OP> {
        ReduceWithIdentityOp {
            identity: identity,
            op: op,
        }
    }
}

impl<'r, IDENTITY, OP, ITEM> ReduceOp<ITEM> for ReduceWithIdentityOp<'r, IDENTITY, OP>
    where OP: Fn(ITEM, ITEM) -> ITEM + Sync,
          IDENTITY: Fn() -> ITEM + Sync,
          ITEM: 'r
{
    fn start_value(&self) -> ITEM {
        (self.identity)()
    }

    fn reduce(&self, value1: ITEM, value2: ITEM) -> ITEM {
        (self.op)(value1, value2)
    }
}
<commit_msg>reduce: Add #[inline] on the primitive numeric type impls<commit_after>use super::ParallelIterator;
use super::len::*;
use super::internal::*;

/// Specifies a "reduce operator". This is the combination of a start
/// value and a reduce function. The reduce function takes two items
/// and computes a reduced version. The start value `S` is a kind of
/// "zero" or "identity" value that may be intermingled as needed;
/// ideally, `reduce(S, X)` for any item `X` yields `X`.
///
/// Example: to sum up the values, use a `start_value` of `0` and a
/// reduce function of `reduce(a, b) = a + b`.
///
/// The order in which the reduce function will be applied is not
/// specified. For example, the input `[ 0 1 2 ]` might be reduced in a
/// sequential fashion:
///
/// ```ignore
/// reduce(reduce(reduce(S, 0), 1), 2)
/// ```
///
/// or it might be reduced in a tree-like way:
///
/// ```ignore
/// reduce(reduce(0, 1), reduce(S, 2))
/// ```
///
/// etc.
pub trait ReduceOp<T>: Sync {
    fn start_value(&self) -> T;
    fn reduce(&self, value1: T, value2: T) -> T;
}

pub fn reduce<PAR_ITER, REDUCE_OP, T>(pi: PAR_ITER, reduce_op: &REDUCE_OP) -> T
    where PAR_ITER: ParallelIterator<Item = T>,
          REDUCE_OP: ReduceOp<T>,
          T: Send
{
    let consumer = ReduceConsumer { reduce_op: reduce_op };
    pi.drive_unindexed(consumer)
}

struct ReduceConsumer<'r, REDUCE_OP: 'r> {
    reduce_op: &'r REDUCE_OP,
}

impl<'r, REDUCE_OP> Copy for ReduceConsumer<'r, REDUCE_OP> {}

impl<'r, REDUCE_OP> Clone for ReduceConsumer<'r, REDUCE_OP> {
    fn clone(&self) -> Self {
        *self
    }
}

impl<'r, REDUCE_OP, ITEM> Consumer<ITEM> for ReduceConsumer<'r, REDUCE_OP>
    where REDUCE_OP: ReduceOp<ITEM>,
          ITEM: Send
{
    type Folder = ReduceFolder<'r, REDUCE_OP, ITEM>;
    type Reducer = Self;
    type Result = ITEM;

    fn cost(&mut self, cost: f64) -> f64 {
        // This isn't quite right, as we will do more than O(n) reductions, but whatever.
        cost * FUNC_ADJUSTMENT
    }

    fn split_at(self, _index: usize) -> (Self, Self, Self) {
        (self, self, self)
    }

    fn into_folder(self) -> ReduceFolder<'r, REDUCE_OP, ITEM> {
        ReduceFolder {
            reduce_op: self.reduce_op,
            item: self.reduce_op.start_value(),
        }
    }
}

impl<'r, REDUCE_OP, ITEM> UnindexedConsumer<ITEM> for ReduceConsumer<'r, REDUCE_OP>
    where REDUCE_OP: ReduceOp<ITEM>,
          ITEM: Send
{
    fn split_off(&self) -> Self {
        ReduceConsumer { reduce_op: self.reduce_op }
    }

    fn to_reducer(&self) -> Self::Reducer {
        *self
    }
}

impl<'r, REDUCE_OP, ITEM> Reducer<ITEM> for ReduceConsumer<'r, REDUCE_OP>
    where REDUCE_OP: ReduceOp<ITEM>
{
    fn reduce(self, left: ITEM, right: ITEM) -> ITEM {
        self.reduce_op.reduce(left, right)
    }
}

pub struct ReduceFolder<'r, REDUCE_OP: 'r, ITEM> {
    reduce_op: &'r REDUCE_OP,
    item: ITEM,
}

impl<'r, REDUCE_OP, ITEM> Folder<ITEM> for ReduceFolder<'r, REDUCE_OP, ITEM>
    where REDUCE_OP: ReduceOp<ITEM>
{
    type Result = ITEM;

    fn consume(self, item: ITEM) -> Self {
        let item = self.reduce_op.reduce(self.item, item);
        ReduceFolder {
            reduce_op: self.reduce_op,
            item: item,
        }
    }

    fn complete(self) -> ITEM {
        self.item
    }
}

/// ////////////////////////////////////////////////////////////////////////
/// Specific operations

pub struct SumOp;

pub const SUM: &'static SumOp = &SumOp;

macro_rules! sum_rule {
    ($i:ty, $z:expr) => {
        impl ReduceOp<$i> for SumOp {
            #[inline]
            fn start_value(&self) -> $i {
                $z
            }
            #[inline]
            fn reduce(&self, value1: $i, value2: $i) -> $i {
                value1 + value2
            }
        }
    }
}

sum_rule!(i8, 0);
sum_rule!(i16, 0);
sum_rule!(i32, 0);
sum_rule!(i64, 0);
sum_rule!(isize, 0);
sum_rule!(u8, 0);
sum_rule!(u16, 0);
sum_rule!(u32, 0);
sum_rule!(u64, 0);
sum_rule!(usize, 0);
sum_rule!(f32, 0.0);
sum_rule!(f64, 0.0);

pub struct ProductOp;

pub const PRODUCT: &'static ProductOp = &ProductOp;

macro_rules! product_rule {
    ($i:ty, $z:expr) => {
        impl ReduceOp<$i> for ProductOp {
            #[inline]
            fn start_value(&self) -> $i {
                $z
            }
            #[inline]
            fn reduce(&self, value1: $i, value2: $i) -> $i {
                value1 * value2
            }
        }
    }
}

product_rule!(i8, 1);
product_rule!(i16, 1);
product_rule!(i32, 1);
product_rule!(i64, 1);
product_rule!(isize, 1);
product_rule!(u8, 1);
product_rule!(u16, 1);
product_rule!(u32, 1);
product_rule!(u64, 1);
product_rule!(usize, 1);
product_rule!(f32, 1.0);
product_rule!(f64, 1.0);

pub struct ReduceWithIdentityOp<'r, IDENTITY: 'r, OP: 'r> {
    identity: &'r IDENTITY,
    op: &'r OP,
}

impl<'r, IDENTITY, OP> ReduceWithIdentityOp<'r, IDENTITY, OP> {
    pub fn new(identity: &'r IDENTITY, op: &'r OP) -> ReduceWithIdentityOp<'r, IDENTITY, OP> {
        ReduceWithIdentityOp {
            identity: identity,
            op: op,
        }
    }
}

impl<'r, IDENTITY, OP, ITEM> ReduceOp<ITEM> for ReduceWithIdentityOp<'r, IDENTITY, OP>
    where OP: Fn(ITEM, ITEM) -> ITEM + Sync,
          IDENTITY: Fn() -> ITEM + Sync,
          ITEM: 'r
{
    fn start_value(&self) -> ITEM {
        (self.identity)()
    }

    fn reduce(&self, value1: ITEM, value2: ITEM) -> ITEM {
        (self.op)(value1, value2)
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
use std::io::Result as IoResult;
use std::io::Error  as IoError;
use super::imagemagick_commands;
use image_tools::image_ops::{ElementaryPageOperations, Pixels, Direction};
use image_tools::image_ops::ImageResolution;
use image_tools::image_ops::RunOperation;
use image_tools::image_ops::OperationResults;

type ImageMagickArg = String;
type FileName = String;
type FilePath = String;

#[derive(Clone)]
enum ImageMagickOpType {
    Identify,
    IdentifyVerbose,
    Mogrify,
    Convert,
    NoOperation,
}

trait AsShellCommand {
    fn as_shell_command(&self) -> String;
}

impl AsShellCommand for ImageMagickOpType {
    fn as_shell_command(&self) -> String {
        match *self {
            ImageMagickOpType::Identify        => String::from("identify"),
            ImageMagickOpType::IdentifyVerbose => String::from("identify"),
            ImageMagickOpType::Mogrify         => String::from("mogrify"),
            ImageMagickOpType::Convert         => String::from("convert"),
            ImageMagickOpType::NoOperation     => String::from("echo"),
        }
    }
}

#[derive(Clone)]
struct ImageMagickArgs {
    file_path: FilePath,
    file_name: FileName,
    img_args:  Vec<ImageMagickArg>,
}

impl ImageMagickArgs {
    fn new(file_path: FilePath, file_name: FileName, img_args: &Vec<ImageMagickArg>) -> ImageMagickArgs {
        ImageMagickArgs {
            file_path: file_path,
            file_name: file_name,
            img_args:  img_args.clone(),
        }
    }
}

#[derive(Clone)]
struct ElementaryImageMagickOperation {
    op:   ImageMagickOpType,
    args: ImageMagickArgs,
}

impl ElementaryImageMagickOperation {
    fn new(op: ImageMagickOpType, args: ImageMagickArgs) -> ElementaryImageMagickOperation {
        ElementaryImageMagickOperation {
            op:   op,
            args: args,
        }
    }

    fn arg(&mut self, arg: ImageMagickArg) {
        self.args.img_args.push(arg);
    }

    fn args(&mut self, args: &[ImageMagickArg]) {
        for arg in args {
            self.args.img_args.push(arg.clone());
        }
    }

    fn run_operation(&self) -> IoResult<String> {
        match self.op {
            ImageMagickOpType::Identify        => {
                imagemagick_commands::imagemagick_identify_default(&self.args.file_path)
            }
            ImageMagickOpType::IdentifyVerbose => {
                imagemagick_commands::imagemagick_identify_verbose(&self.args.file_path)
            }
            ImageMagickOpType::Convert         => {
                imagemagick_commands::imagemagick_convert(&self.args.file_path, &self.args.img_args)
            }
            ImageMagickOpType::Mogrify         => {
                imagemagick_commands::imagemagick_mogrify(&self.args.file_path, &self.args.img_args)
            }
            ImageMagickOpType::NoOperation     => {
                imagemagick_commands::imagemagick_no_operation()
            }
        }
    }
}

#[derive(Clone)]
pub struct ImageMagickOperation {
    ops: Vec<ElementaryImageMagickOperation>,
}

impl ImageMagickOperation {
    fn new() -> ImageMagickOperation {
        ImageMagickOperation {
            ops: Vec::new(),
        }
    }

    fn add_op(&mut self, op: ElementaryImageMagickOperation)  {
        self.ops.push(op);
    }

    fn add_ops(&mut self, ops: &[ElementaryImageMagickOperation]) {
        for op in ops.iter() {
            self.ops.push(op.clone());
        }
    }
}

// This implementation will be the generator for the sequence of
// ImageMagick commands to implement each operation.
impl ElementaryPageOperations for ImageMagickOperation {

    fn identify(file_name: FileName, file_path: FilePath) -> ImageMagickOperation {
        // Identify presesntly generates an identify command without the -verbose flag.
        // This may change in the future where we use verbose as the default.
        let args = ImageMagickArgs::new(file_name, file_path, &Vec::new());
        let elem_op = ElementaryImageMagickOperation::new(ImageMagickOpType::Identify, args);
        let mut op = ImageMagickOperation::new();
        op.add_op(elem_op);

        op

    }

    fn rescale(amount: Pixels, dir: Direction) -> ImageMagickOperation {
        unimplemented!();
    }

    fn expand_left_edge(amount: Pixels)        -> ImageMagickOperation {
        unimplemented!();
    }

    fn expand_right_edge(amount: Pixels)       -> ImageMagickOperation {
        unimplemented!();
    }

    fn expand_top_edge(amount: Pixels)         -> ImageMagickOperation {
        unimplemented!();
    }

    fn expand_bottom_edge(amount: Pixels)      -> ImageMagickOperation {
        unimplemented!();
    }

    fn trim_left_edge(amount: Pixels)          -> ImageMagickOperation {
        unimplemented!();
    }

    fn trim_right_edge(amount: Pixels)         -> ImageMagickOperation {
        unimplemented!();
    }

    fn trim_top_edge(amount: Pixels)           -> ImageMagickOperation {
        unimplemented!();
    }

    fn trim_bottom_edge(amount: Pixels)        -> ImageMagickOperation {
        unimplemented!();
    }

    fn set_resolution(res: ImageResolution)    -> ImageMagickOperation {
        unimplemented!();
    }
    fn no_operation()                          -> ImageMagickOperation {
        unimplemented!();
    }
}

impl RunOperation for ImageMagickOperation {
    fn run_operation(op: ImageMagickOperation) -> OperationResults {
        let mut results = OperationResults::new();

        for action in op.ops {
            let mut result = Vec::new();
            result.push(action.run_operation());
            results.append(&mut OperationResults::from(&mut result));
        }

        results
    }
}
<commit_msg>AsRef implementation for ImageMagickOperation.<commit_after>#![allow(dead_code)]
use std::io::Result as IoResult;
use std::io::Error  as IoError;
use std::convert::AsRef;
use super::imagemagick_commands;
use image_tools::image_ops::{ElementaryPageOperations, Pixels, Direction};
use image_tools::image_ops::ImageResolution;
use image_tools::image_ops::RunOperation;
use image_tools::image_ops::OperationResults;

type ImageMagickArg = String;
type FileName = String;
type FilePath = String;

#[derive(Clone)]
enum ImageMagickOpType {
    Identify,
    IdentifyVerbose,
    Mogrify,
    Convert,
    NoOperation,
}

trait AsShellCommand {
    fn as_shell_command(&self) -> String;
}

impl AsShellCommand for ImageMagickOpType {
    fn as_shell_command(&self) -> String {
        match *self {
            ImageMagickOpType::Identify        => String::from("identify"),
            ImageMagickOpType::IdentifyVerbose => String::from("identify"),
            ImageMagickOpType::Mogrify         => String::from("mogrify"),
            ImageMagickOpType::Convert         => String::from("convert"),
            ImageMagickOpType::NoOperation     => String::from("echo"),
        }
    }
}

#[derive(Clone)]
struct ImageMagickArgs {
    file_path: FilePath,
    file_name: FileName,
    img_args:  Vec<ImageMagickArg>,
}

impl ImageMagickArgs {
    fn new(file_path: FilePath, file_name: FileName, img_args: &Vec<ImageMagickArg>) -> ImageMagickArgs {
        ImageMagickArgs {
            file_path: file_path,
            file_name: file_name,
            img_args:  img_args.clone(),
        }
    }
}

#[derive(Clone)]
pub struct ElementaryImageMagickOperation {
    op:   ImageMagickOpType,
    args: ImageMagickArgs,
}

impl ElementaryImageMagickOperation {
    fn new(op: ImageMagickOpType, args: ImageMagickArgs) -> ElementaryImageMagickOperation {
        ElementaryImageMagickOperation {
            op:   op,
            args: args,
        }
    }

    fn arg(&mut self, arg: ImageMagickArg) {
        self.args.img_args.push(arg);
    }

    fn args(&mut self, args: &[ImageMagickArg]) {
        for arg in args {
            self.args.img_args.push(arg.clone());
        }
    }

    fn run_operation(&self) -> IoResult<String> {
        match self.op {
            ImageMagickOpType::Identify        => {
                imagemagick_commands::imagemagick_identify_default(&self.args.file_path)
            }
            ImageMagickOpType::IdentifyVerbose => {
                imagemagick_commands::imagemagick_identify_verbose(&self.args.file_path)
            }
            ImageMagickOpType::Convert         => {
                imagemagick_commands::imagemagick_convert(&self.args.file_path, &self.args.img_args)
            }
            ImageMagickOpType::Mogrify         => {
                imagemagick_commands::imagemagick_mogrify(&self.args.file_path, &self.args.img_args)
            }
            ImageMagickOpType::NoOperation     => {
                imagemagick_commands::imagemagick_no_operation()
            }
        }
    }
}

#[derive(Clone)]
pub struct ImageMagickOperation {
    ops: Vec<ElementaryImageMagickOperation>,
}

impl ImageMagickOperation {
    fn new() -> ImageMagickOperation {
        ImageMagickOperation {
            ops: Vec::new(),
        }
    }

    fn add_op(&mut self, op: ElementaryImageMagickOperation)  {
        self.ops.push(op);
    }

    fn add_ops(&mut self, ops: &[ElementaryImageMagickOperation]) {
        for op in ops.iter() {
            self.ops.push(op.clone());
        }
    }
}

// This implementation will be the generator for the sequence of
// ImageMagick commands to implement each operation.
impl ElementaryPageOperations for ImageMagickOperation {

    fn identify(file_name: FileName, file_path: FilePath) -> ImageMagickOperation {
        // Identify presesntly generates an identify command without the -verbose flag.
        // This may change in the future where we use verbose as the default.
        let args = ImageMagickArgs::new(file_name, file_path, &Vec::new());
        let elem_op = ElementaryImageMagickOperation::new(ImageMagickOpType::Identify, args);
        let mut op = ImageMagickOperation::new();
        op.add_op(elem_op);

        op

    }

    fn rescale(amount: Pixels, dir: Direction) -> ImageMagickOperation {
        unimplemented!();
    }

    fn expand_left_edge(amount: Pixels)        -> ImageMagickOperation {
        unimplemented!();
    }

    fn expand_right_edge(amount: Pixels)       -> ImageMagickOperation {
        unimplemented!();
    }

    fn expand_top_edge(amount: Pixels)         -> ImageMagickOperation {
        unimplemented!();
    }

    fn expand_bottom_edge(amount: Pixels)      -> ImageMagickOperation {
        unimplemented!();
    }

    fn trim_left_edge(amount: Pixels)          -> ImageMagickOperation {
        unimplemented!();
    }

    fn trim_right_edge(amount: Pixels)         -> ImageMagickOperation {
        unimplemented!();
    }

    fn trim_top_edge(amount: Pixels)           -> ImageMagickOperation {
        unimplemented!();
    }

    fn trim_bottom_edge(amount: Pixels)        -> ImageMagickOperation {
        unimplemented!();
    }

    fn set_resolution(res: ImageResolution)    -> ImageMagickOperation {
        unimplemented!();
    }
    fn no_operation()                          -> ImageMagickOperation {
        unimplemented!();
    }
}

impl AsRef<[ElementaryImageMagickOperation]> for ImageMagickOperation {
    fn as_ref(&self) -> &[ElementaryImageMagickOperation] {
        self.ops.as_ref()
    }
}

impl RunOperation for ImageMagickOperation {
    fn run_operation(op: ImageMagickOperation) -> OperationResults {
        let mut results = OperationResults::new();

        for action in op.ops {
            let mut result = Vec::new();
            result.push(action.run_operation());
            results.append(&mut OperationResults::from(&mut result));
        }

        results
    }
}
<|endoftext|>