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

#![allow(clippy::integer_arithmetic)]

use crate::{utils, Result};
use std::{
    io::{self, Write},
    num::NonZeroUsize,
    panic::{catch_unwind, AssertUnwindSafe},
    path::Path,
    process,
    sync::mpsc::{channel, Sender},
    thread,
};
use structopt::StructOpt;
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};

#[derive(Debug, StructOpt)]
#[structopt(about = "Datatest-harness for running data-driven tests")]
struct TestOpts {
    /// 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(long, default_value = "32", env = "RUST_TEST_THREADS")]
    /// Number of threads used for running tests in parallel
    test_threads: NonZeroUsize,
    #[structopt(short = "q", long)]
    /// Output minimal information
    quiet: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    nocapture: bool,
    #[structopt(long)]
    /// List all tests
    list: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    ignored: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    include_ignored: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    force_run_in_process: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    exclude_should_panic: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    test: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    bench: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    logfile: Option<String>,
    #[structopt(long, number_of_values = 1)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    skip: Vec<String>,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    show_output: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    color: Option<String>,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    format: Option<String>,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    report_time: Option<String>,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    ensure_time: bool,
}

pub fn runner(reqs: &[Requirements]) {
    let options = TestOpts::from_args();

    let tests: Vec<Test> = reqs.iter().flat_map(|req| req.expand()).collect();

    if options.list {
        for test in &tests {
            println!("{}: test", test.name);
        }

        println!();
        println!("{} tests, 0 benchmarks", tests.len());
        return;
    }

    match run_tests(options, tests) {
        Ok(true) => {}
        Ok(false) => process::exit(101),
        Err(e) => {
            eprintln!("error: io error when running tests: {:?}", e);
            process::exit(101);
        }
    }
}

struct Test {
    testfn: Box<dyn Fn() -> Result<()> + Send>,
    name: String,
}

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

fn run_tests(options: TestOpts, tests: Vec<Test>) -> io::Result<bool> {
    let total = tests.len();

    // Filter out tests
    let mut remaining = match &options.filter {
        None => tests,
        Some(filter) => tests
            .into_iter()
            .filter(|test| {
                if options.filter_exact {
                    test.name == filter[..]
                } else {
                    test.name.contains(&filter[..])
                }
            })
            .rev()
            .collect(),
    };

    let filtered_out = total - remaining.len();
    let mut summary = TestSummary::new(total, filtered_out);

    if !options.quiet {
        summary.write_starting_msg()?;
    }

    let (tx, rx) = channel();

    let mut pending = 0;
    while pending > 0 || !remaining.is_empty() {
        while pending < options.test_threads.get() && !remaining.is_empty() {
            let test = remaining.pop().unwrap();
            run_test(test, tx.clone());
            pending += 1;
        }

        let (name, result) = rx.recv().unwrap();
        summary.handle_result(name, result)?;

        pending -= 1;
    }

    // Write Test Summary
    if !options.quiet {
        summary.write_summary()?;
    }

    Ok(summary.success())
}

fn run_test(test: Test, channel: Sender<(String, TestResult)>) {
    let Test { name, testfn } = test;

    let cfg = thread::Builder::new().name(name.clone());
    cfg.spawn(move || {
        let result = match catch_unwind(AssertUnwindSafe(|| testfn())) {
            Ok(Ok(())) => TestResult::Ok,
            Ok(Err(e)) => TestResult::FailedWithMsg(format!("{:?}", e)),
            Err(_) => TestResult::Failed,
        };

        channel.send((name, result)).unwrap();
    })
    .unwrap();
}

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()
    }
}

pub struct Requirements {
    test: fn(&Path) -> Result<()>,
    test_name: String,
    root: String,
    pattern: String,
}

impl Requirements {
    pub fn new(
        test: fn(&Path) -> Result<()>,
        test_name: String,
        root: String,
        pattern: String,
    ) -> Self {
        Self {
            test,
            test_name,
            root,
            pattern,
        }
    }

    /// Generate standard test descriptors ([`test::TestDescAndFn`]) from the descriptor of
    /// `#[datatest::files(..)]`.
    ///
    /// Scans all files in a given directory, finds matching ones and generates a test descriptor
    /// for each of them.
    fn expand(&self) -> Vec<Test> {
        let root = Path::new(&self.root).to_path_buf();

        let re = regex::Regex::new(&self.pattern)
            .unwrap_or_else(|_| panic!("invalid regular expression: '{}'", self.pattern));

        let tests: Vec<_> = utils::iterate_directory(&root)
            .filter_map(|path| {
                let input_path = path.to_string_lossy();
                if re.is_match(&input_path) {
                    let testfn = self.test;
                    let name = utils::derive_test_name(&root, &path, &self.test_name);
                    let testfn = Box::new(move || (testfn)(&path));

                    Some(Test { testfn, name })
                } else {
                    None
                }
            })
            .collect();

        // We want to avoid silent fails due to typos in regexp!
        if tests.is_empty() {
            panic!(
                "no test cases found for test '{}'. Scanned directory: '{}' with pattern '{}'",
                self.test_name, self.root, self.pattern,
            );
        }

        tests
    }
}
<commit_msg>[datatest-stable] support --format terse<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![allow(clippy::integer_arithmetic)]

use crate::{utils, Result};
use std::{
    io::{self, Write},
    num::NonZeroUsize,
    panic::{catch_unwind, AssertUnwindSafe},
    path::Path,
    process,
    sync::mpsc::{channel, Sender},
    thread,
};
use structopt::{clap::arg_enum, StructOpt};
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};

#[derive(Debug, StructOpt)]
#[structopt(about = "Datatest-harness for running data-driven tests")]
struct TestOpts {
    /// 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(long, default_value = "32", env = "RUST_TEST_THREADS")]
    /// Number of threads used for running tests in parallel
    test_threads: NonZeroUsize,
    #[structopt(short = "q", long)]
    /// Output minimal information
    quiet: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    nocapture: bool,
    #[structopt(long)]
    /// List all tests
    list: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    ignored: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    include_ignored: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    force_run_in_process: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    exclude_should_panic: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    test: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    bench: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    logfile: Option<String>,
    #[structopt(long, number_of_values = 1)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    skip: Vec<String>,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    show_output: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    color: Option<String>,
    #[structopt(long)]
    /// 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(possible_values = &Format::variants(), default_value, case_insensitive = true)]
    format: Format,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    report_time: Option<String>,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    ensure_time: bool,
}

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

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

pub fn runner(reqs: &[Requirements]) {
    let options = TestOpts::from_args();

    let tests: Vec<Test> = reqs.iter().flat_map(|req| req.expand()).collect();

    if options.list {
        for test in &tests {
            println!("{}: test", test.name);
        }

        if options.format == Format::Pretty {
            println!();
            println!("{} tests, 0 benchmarks", tests.len());
        }
        return;
    }

    match run_tests(options, tests) {
        Ok(true) => {}
        Ok(false) => process::exit(101),
        Err(e) => {
            eprintln!("error: io error when running tests: {:?}", e);
            process::exit(101);
        }
    }
}

struct Test {
    testfn: Box<dyn Fn() -> Result<()> + Send>,
    name: String,
}

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

fn run_tests(options: TestOpts, tests: Vec<Test>) -> io::Result<bool> {
    let total = tests.len();

    // Filter out tests
    let mut remaining = match &options.filter {
        None => tests,
        Some(filter) => tests
            .into_iter()
            .filter(|test| {
                if options.filter_exact {
                    test.name == filter[..]
                } else {
                    test.name.contains(&filter[..])
                }
            })
            .rev()
            .collect(),
    };

    let filtered_out = total - remaining.len();
    let mut summary = TestSummary::new(total, filtered_out);

    if !options.quiet {
        summary.write_starting_msg()?;
    }

    let (tx, rx) = channel();

    let mut pending = 0;
    while pending > 0 || !remaining.is_empty() {
        while pending < options.test_threads.get() && !remaining.is_empty() {
            let test = remaining.pop().unwrap();
            run_test(test, tx.clone());
            pending += 1;
        }

        let (name, result) = rx.recv().unwrap();
        summary.handle_result(name, result)?;

        pending -= 1;
    }

    // Write Test Summary
    if !options.quiet {
        summary.write_summary()?;
    }

    Ok(summary.success())
}

fn run_test(test: Test, channel: Sender<(String, TestResult)>) {
    let Test { name, testfn } = test;

    let cfg = thread::Builder::new().name(name.clone());
    cfg.spawn(move || {
        let result = match catch_unwind(AssertUnwindSafe(|| testfn())) {
            Ok(Ok(())) => TestResult::Ok,
            Ok(Err(e)) => TestResult::FailedWithMsg(format!("{:?}", e)),
            Err(_) => TestResult::Failed,
        };

        channel.send((name, result)).unwrap();
    })
    .unwrap();
}

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()
    }
}

pub struct Requirements {
    test: fn(&Path) -> Result<()>,
    test_name: String,
    root: String,
    pattern: String,
}

impl Requirements {
    pub fn new(
        test: fn(&Path) -> Result<()>,
        test_name: String,
        root: String,
        pattern: String,
    ) -> Self {
        Self {
            test,
            test_name,
            root,
            pattern,
        }
    }

    /// Generate standard test descriptors ([`test::TestDescAndFn`]) from the descriptor of
    /// `#[datatest::files(..)]`.
    ///
    /// Scans all files in a given directory, finds matching ones and generates a test descriptor
    /// for each of them.
    fn expand(&self) -> Vec<Test> {
        let root = Path::new(&self.root).to_path_buf();

        let re = regex::Regex::new(&self.pattern)
            .unwrap_or_else(|_| panic!("invalid regular expression: '{}'", self.pattern));

        let tests: Vec<_> = utils::iterate_directory(&root)
            .filter_map(|path| {
                let input_path = path.to_string_lossy();
                if re.is_match(&input_path) {
                    let testfn = self.test;
                    let name = utils::derive_test_name(&root, &path, &self.test_name);
                    let testfn = Box::new(move || (testfn)(&path));

                    Some(Test { testfn, name })
                } else {
                    None
                }
            })
            .collect();

        // We want to avoid silent fails due to typos in regexp!
        if tests.is_empty() {
            panic!(
                "no test cases found for test '{}'. Scanned directory: '{}' with pattern '{}'",
                self.test_name, self.root, self.pattern,
            );
        }

        tests
    }
}
<|endoftext|>


<commit_before>#[feature(macro_rules)];
#[crate_id = "codegen#0.1"];

use std::os;
use std::io::BufferedWriter;
use std::io::File;
use std::io;
use std::io::stdio::println;
use std::io::fs::mkdir_recursive;
use std::path::GenericPath;
use std::vec_ng::Vec;
pub mod branchify;
pub mod keycode;
pub mod scancode;

fn main() {
    let args = Vec::from_slice(os::args());
    match args.len() {
        0 => {
            println("usage: codegen [keycode|scancode].rs destdir");
            os::set_exit_status(1);
        },
        3 => {
            let output_dir = GenericPath::new(args.get(2).clone());
            // TODO: maybe not 0777?
            match mkdir_recursive(&output_dir, 0b111_111_111) {
                Err(msg) => fail!("Could not create directory for generated sources: {}", msg),
                Ok(_) => {},
            };

            if *args.get(1) == ~"keycode.rs" {
                keycode::generate(&output_dir);
            } else if *args.get(1) == ~"scancode.rs" {
                match scancode::generate(&output_dir) {
                    Ok(_)    => {},
                    Err(msg) => fail!("Could not automatically generate sources for scancodes: {}", msg.desc),
                };
            } else {
                println!("unknown thing-to-generate '{}'", args.get(1));
                os::set_exit_status(1);
            }
        },
        _ => {
            println!("usage: {} [keycode|scancode].rs destdir", args.get(0));
            os::set_exit_status(1);
        }
    }
}

pub fn get_writer(output_dir: &Path, filename: &str) -> ~BufferedWriter<File> {
    match File::open_mode(&output_dir.join(filename), io::Truncate, io::Write) {
        Ok(writer) => ~BufferedWriter::new(writer),
        Err(e) => fail!("Unable to write file: {:s}", e.desc),
    }
}
<commit_msg>(Use consistent variable names when matching IoResults)<commit_after>#[feature(macro_rules)];
#[crate_id = "codegen#0.1"];

use std::os;
use std::io::BufferedWriter;
use std::io::File;
use std::io;
use std::io::stdio::println;
use std::io::fs::mkdir_recursive;
use std::path::GenericPath;
use std::vec_ng::Vec;
pub mod branchify;
pub mod keycode;
pub mod scancode;

fn main() {
    let args = Vec::from_slice(os::args());
    match args.len() {
        0 => {
            println("usage: codegen [keycode|scancode].rs destdir");
            os::set_exit_status(1);
        },
        3 => {
            let output_dir = GenericPath::new(args.get(2).clone());
            // TODO: maybe not 0777?
            match mkdir_recursive(&output_dir, 0b111_111_111) {
                Err(e) => fail!("Could not create directory for generated sources: {:s}", e.desc),
                Ok(_) => {},
            };

            if *args.get(1) == ~"keycode.rs" {
                match keycode::generate(&output_dir) {
                    Ok(_) => {},
                    Err(e) => fail!("Could not automatically generate sources for keycodes: {:s}", e.desc),
                };
            } else if *args.get(1) == ~"scancode.rs" {
                match scancode::generate(&output_dir) {
                    Ok(_)    => {},
                    Err(e) => fail!("Could not automatically generate sources for scancodes: {:s}", e.desc),
                };
            } else {
                println!("unknown thing-to-generate '{}'", args.get(1));
                os::set_exit_status(1);
            }
        },
        _ => {
            println!("usage: {} [keycode|scancode].rs destdir", args.get(0));
            os::set_exit_status(1);
        }
    }
}

pub fn get_writer(output_dir: &Path, filename: &str) -> ~BufferedWriter<File> {
    match File::open_mode(&output_dir.join(filename), io::Truncate, io::Write) {
        Ok(writer) => ~BufferedWriter::new(writer),
        Err(e) => fail!("Unable to write file: {:s}", e.desc),
    }
}
<|endoftext|>


<commit_before>extern crate calx;
use calx::text;
use std::num::log10;
use std::rand::Rng;
use std::rand;

pub fn probToDb(prob: f64) -> f64 {
    assert!(prob > 0.0);
    assert!(prob < 1.0);
    -10.0 * log10(1.0 / prob - 1.0)
}

pub fn randomDb<R: Rng>(rng: &mut R) -> f64 {
    probToDb(rng.gen_range(1.0, 99.0) / 100.0)
}

pub fn main() {
    println!("{}\n",
        text::wrap_lines(20, "Crunchy: A program for testing rules and object interactions."));
    println!("{}\n", randomDb(&mut rand::task_rng()));
}
<commit_msg>Remove the crunchy module for now, never got around to working on it<commit_after><|endoftext|>


<commit_before>use crate::RegistryType;
use clap::{App,
           Arg};
use habitat_core::package::PackageIdent;
use std::{path::Path,
          result,
          str::FromStr};
use url::Url;

/// The version of this library and program when built.
pub const VERSION: &str = include_str!(concat!(env!("OUT_DIR"), "/VERSION"));

/// A Docker-specific clap:App wrapper
#[derive(Clone)]
pub struct Cli<'a, 'b>
    where 'a: 'b
{
    pub app: App<'a, 'b>,
}

#[derive(Clone, Copy)]
pub struct PkgIdentArgOptions {
    pub multiple: bool,
}

impl<'a, 'b> Cli<'a, 'b> {
    pub fn new(name: &str, about: &'a str) -> Self {
        Cli { app: clap_app!(
              (name) =>
              (about: about)
              (version: VERSION)
              (author: "\nAuthors: The Habitat Maintainers <humans@habitat.sh>\n\n")
              (@arg IMAGE_NAME: --("image-name") -i +takes_value
                  "Image name (default: \"{{pkg_origin}}/{{pkg_name}}\" supports: \
                   {{pkg_origin}}, {{pkg_name}}, {{pkg_version}}, {{pkg_release}}, {{channel}})")
              ), }
    }

    pub fn add_base_packages_args(self) -> Self {
        let app = self
            .app
            .arg(
                Arg::with_name("HAB_PKG")
                    .long("hab-pkg")
                    .value_name("HAB_PKG")
                    .validator(valid_ident_or_hart)
                    .help(
                        "Habitat CLI package identifier (ex: acme/redis) or filepath to a Habitat \
                         artifact (ex: /home/acme-redis-3.0.7-21120102031201-x86_64-linux.hart) \
                         to install (default: core/hab)",
                    ),
            )
            .arg(
                Arg::with_name("HAB_LAUNCHER_PKG")
                    .long("launcher-pkg")
                    .value_name("HAB_LAUNCHER_PKG")
                    .validator(valid_ident_or_hart)
                    .help(
                        "Launcher package identifier (ex: core/hab-launcher) or filepath to a \
                         Habitat artifact (ex: \
                         /home/core-hab-launcher-6083-20171101045646-x86_64-linux.hart) to \
                         install (default: core/hab-launcher)",
                    ),
            )
            .arg(
                Arg::with_name("HAB_SUP_PKG")
                    .long("sup-pkg")
                    .value_name("HAB_SUP_PKG")
                    .validator(valid_ident_or_hart)
                    .help(
                        "Supervisor package identifier (ex: core/hab-sup) or filepath to a \
                         Habitat artifact (ex: \
                         /home/ore-hab-sup-0.39.1-20171118011657-x86_64-linux.hart) to install \
                         (default: core/hab-sup)",
                    ),
            );

        Cli { app }
    }

    pub fn add_builder_args(self) -> Self {
        let app = self
            .app
            .arg(
                Arg::with_name("BLDR_URL")
                    .long("url")
                    .short("u")
                    .value_name("BLDR_URL")
                    .validator(valid_url)
                    .help(
                        "Install packages from Builder at the specified URL \
                         (default: https://bldr.habitat.sh)",
                    ),
            )
            .arg(
                Arg::with_name("CHANNEL")
                    .long("channel")
                    .short("c")
                    .value_name("CHANNEL")
                    .help("Install packages from the specified release channel (default: stable)"),
            )
            .arg(
                Arg::with_name("BASE_PKGS_BLDR_URL")
                    .long("base-pkgs-url")
                    .value_name("BASE_PKGS_BLDR_URL")
                    .validator(valid_url)
                    .help(
                        "Install base packages from Builder at the specified URL \
                         (default: https://bldr.habitat.sh)",
                    ),
            )
            .arg(
                Arg::with_name("BASE_PKGS_CHANNEL")
                    .long("base-pkgs-channel")
                    .value_name("BASE_PKGS_CHANNEL")
                    .help(
                        "Install base packages from the specified release channel \
                         (default: stable)",
                    ),
            )
            .arg(
                Arg::with_name("BLDR_AUTH_TOKEN")
                    .long("auth")
                    .short("z")
                    .value_name("BLDR_AUTH_TOKEN")
                    .help("Provide a Builder auth token for private pkg export"),
            );

        Cli { app }
    }

    pub fn add_tagging_args(self) -> Self {
        let app = self
            .app
            .arg(
                Arg::with_name("TAG_VERSION_RELEASE")
                    .long("tag-version-release")
                    .conflicts_with("NO_TAG_VERSION_RELEASE")
                    .help("Tag image with :\"{{pkg_version}}-{{pkg_release}}\" (default: yes)"),
            )
            .arg(
                Arg::with_name("NO_TAG_VERSION_RELEASE")
                    .long("no-tag-version-release")
                    .conflicts_with("TAG_VERSION_RELEASE")
                    .help(
                        "Do not tag image with :\"{{pkg_version}}-{{pkg_release}}\" (default: no)",
                    ),
            )
            .arg(
                Arg::with_name("TAG_VERSION")
                    .long("tag-version")
                    .conflicts_with("NO_TAG_VERSION")
                    .help("Tag image with :\"{{pkg_version}}\" (default: yes)"),
            )
            .arg(
                Arg::with_name("NO_TAG_VERSION")
                    .long("no-tag-version")
                    .conflicts_with("TAG_VERSION")
                    .help("Do not tag image with :\"{{pkg_version}}\" (default: no)"),
            )
            .arg(
                Arg::with_name("TAG_LATEST")
                    .long("tag-latest")
                    .conflicts_with("NO_TAG_LATEST")
                    .help("Tag image with :\"latest\" (default: yes)"),
            )
            .arg(
                Arg::with_name("NO_TAG_LATEST")
                    .long("no-tag-latest")
                    .conflicts_with("TAG_LATEST")
                    .help("Do not tag image with :\"latest\" (default: no)"),
            )
            .arg(
                Arg::with_name("TAG_CUSTOM")
                    .long("tag-custom")
                    .value_name("TAG_CUSTOM")
                    .help(
                        "Tag image with additional custom tag (supports: {{pkg_origin}}, \
                         {{pkg_name}}, {{pkg_version}}, {{pkg_release}}, {{channel}})",
                    ),
            );

        Cli { app }
    }

    pub fn add_publishing_args(self) -> Self {
        let app = self
            .app
            .arg(
                Arg::with_name("PUSH_IMAGE")
                    .long("push-image")
                    .conflicts_with("NO_PUSH_IMAGE")
                    .requires_all(&["REGISTRY_USERNAME", "REGISTRY_PASSWORD"])
                    .help("Push image to remote registry (default: no)"),
            )
            .arg(
                Arg::with_name("NO_PUSH_IMAGE")
                    .long("no-push-image")
                    .conflicts_with("PUSH_IMAGE")
                    .help("Do not push image to remote registry (default: yes)"),
            )
            .arg(
                Arg::with_name("REGISTRY_USERNAME")
                    .long("username")
                    .short("U")
                    .value_name("REGISTRY_USERNAME")
                    .requires("REGISTRY_PASSWORD")
                    .help(
                        "Remote registry username, required for pushing image to remote registry",
                    ),
            )
            .arg(
                Arg::with_name("REGISTRY_PASSWORD")
                    .long("password")
                    .short("P")
                    .value_name("REGISTRY_PASSWORD")
                    .requires("REGISTRY_USERNAME")
                    .help(
                        "Remote registry password, required for pushing image to remote registry",
                    ),
            )
            .arg(
                Arg::with_name("REGISTRY_TYPE")
                    .possible_values(RegistryType::variants())
                    .long("registry-type")
                    .short("R")
                    .value_name("REGISTRY_TYPE")
                    .help("Remote registry type (default: docker)"),
            )
            .arg(
                Arg::with_name("REGISTRY_URL")
                    // This is not strictly a requirement but will keep someone from
                    // making a mistake when inputing an ECR URL
                    .required_if("REGISTRY_TYPE", "amazon")
                    .required_if("REGISTRY_TYPE", "azure")
                    .long("registry-url")
                    .short("G")
                    .value_name("REGISTRY_URL")
                    .help("Remote registry url"),
            )
            // Cleanup
            .arg(
                Arg::with_name("RM_IMAGE")
                    .long("rm-image")
                    .help("Remove local image from engine after build and/or push (default: no)"),
            );

        Cli { app }
    }

    pub fn add_pkg_ident_arg(self, options: PkgIdentArgOptions) -> Self {
        let help = if options.multiple {
            "One or more Habitat package identifiers (ex: acme/redis) and/or filepaths to a \
             Habitat Artifact (ex: /home/acme-redis-3.0.7-21120102031201-x86_64-linux.hart)"
        } else {
            "A Habitat package identifier (ex: acme/redis) and/or filepath to a Habitat Artifact \
             (ex: /home/acme-redis-3.0.7-21120102031201-x86_64-linux.hart)"
        };

        let app =
            self.app
                .arg(Arg::with_name("PKG_IDENT_OR_ARTIFACT").value_name("PKG_IDENT_OR_ARTIFACT")
                                                            .required(true)
                                                            .multiple(options.multiple)
                                                            .help(help));

        Cli { app }
    }

    pub fn add_memory_arg(self) -> Self {
        let app = self.app
                      .arg(Arg::with_name("MEMORY_LIMIT").value_name("MEMORY_LIMIT")
                                                         .long("memory")
                                                         .short("m")
                                                         .help("Memory limit passed to docker \
                                                                build's --memory arg (ex: 2bg)"));

        Cli { app }
    }

    pub fn add_base_image_arg(self) -> Self {
        let app = self.app
                      .arg(Arg::with_name("BASE_IMAGE").value_name("BASE_IMAGE")
                                                       .long("base-image")
                                                       .help("Base image of the final exported \
                                                              image --base-image \
                                                              mcr.microsoft.com/windows/\
                                                              servercore:ltsc2019"));

        Cli { app }
    }

    pub fn add_layer_arg(self) -> Self {
        let app =
            self.app
                .arg(Arg::with_name("MULTI_LAYER").value_name("MULTI_LAYER")
                                                  .long("multi-layer")
                                                  .required(false)
                                                  .takes_value(false)
                                                  .multiple(false)
                                                  .help("If specified, creates an image where \
                                                         each Habitat package is added in its \
                                                         own layer, in dependency order (that \
                                                         is, low-level dependencies are added \
                                                         first, with user packages added last). \
                                                         This will allow for reusable layers, \
                                                         reducing storage and network \
                                                         transmission costs. If the resulting \
                                                         image cannot be built because there \
                                                         are too many layers, re-build without \
                                                         specifying this option to add all \
                                                         Habitat packages in a single layer \
                                                         (which is the default behavior)."));
        Cli { app }
    }
}

#[allow(clippy::needless_pass_by_value)] // Signature required by CLAP
fn valid_ident_or_hart(val: String) -> result::Result<(), String> {
    if Path::new(&val).is_file() {
        Ok(())
    } else if val.ends_with(".hart") {
        Err(format!("Habitat artifact file: '{}' not found", &val))
    } else {
        match PackageIdent::from_str(&val) {
            Ok(_) => Ok(()),
            Err(e) => Err(format!("{}", e)),
        }
    }
}

#[allow(clippy::needless_pass_by_value)] // Signature required by CLAP
fn valid_url(val: String) -> result::Result<(), String> {
    match Url::parse(&val) {
        Ok(_) => Ok(()),
        Err(_) => Err(format!("URL: '{}' is not valid", &val)),
    }
}
<commit_msg>[TYPO] Gigabytes are "gb", not "bg"<commit_after>use crate::RegistryType;
use clap::{App,
           Arg};
use habitat_core::package::PackageIdent;
use std::{path::Path,
          result,
          str::FromStr};
use url::Url;

/// The version of this library and program when built.
pub const VERSION: &str = include_str!(concat!(env!("OUT_DIR"), "/VERSION"));

/// A Docker-specific clap:App wrapper
#[derive(Clone)]
pub struct Cli<'a, 'b>
    where 'a: 'b
{
    pub app: App<'a, 'b>,
}

#[derive(Clone, Copy)]
pub struct PkgIdentArgOptions {
    pub multiple: bool,
}

impl<'a, 'b> Cli<'a, 'b> {
    pub fn new(name: &str, about: &'a str) -> Self {
        Cli { app: clap_app!(
              (name) =>
              (about: about)
              (version: VERSION)
              (author: "\nAuthors: The Habitat Maintainers <humans@habitat.sh>\n\n")
              (@arg IMAGE_NAME: --("image-name") -i +takes_value
                  "Image name (default: \"{{pkg_origin}}/{{pkg_name}}\" supports: \
                   {{pkg_origin}}, {{pkg_name}}, {{pkg_version}}, {{pkg_release}}, {{channel}})")
              ), }
    }

    pub fn add_base_packages_args(self) -> Self {
        let app = self
            .app
            .arg(
                Arg::with_name("HAB_PKG")
                    .long("hab-pkg")
                    .value_name("HAB_PKG")
                    .validator(valid_ident_or_hart)
                    .help(
                        "Habitat CLI package identifier (ex: acme/redis) or filepath to a Habitat \
                         artifact (ex: /home/acme-redis-3.0.7-21120102031201-x86_64-linux.hart) \
                         to install (default: core/hab)",
                    ),
            )
            .arg(
                Arg::with_name("HAB_LAUNCHER_PKG")
                    .long("launcher-pkg")
                    .value_name("HAB_LAUNCHER_PKG")
                    .validator(valid_ident_or_hart)
                    .help(
                        "Launcher package identifier (ex: core/hab-launcher) or filepath to a \
                         Habitat artifact (ex: \
                         /home/core-hab-launcher-6083-20171101045646-x86_64-linux.hart) to \
                         install (default: core/hab-launcher)",
                    ),
            )
            .arg(
                Arg::with_name("HAB_SUP_PKG")
                    .long("sup-pkg")
                    .value_name("HAB_SUP_PKG")
                    .validator(valid_ident_or_hart)
                    .help(
                        "Supervisor package identifier (ex: core/hab-sup) or filepath to a \
                         Habitat artifact (ex: \
                         /home/ore-hab-sup-0.39.1-20171118011657-x86_64-linux.hart) to install \
                         (default: core/hab-sup)",
                    ),
            );

        Cli { app }
    }

    pub fn add_builder_args(self) -> Self {
        let app = self
            .app
            .arg(
                Arg::with_name("BLDR_URL")
                    .long("url")
                    .short("u")
                    .value_name("BLDR_URL")
                    .validator(valid_url)
                    .help(
                        "Install packages from Builder at the specified URL \
                         (default: https://bldr.habitat.sh)",
                    ),
            )
            .arg(
                Arg::with_name("CHANNEL")
                    .long("channel")
                    .short("c")
                    .value_name("CHANNEL")
                    .help("Install packages from the specified release channel (default: stable)"),
            )
            .arg(
                Arg::with_name("BASE_PKGS_BLDR_URL")
                    .long("base-pkgs-url")
                    .value_name("BASE_PKGS_BLDR_URL")
                    .validator(valid_url)
                    .help(
                        "Install base packages from Builder at the specified URL \
                         (default: https://bldr.habitat.sh)",
                    ),
            )
            .arg(
                Arg::with_name("BASE_PKGS_CHANNEL")
                    .long("base-pkgs-channel")
                    .value_name("BASE_PKGS_CHANNEL")
                    .help(
                        "Install base packages from the specified release channel \
                         (default: stable)",
                    ),
            )
            .arg(
                Arg::with_name("BLDR_AUTH_TOKEN")
                    .long("auth")
                    .short("z")
                    .value_name("BLDR_AUTH_TOKEN")
                    .help("Provide a Builder auth token for private pkg export"),
            );

        Cli { app }
    }

    pub fn add_tagging_args(self) -> Self {
        let app = self
            .app
            .arg(
                Arg::with_name("TAG_VERSION_RELEASE")
                    .long("tag-version-release")
                    .conflicts_with("NO_TAG_VERSION_RELEASE")
                    .help("Tag image with :\"{{pkg_version}}-{{pkg_release}}\" (default: yes)"),
            )
            .arg(
                Arg::with_name("NO_TAG_VERSION_RELEASE")
                    .long("no-tag-version-release")
                    .conflicts_with("TAG_VERSION_RELEASE")
                    .help(
                        "Do not tag image with :\"{{pkg_version}}-{{pkg_release}}\" (default: no)",
                    ),
            )
            .arg(
                Arg::with_name("TAG_VERSION")
                    .long("tag-version")
                    .conflicts_with("NO_TAG_VERSION")
                    .help("Tag image with :\"{{pkg_version}}\" (default: yes)"),
            )
            .arg(
                Arg::with_name("NO_TAG_VERSION")
                    .long("no-tag-version")
                    .conflicts_with("TAG_VERSION")
                    .help("Do not tag image with :\"{{pkg_version}}\" (default: no)"),
            )
            .arg(
                Arg::with_name("TAG_LATEST")
                    .long("tag-latest")
                    .conflicts_with("NO_TAG_LATEST")
                    .help("Tag image with :\"latest\" (default: yes)"),
            )
            .arg(
                Arg::with_name("NO_TAG_LATEST")
                    .long("no-tag-latest")
                    .conflicts_with("TAG_LATEST")
                    .help("Do not tag image with :\"latest\" (default: no)"),
            )
            .arg(
                Arg::with_name("TAG_CUSTOM")
                    .long("tag-custom")
                    .value_name("TAG_CUSTOM")
                    .help(
                        "Tag image with additional custom tag (supports: {{pkg_origin}}, \
                         {{pkg_name}}, {{pkg_version}}, {{pkg_release}}, {{channel}})",
                    ),
            );

        Cli { app }
    }

    pub fn add_publishing_args(self) -> Self {
        let app = self
            .app
            .arg(
                Arg::with_name("PUSH_IMAGE")
                    .long("push-image")
                    .conflicts_with("NO_PUSH_IMAGE")
                    .requires_all(&["REGISTRY_USERNAME", "REGISTRY_PASSWORD"])
                    .help("Push image to remote registry (default: no)"),
            )
            .arg(
                Arg::with_name("NO_PUSH_IMAGE")
                    .long("no-push-image")
                    .conflicts_with("PUSH_IMAGE")
                    .help("Do not push image to remote registry (default: yes)"),
            )
            .arg(
                Arg::with_name("REGISTRY_USERNAME")
                    .long("username")
                    .short("U")
                    .value_name("REGISTRY_USERNAME")
                    .requires("REGISTRY_PASSWORD")
                    .help(
                        "Remote registry username, required for pushing image to remote registry",
                    ),
            )
            .arg(
                Arg::with_name("REGISTRY_PASSWORD")
                    .long("password")
                    .short("P")
                    .value_name("REGISTRY_PASSWORD")
                    .requires("REGISTRY_USERNAME")
                    .help(
                        "Remote registry password, required for pushing image to remote registry",
                    ),
            )
            .arg(
                Arg::with_name("REGISTRY_TYPE")
                    .possible_values(RegistryType::variants())
                    .long("registry-type")
                    .short("R")
                    .value_name("REGISTRY_TYPE")
                    .help("Remote registry type (default: docker)"),
            )
            .arg(
                Arg::with_name("REGISTRY_URL")
                    // This is not strictly a requirement but will keep someone from
                    // making a mistake when inputing an ECR URL
                    .required_if("REGISTRY_TYPE", "amazon")
                    .required_if("REGISTRY_TYPE", "azure")
                    .long("registry-url")
                    .short("G")
                    .value_name("REGISTRY_URL")
                    .help("Remote registry url"),
            )
            // Cleanup
            .arg(
                Arg::with_name("RM_IMAGE")
                    .long("rm-image")
                    .help("Remove local image from engine after build and/or push (default: no)"),
            );

        Cli { app }
    }

    pub fn add_pkg_ident_arg(self, options: PkgIdentArgOptions) -> Self {
        let help = if options.multiple {
            "One or more Habitat package identifiers (ex: acme/redis) and/or filepaths to a \
             Habitat Artifact (ex: /home/acme-redis-3.0.7-21120102031201-x86_64-linux.hart)"
        } else {
            "A Habitat package identifier (ex: acme/redis) and/or filepath to a Habitat Artifact \
             (ex: /home/acme-redis-3.0.7-21120102031201-x86_64-linux.hart)"
        };

        let app =
            self.app
                .arg(Arg::with_name("PKG_IDENT_OR_ARTIFACT").value_name("PKG_IDENT_OR_ARTIFACT")
                                                            .required(true)
                                                            .multiple(options.multiple)
                                                            .help(help));

        Cli { app }
    }

    pub fn add_memory_arg(self) -> Self {
        let app = self.app
                      .arg(Arg::with_name("MEMORY_LIMIT").value_name("MEMORY_LIMIT")
                                                         .long("memory")
                                                         .short("m")
                                                         .help("Memory limit passed to docker \
                                                                build's --memory arg (ex: 2gb)"));

        Cli { app }
    }

    pub fn add_base_image_arg(self) -> Self {
        let app = self.app
                      .arg(Arg::with_name("BASE_IMAGE").value_name("BASE_IMAGE")
                                                       .long("base-image")
                                                       .help("Base image of the final exported \
                                                              image --base-image \
                                                              mcr.microsoft.com/windows/\
                                                              servercore:ltsc2019"));

        Cli { app }
    }

    pub fn add_layer_arg(self) -> Self {
        let app =
            self.app
                .arg(Arg::with_name("MULTI_LAYER").value_name("MULTI_LAYER")
                                                  .long("multi-layer")
                                                  .required(false)
                                                  .takes_value(false)
                                                  .multiple(false)
                                                  .help("If specified, creates an image where \
                                                         each Habitat package is added in its \
                                                         own layer, in dependency order (that \
                                                         is, low-level dependencies are added \
                                                         first, with user packages added last). \
                                                         This will allow for reusable layers, \
                                                         reducing storage and network \
                                                         transmission costs. If the resulting \
                                                         image cannot be built because there \
                                                         are too many layers, re-build without \
                                                         specifying this option to add all \
                                                         Habitat packages in a single layer \
                                                         (which is the default behavior)."));
        Cli { app }
    }
}

#[allow(clippy::needless_pass_by_value)] // Signature required by CLAP
fn valid_ident_or_hart(val: String) -> result::Result<(), String> {
    if Path::new(&val).is_file() {
        Ok(())
    } else if val.ends_with(".hart") {
        Err(format!("Habitat artifact file: '{}' not found", &val))
    } else {
        match PackageIdent::from_str(&val) {
            Ok(_) => Ok(()),
            Err(e) => Err(format!("{}", e)),
        }
    }
}

#[allow(clippy::needless_pass_by_value)] // Signature required by CLAP
fn valid_url(val: String) -> result::Result<(), String> {
    match Url::parse(&val) {
        Ok(_) => Ok(()),
        Err(_) => Err(format!("URL: '{}' is not valid", &val)),
    }
}
<|endoftext|>


<commit_before>use core::gameboy::*;
use core::rom::*;
use core::sink::*;
use minifb::{Key, WindowOptions, Window, Scale, KeyRepeat};
use std::{thread, time};

const CLOCK_SPEED: i32 = 4194304;
const FRAME_RATE: i32 = 60;

pub struct Emulator {
	gameboy: GameBoy,
	window: Window,
}

impl Emulator {

	pub fn new(rom: Rom) -> Emulator {
		let mut title = "Gameboy Crust - ".to_owned();
		title.push_str(&rom.name());
		Emulator {
			gameboy: GameBoy::new(rom),
			window: Window::new(title.as_str(), 160, 144, WindowOptions {
				borderless: false,
				title: true,
				resize: false,
				scale: Scale::X4,
			}).unwrap(),
		}
	}

	pub fn run(&mut self) {

		let mut tile_window: Option<Box<Window>> = None;

		while self.window.is_open() && !self.window.is_key_down(Key::Escape) {
			let mut video_sink = VideoSink::new();
			let cycles_per_frame = CLOCK_SPEED / FRAME_RATE;
			let mut emulated_cycles = 0;

			while emulated_cycles <= cycles_per_frame {
				emulated_cycles += self.gameboy.step(&mut video_sink) as i32;
			}

			if let Some(frame) = video_sink.consume() {
				self.window.update_with_buffer(frame.as_slice()).unwrap();

				if self.window.is_key_pressed(Key::V, KeyRepeat::No) {
					self.toggle_vram(&mut tile_window);
				}

				match tile_window.as_mut() {
					Some(window) => {
						let buffer = self.gameboy.interconnect.gpu.get_tiles();
						window.update_with_buffer(&buffer).unwrap();
					},
					None => {},
				}
			}

			thread::sleep(time::Duration::from_millis(10));
		}

		self.gameboy.cpu.debug();
	}

	fn toggle_vram(&self, tile_viewer: &mut Option<Box<Window>>) {
		if tile_viewer.is_some() {
			println!("Closing VRAM window");
			*tile_viewer = None
		} else {
			println!("Opening VRAM window");
			*tile_viewer = Some(Box::new(Window::new("VRAM Tile Viewer", 128, 192, WindowOptions {
				borderless: false,
				title: true,
				resize: false,
				scale: Scale::X4,
			}).unwrap()));
		}
	}
}
<commit_msg>sorted out window issues<commit_after>use core::gameboy::*;
use core::rom::*;
use core::sink::*;
use minifb::{Key, WindowOptions, Window, Scale, KeyRepeat};
use std::{thread, time};

const CLOCK_SPEED: i32 = 4194304;
const FRAME_RATE: i32 = 60;

pub struct Emulator {
	gameboy: GameBoy,
	window: Window,
}

impl Emulator {

	pub fn new(rom: Rom) -> Emulator {
		let mut title = "Gameboy Crust - ".to_owned();
		title.push_str(&rom.name());
		Emulator {
			gameboy: GameBoy::new(rom),
			window: Window::new(title.as_str(), 160, 144, WindowOptions {
				borderless: false,
				title: true,
				resize: false,
				scale: Scale::X4,
			}).unwrap(),
		}
	}

	pub fn run(&mut self) {

		let mut tile_window: Option<Window> = None;

		while self.window.is_open() && !self.window.is_key_down(Key::Escape) {
			let mut video_sink = VideoSink::new();
			let cycles_per_frame = CLOCK_SPEED / FRAME_RATE;
			let mut emulated_cycles = 0;

			while emulated_cycles <= cycles_per_frame {
				emulated_cycles += self.gameboy.step(&mut video_sink) as i32;
			}

			if let Some(frame) = video_sink.consume() {
				self.window.update_with_buffer(frame.as_slice()).unwrap();

				if self.window.is_key_pressed(Key::V, KeyRepeat::No) {
					println!("V PRESSED");
					self.toggle_vram(&mut tile_window);
				}

				self.vram_loop(&mut tile_window);
			}

			thread::sleep(time::Duration::from_millis(10));
		}

		self.gameboy.cpu.debug();
	}

	fn vram_loop(&mut self, window: &mut Option<Window>) {
		let mut close = false;
		if let Some(vram) = window.as_mut() {
			if vram.is_open() {
				let buffer = self.gameboy.interconnect.gpu.get_tiles();
				vram.update_with_buffer(buffer.as_slice()).unwrap();
			} else {
				close = true;
			}
		}
		if close {
			*window = None;
		}
	}

	fn toggle_vram(&self, tile_viewer: &mut Option<Window>) {
		if tile_viewer.is_some() {
			println!("Closing VRAM window");
			*tile_viewer = None
		} else {
			println!("Opening VRAM window");
			*tile_viewer = Some(Window::new("VRAM Tile Viewer", 128, 192, WindowOptions {
				borderless: false,
				title: true,
				resize: false,
				scale: Scale::X4,
			}).unwrap());
		}
	}
}
<|endoftext|>


<commit_before>#![cfg(test)]
use traits::Cell;
use traits::Coord;
use traits::Grid;
use traits::Engine;
use traits::ReprConsumer;
use engine::Sequential;
use grid::nhood::VonNeumannNhood;
use grid::square::SquareGrid;

/// Implementation of [HPP model](https://en.wikipedia.org/wiki/HPP_model).
/// Assumes Von Nuemann's neighborhood.

#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
enum Stage {
    Collision,
    Transport
}

impl Default for Stage {
    fn default() -> Self { Stage::Collision }
}

#[derive(Clone, Copy, Debug, PartialEq)]
enum Direction {
    Up,
    Left,
    Right,
    Down
}

impl Direction {

    fn opposite(&self) -> Self {

        match *self {
            Direction::Up => Direction::Down,
            Direction::Left => Direction::Right,
            Direction::Right => Direction::Left,
            Direction::Down => Direction::Up
        }
    }

    fn perpendicular(&self) -> Self {

        match *self {
            Direction::Up => Direction::Left,
            Direction::Left => Direction::Down,
            Direction::Right => Direction::Up,
            Direction::Down => Direction::Right
        }
    }
}

#[derive(Clone, Debug, Default, Serialize, Deserialize)]
struct HPP {
    particles: [bool; 4],
    stage: Stage,
    coord: (i32, i32)
}

impl Cell for HPP {
    type Coord = (i32, i32);

    fn step<'a, I>(&'a self, neighbors: I) -> Self
            where I: Iterator<Item=Option<&'a Self>> {

        match self.stage {
            Stage::Collision => self.collision(neighbors),
            Stage::Transport => self.transport(neighbors),
        }
    }

    fn with_coord<C: Coord>(coord: C) -> Self {
        HPP {
            stage: Stage::Collision,
            coord: (coord.x(), coord.y()),
            ..Default::default()
        }
    }

    fn coord(&self) -> &Self::Coord {
        &self.coord
    }

    fn set_coord<C: Coord>(&mut self, coord: &C) {
        self.coord = (coord.x(), coord.y());
    }
}

impl HPP {

    fn collision<'a, I>(&self, neighbors: I) -> Self
        where I: Iterator<Item=Option<&'a Self>> {

        let mut new = HPP {
            stage: Stage::Transport,
            ..Default::default()
        };

        for (neighbor, direction) in neighbors.zip(self.directions().iter()) {

            match neighbor {

                Some(neighbor) => {
                    let opposite = direction.opposite();
                    let head_on = self.particle(&direction) && neighbor.particle(&opposite);

                    if head_on {
                        new.set_particle(&direction.perpendicular(), self.particle(&direction));
                    }
                    else {
                        let particle = new.particle(&direction) || self.particle(&direction);
                        new.set_particle(&direction, particle);
                    }
                },
                // Rebound
                None => {
                    let opposite = direction.opposite();
                    new.set_particle(&opposite, self.particle(direction));
                }
            }
        }

        new
    }

    fn transport<'a, I>(&self, neighbors: I) -> Self
        where I: Iterator<Item=Option<&'a Self>> {

        let mut new = HPP {
            stage: Stage::Collision,
            ..Default::default()
        };

        for (neighbor, direction) in neighbors.zip(self.directions().iter()) {

            match neighbor {
                Some(neighbor) => {
                    let opposite = direction.opposite();
                    new.set_particle(
                        &opposite,
                        neighbor.particle(&opposite) || self.particle(&opposite)
                    );
                },
                None => {
                    new.set_particle(&direction, self.particle(&direction))
                }
            }
        }

        new
    }

    pub fn particle(&self, direction: &Direction) -> bool {

        match *direction {
            Direction::Up => self.particles[0],
            Direction::Left => self.particles[1],
            Direction::Right => self.particles[2],
            Direction::Down => self.particles[3]
        }
    }

    fn set_particle(&mut self, direction: &Direction, exists: bool) {

        match *direction {
            Direction::Up => { self.particles[0] = exists },
            Direction::Left => { self.particles[1] = exists },
            Direction::Right => { self.particles[2] = exists },
            Direction::Down => { self.particles[3] = exists }
        }
    }

    #[inline]
    pub fn directions(&self) -> [Direction; 4] {
        [Direction::Up, Direction::Left, Direction::Right, Direction::Down]
    }
}

#[derive(Debug)]
struct HPPTestConsumer;

use test_helpers::to_cell;

impl HPPTestConsumer {

    pub fn new() -> Self {
        HPPTestConsumer { }
    }

    fn particles_count<C: Cell>(&self,
                                 cells: &Vec<C>,
                                 direction: &Direction) -> i32 {

        cells.iter()
             .map(|c| to_cell(c))
             .filter(|c: &HPP| c.particle(direction) == true)
             .count() as i32
    }

    fn find_cell<C: Cell>(&self,
                          cells: &Vec<C>,
                          x: i32, y: i32) -> HPP {

        assert!(cells.iter().any(|c| c.coord().x() == x && c.coord().y() == y));

        let found = cells.iter()
                         .find(|c| c.coord().x() == x && c.coord().y() == y)
                         .unwrap();

        to_cell(found)
    }

    fn test_collision<G: Grid>(&self, grid: &G) {

        let left_particle_count =
            self.particles_count(&grid.cells(), &Direction::Left);
        assert_eq!(left_particle_count, 0);

        let right_particle_count =
            self.particles_count(&grid.cells(), &Direction::Right);
        assert_eq!(right_particle_count, 2);

        let up_particles_count =
            self.particles_count(&grid.cells(), &Direction::Up);
        assert_eq!(up_particles_count, 1);

        let down_particles_count =
            self.particles_count(&grid.cells(), &Direction::Down);
        assert_eq!(down_particles_count, 1);

        let rebound_to_right =
            self.find_cell(&grid.cells(), 0, 1);
        assert_eq!(rebound_to_right.particle(&Direction::Right), true);

        let head_on_up =
            self.find_cell(&grid.cells(), 1, 0);
        assert_eq!(head_on_up.particle(&Direction::Up), true);

        let head_on_down =
            self.find_cell(&grid.cells(), 2, 0);
        assert_eq!(head_on_down.particle(&Direction::Down), true);
    }

    fn test_transport<G: Grid>(&self, grid: &G) {
        let simple_move_to_right = self.find_cell(&grid.cells(), 1, 2);
        assert_eq!(simple_move_to_right.particle(&Direction::Right), true);

        let move_to_right_after_rebound = self.find_cell(&grid.cells(), 1, 2);
        assert_eq!(move_to_right_after_rebound.particle(&Direction::Right), true);

        let move_to_down_after_head_on = self.find_cell(&grid.cells(), 2, 1);
        assert_eq!(move_to_down_after_head_on.particle(&Direction::Down), true);

        let fixed_to_up_after_head_on = self.find_cell(&grid.cells(), 1, 0);
        assert_eq!(fixed_to_up_after_head_on.particle(&Direction::Up), true);
    }

    fn pretty_print<G: Grid>(&self, grid: &G) {
        println!("");

        for y in 0 .. 3 {
            print!("|");

            for x in 0 .. 3 {
                let cell = self.find_cell(grid.cells(), x, y);
                let directions = cell.directions();
                let maybe_particle =
                    directions.iter().find(|d| cell.particle(d));

                let to_print = match maybe_particle {
                    Some(&Direction::Up) => " ^ |",
                    Some(&Direction::Left) => " < |",
                    Some(&Direction::Right) => " > |",
                    Some(&Direction::Down) => " v |",
                    None => " * |",
                };
                print!("{}", to_print);
            }

            println!("");
        }
    }
}

impl ReprConsumer for HPPTestConsumer {

    fn consume<G: Grid>(&mut self, grid: &G) {
        assert_eq!(grid.cells().len(), 9);

        self.pretty_print(grid);

        // We are testing previous state.
        let first: HPP = to_cell(&grid.cells()[0]);

        match first.stage {
            Stage::Collision => self.test_transport(grid),
            Stage::Transport => self.test_collision(grid),
        }
    }
}

#[test]
fn test_particles() {
    // initial      collision    transport
    // | * > < |    | * ^ v |    | * ^ * |
    // | < * * | => | > * * | => | * > v |
    // | > * * |    | > * * |    | * > * |
    // 3x3 grid with 4 particles. There should be
    // one rebound, head-on collision and simple move.

    let left_particle = [false, true, false, false];
    let right_particle = [false, false, true, false];

    let cells = vec![
        HPP { stage: Stage::Collision, particles: right_particle, coord: (1, 0) },
        HPP { stage: Stage::Collision, particles: left_particle, coord: (2, 0) },
        HPP { stage: Stage::Collision, particles: left_particle, coord: (0, 1) },
        HPP { stage: Stage::Collision, particles: right_particle, coord: (0, 2) },
    ];

    let nhood = VonNeumannNhood::new();
    let mut grid: SquareGrid<HPP, _> = SquareGrid::new(3, 3, nhood);
    grid.set_cells(cells);

    let right_particles_count =
        grid.cells()
            .iter()
            .map(|c| to_cell(c))
            .filter(|c: &HPP| c.particle(&Direction::Right) == true)
            .count();
    assert_eq!(right_particles_count, 2);

    let consumer = HPPTestConsumer::new();
    let mut engine = Sequential::new(grid, consumer);
    engine.run_times(2);
}
<commit_msg>Fixed HPP example + tests.<commit_after>#![cfg(test)]
use traits::Cell;
use traits::Coord;
use traits::Grid;
use traits::Engine;
use traits::ReprConsumer;
use engine::Sequential;
use grid::nhood::VonNeumannNhood;
use grid::square::SquareGrid;

/// Implementation of [HPP model](https://en.wikipedia.org/wiki/HPP_model).
/// Assumes Von Nuemann's neighborhood.

#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
enum Stage {
    Collision,
    Transport
}

impl Default for Stage {
    fn default() -> Self { Stage::Collision }
}

#[derive(Clone, Copy, Debug, PartialEq)]
enum Direction {
    Up,
    Left,
    Right,
    Down
}

impl Direction {

    fn opposite(&self) -> Self {

        match *self {
            Direction::Up => Direction::Down,
            Direction::Left => Direction::Right,
            Direction::Right => Direction::Left,
            Direction::Down => Direction::Up
        }
    }

    fn perpendicular(&self) -> Self {

        match *self {
            Direction::Up => Direction::Left,
            Direction::Left => Direction::Down,
            Direction::Right => Direction::Up,
            Direction::Down => Direction::Right
        }
    }
}

#[derive(Clone, Debug, Default, Serialize, Deserialize)]
struct HPP {
    particles: [bool; 4],
    stage: Stage,
    coord: (i32, i32)
}

impl Cell for HPP {
    type Coord = (i32, i32);

    fn step<'a, I>(&'a self, neighbors: I) -> Self
            where I: Iterator<Item=Option<&'a Self>> {

        match self.stage {
            Stage::Collision => self.collision(neighbors),
            Stage::Transport => self.transport(neighbors),
        }
    }

    fn with_coord<C: Coord>(coord: C) -> Self {
        HPP {
            stage: Stage::Collision,
            coord: (coord.x(), coord.y()),
            ..Default::default()
        }
    }

    fn coord(&self) -> &Self::Coord {
        &self.coord
    }

    fn set_coord<C: Coord>(&mut self, coord: &C) {
        self.coord = (coord.x(), coord.y());
    }
}

impl HPP {

    fn collision<'a, I>(&self, neighbors: I) -> Self
        where I: Iterator<Item=Option<&'a Self>> {

        let mut new = HPP {
            stage: Stage::Transport,
            ..Default::default()
        };

        for (neighbor, direction) in neighbors.zip(self.directions().iter()) {

            match neighbor {

                Some(neighbor) => {
                    let opposite = direction.opposite();
                    let head_on = self.particle(&direction) && neighbor.particle(&opposite);

                    if head_on {
                        new.set_particle(&direction.perpendicular(), self.particle(&direction));
                    }
                    else {
                        let particle = new.particle(&direction) || self.particle(&direction);
                        new.set_particle(&direction, particle);
                    }
                },
                // Rebound
                None => {
                    if self.particle(&direction) {
                        let opposite = direction.opposite();
                        new.set_particle(&opposite, true);
                    }
                }
            }
        }

        new
    }

    fn transport<'a, I>(&self, neighbors: I) -> Self
        where I: Iterator<Item=Option<&'a Self>> {

        let mut new = HPP {
            stage: Stage::Collision,
            ..Default::default()
        };

        for (neighbor, direction) in neighbors.zip(self.directions().iter()) {

            match neighbor {
                Some(neighbor) => {
                    let opposite = direction.opposite();

                    if neighbor.particle(&opposite) {
                        new.set_particle(&opposite, neighbor.particle(&opposite));
                    }
                },
                None => {
                    if self.particle(&direction) {
                        new.set_particle(&direction, true);
                    }
                }
            }
        }

        new
    }

    pub fn particle(&self, direction: &Direction) -> bool {

        match *direction {
            Direction::Up => self.particles[0],
            Direction::Left => self.particles[1],
            Direction::Right => self.particles[2],
            Direction::Down => self.particles[3]
        }
    }

    fn set_particle(&mut self, direction: &Direction, exists: bool) {

        match *direction {
            Direction::Up => { self.particles[0] = exists },
            Direction::Left => { self.particles[1] = exists },
            Direction::Right => { self.particles[2] = exists },
            Direction::Down => { self.particles[3] = exists }
        }
    }

    #[inline]
    pub fn directions(&self) -> [Direction; 4] {
        [Direction::Up, Direction::Left, Direction::Right, Direction::Down]
    }
}

#[derive(Debug)]
struct HPPRulesTestConsumer;

use test_helpers::to_cell;

impl HPPRulesTestConsumer {

    pub fn new() -> Self {
        HPPRulesTestConsumer { }
    }

    fn particles_count<C: Cell>(&self,
                                 cells: &Vec<C>,
                                 direction: &Direction) -> i32 {

        cells.iter()
             .map(|c| to_cell(c))
             .filter(|c: &HPP| c.particle(direction) == true)
             .count() as i32
    }

    fn find_cell<C: Cell>(&self,
                          cells: &Vec<C>,
                          x: i32, y: i32) -> HPP {

        assert!(cells.iter().any(|c| c.coord().x() == x && c.coord().y() == y));

        let found = cells.iter()
                         .find(|c| c.coord().x() == x && c.coord().y() == y)
                         .unwrap();

        to_cell(found)
    }

    fn test_collision<G: Grid>(&self, grid: &G) {
        println!("Collision");

        let left_particle_count =
            self.particles_count(&grid.cells(), &Direction::Left);
        assert_eq!(left_particle_count, 0);

        let right_particle_count =
            self.particles_count(&grid.cells(), &Direction::Right);
        assert_eq!(right_particle_count, 2);

        let up_particles_count =
            self.particles_count(&grid.cells(), &Direction::Up);
        assert_eq!(up_particles_count, 1);

        let down_particles_count =
            self.particles_count(&grid.cells(), &Direction::Down);
        assert_eq!(down_particles_count, 1);

        let rebound_to_right =
            self.find_cell(&grid.cells(), 0, 1);
        assert_eq!(rebound_to_right.particle(&Direction::Right), true);

        let head_on_up =
            self.find_cell(&grid.cells(), 1, 0);
        assert_eq!(head_on_up.particle(&Direction::Up), true);

        let head_on_down =
            self.find_cell(&grid.cells(), 2, 0);
        assert_eq!(head_on_down.particle(&Direction::Down), true);
    }

    fn test_transport<G: Grid>(&self, grid: &G) {
        println!("Transport");

        let simple_move_to_right = self.find_cell(&grid.cells(), 1, 2);
        assert_eq!(simple_move_to_right.particle(&Direction::Right), true);

        let move_to_right_after_rebound = self.find_cell(&grid.cells(), 1, 2);
        assert_eq!(move_to_right_after_rebound.particle(&Direction::Right), true);

        let move_to_down_after_head_on = self.find_cell(&grid.cells(), 2, 1);
        assert_eq!(move_to_down_after_head_on.particle(&Direction::Down), true);

        let fixed_to_up_after_head_on = self.find_cell(&grid.cells(), 1, 0);
        assert_eq!(fixed_to_up_after_head_on.particle(&Direction::Up), true);
    }

    fn pretty_print<G: Grid>(&self, grid: &G) {
        println!("");

        for y in 0 .. 3 {
            print!("|");

            for x in 0 .. 3 {
                let cell = self.find_cell(grid.cells(), x, y);
                let directions = cell.directions();
                let maybe_particle =
                    directions.iter().find(|d| cell.particle(d));

                let to_print = match maybe_particle {
                    Some(&Direction::Up) => " ^ |",
                    Some(&Direction::Left) => " < |",
                    Some(&Direction::Right) => " > |",
                    Some(&Direction::Down) => " v |",
                    None => " * |",
                };
                print!("{}", to_print);
            }

            println!("");
        }
    }
}

impl ReprConsumer for HPPRulesTestConsumer {

    fn consume<G: Grid>(&mut self, grid: &G) {
        assert_eq!(grid.cells().len(), 9);

        self.pretty_print(grid);

        // We are testing previous state.
        let first: HPP = to_cell(&grid.cells()[0]);

        match first.stage {
            Stage::Collision => self.test_transport(grid),
            Stage::Transport => self.test_collision(grid),
        }
    }
}

#[test]
fn test_rules() {
    // initial      collision    transport
    // | * > < |    | * ^ v |    | * ^ * |
    // | < * * | => | > * * | => | * > v |
    // | > * * |    | > * * |    | * > * |
    // 3x3 grid with 4 particles. There should be
    // one rebound, head-on collision and simple move.

    let left_particle = [false, true, false, false];
    let right_particle = [false, false, true, false];

    let cells = vec![
        HPP { stage: Stage::Collision, particles: right_particle, coord: (1, 0) },
        HPP { stage: Stage::Collision, particles: left_particle, coord: (2, 0) },
        HPP { stage: Stage::Collision, particles: left_particle, coord: (0, 1) },
        HPP { stage: Stage::Collision, particles: right_particle, coord: (0, 2) },
    ];

    let nhood = VonNeumannNhood::new();
    let mut grid: SquareGrid<HPP, _> = SquareGrid::new(3, 3, nhood);
    grid.set_cells(cells);

    let right_particles_count =
        grid.cells()
            .iter()
            .map(|c| to_cell(c))
            .filter(|c: &HPP| c.particle(&Direction::Right) == true)
            .count();
    assert_eq!(right_particles_count, 2);

    let consumer = HPPRulesTestConsumer::new();
    let mut engine = Sequential::new(grid, consumer);
    engine.run_times(2);
}

struct HPPSpreadTestConsumer {
    cur_y: i32,
    cur_direction: Direction
}

impl HPPSpreadTestConsumer {

    pub fn new() -> Self {
        HPPSpreadTestConsumer { cur_y: 0, cur_direction: Direction::Down }
    }

    fn particles_count<C: Cell>(&self,
                                 cells: &Vec<C>,
                                 direction: &Direction) -> i32 {

        cells.iter()
             .map(|c| to_cell(c))
             .filter(|c: &HPP| c.particle(direction) == true)
             .count() as i32
    }

    fn find_cell<C: Cell>(&self,
                          cells: &Vec<C>,
                          x: i32, y: i32) -> HPP {

        assert!(cells.iter().any(|c| c.coord().x() == x && c.coord().y() == y));

        let found = cells.iter()
                         .find(|c| c.coord().x() == x && c.coord().y() == y)
                         .unwrap();

        to_cell(found)
    }

    fn pretty_print<G: Grid>(&self, grid: &G) {
        println!("");

        for y in 0 .. 5 {
            print!("|");

            for x in 0 .. 5 {
                let cell = self.find_cell(grid.cells(), x, y);
                let directions = cell.directions();
                let maybe_particle =
                    directions.iter().find(|d| cell.particle(d));

                let to_print = match maybe_particle {
                    Some(&Direction::Up) => " ^ |",
                    Some(&Direction::Left) => " < |",
                    Some(&Direction::Right) => " > |",
                    Some(&Direction::Down) => " v |",
                    None => " * |",
                };
                print!("{}", to_print);
            }

            println!("");
        }
    }

    fn test_collision<G: Grid>(&mut self, grid: &G) {
        println!("Collision");
        println!("{} {:?}", self.cur_y, self.cur_direction);

        if self.cur_y == 0 {
            self.cur_direction = Direction::Down;
        }

        let particles_count =
            self.particles_count(&grid.cells(), &self.cur_direction);
        assert_eq!(particles_count, 5);

        if self.cur_direction == Direction::Down {
            self.cur_y += 1;
        }
        else {
            self.cur_y -= 1;
        }
    }

    fn test_transport<G: Grid>(&mut self, grid: &G) {
        println!("Transport");
        println!("{} {:?}", self.cur_y, self.cur_direction);

        let particles_count =
            self.particles_count(&grid.cells(), &self.cur_direction);
        assert_eq!(particles_count, 5);

        assert!(
            grid.cells().iter()
                        .map(|c| to_cell(c))
                        .filter(|c: &HPP| c.coord().y() == self.cur_y)
                        .all(|c| c.particle(&self.cur_direction) == true)
        );

        if self.cur_y == 4 {
            self.cur_direction = Direction::Up;
        }
    }
}

impl ReprConsumer for HPPSpreadTestConsumer {

    fn consume<G: Grid>(&mut self, grid: &G) {
        assert_eq!(grid.cells().len(), 25);

        self.pretty_print(grid);

        // We are testing previous state.
        let first: HPP = to_cell(&grid.cells()[0]);

        match first.stage {
            Stage::Collision => self.test_transport(grid),
            Stage::Transport => self.test_collision(grid),
        }
    }
}

#[test]
fn test_spread() {
    // initial          later
    // | v v v v v |    | * * * * * |
    // | * * * * * |    | v v v v v |
    // | * * * * * | => | * * * * * | => (so on)
    // | * * * * * |    | * * * * * |
    // | * * * * * |    | * * * * * |
    // 5x5 grid with 5 particles. Particles should move
    // to lower border then rebound, then move to upper and so on.

    let down_particle = [false, false, false, true];

    let mut cells = Vec::new();
    for x in 0 .. 5 {
        cells.push(HPP {
            stage: Stage::Collision,
            particles: down_particle,
            coord: (x, 0)
        });
    }

    let nhood = VonNeumannNhood::new();
    let mut grid: SquareGrid<HPP, _> = SquareGrid::new(5, 5, nhood);
    grid.set_cells(cells);

    let consumer = HPPSpreadTestConsumer::new();
    let mut engine = Sequential::new(grid, consumer);
    // 2 phases * 10 full cycles = 20 times.
    engine.run_times(20);
}<|endoftext|>


<commit_before>use std::path::Path;
use std::str::FromStr;
use temperature::{self, Simulator};

use platform::{self, ElementKind, Platform, Profile, ProfileBuilder};
use schedule::Decision;
use system::Job;
use workload;
use {Config, Result};

/// A platform producing power and temperature data.
pub struct Thermal {
    elements: Vec<platform::Element>,
    simulator: Simulator,
    builder: ProfileBuilder,
}

impl Thermal {
    /// Create a platform.
    pub fn new(config: &Config) -> Result<Thermal> {
        let (elements, simulator) = try!(construct_temperature(config.branch("temperature")
                                                                     .as_ref().unwrap_or(config)));

        let builder = try!(construct_power(&elements, config.branch("power").as_ref()
                                                            .unwrap_or(config)));

        Ok(Thermal { elements: elements, simulator: simulator, builder: builder })
    }
}

impl Platform for Thermal {
    type Data = (Profile, Profile);

    #[inline(always)]
    fn elements(&self) -> &[platform::Element] {
        &self.elements
    }

    fn next(&mut self, time: f64) -> Option<Self::Data> {
        let power = self.builder.pull(time);
        let mut temperature = power.clone_zero();
        self.simulator.next(&power, &mut temperature);
        Some((power, temperature))
    }

    fn push(&mut self, job: &Job, decision: &Decision) -> Result<()> {
        let pattern = &job.pattern;
        let (from, onto) = (&pattern.elements, &self.elements);
        for &(i, j) in &decision.mapping {
            let (from, onto) = (&from[i], &onto[j]);
            self.builder.push(onto.id, decision.start, pattern.time_step, &from.dynamic_power);
        }
        Ok(())
    }
}

fn construct_power(elements: &[platform::Element], config: &Config) -> Result<ProfileBuilder> {
    let units = elements.len();
    let time_step = *some!(config.get::<f64>("time_step"), "a time step is required");

    let path = path!(config, "a leakage pattern is required");
    info!(target: "Platform", "Modeling leakage power based on {:?}...", &path);
    let candidates = try!(workload::Element::collect(path));

    let mut leakage_power = vec![0.0; units];
    for i in 0..units {
        if let Some(element) = candidates.iter().find(|element| element.kind == elements[i].kind) {
            leakage_power[i] = element.leakage_power;
        } else {
            raise!("cannot find leakage data for a processing element");
        }
    }

    Ok(ProfileBuilder::new(units, time_step, leakage_power))
}

fn construct_temperature(config: &Config) -> Result<(Vec<platform::Element>, Simulator)> {
    let path = path!(config, "a thermal specification is required");
    info!(target: "Platform", "Modeling temperature based on {:?}...", &path);
    let (elements, circuit) = match path.extension() {
        Some(extension) if extension == "stk" => try!(construct_threed_ice(&path)),
        _ => raise!("the format of {:?} is unknown", &path),
    };
    info!(target: "Platform", "Found {} processing elements and {} thermal nodes.",
          elements.len(), circuit.capacitance.len());

    info!(target: "Platform", "Initializing the temperature simulator...");
    let config = temperature::Config {
        ambience: *some!(config.get::<f64>("ambience"), "an ambient temperature is required"),
        time_step: *some!(config.get::<f64>("time_step"), "a time step is required"),
    };
    let simulator = ok!(Simulator::new(circuit, config));

    Ok((elements, simulator))
}

fn construct_threed_ice(path: &Path) -> Result<(Vec<platform::Element>, temperature::Circuit)> {
    use temperature::circuit::ThreeDICE;
    use threed_ice::{StackElement, System};

    let system = ok!(System::new(path));
    let mut elements = vec![];
    for element in system.stack.elements.iter().rev() {
        let die = match element {
            &StackElement::Die(ref die) => die,
            _ => continue,
        };
        for element in die.floorplan.elements.iter() {
            let id = elements.len();
            let kind = try!(ElementKind::from_str(&element.id));
            elements.push(platform::Element { id: id, kind: kind });
        }
    }
    Ok((elements, ok!(ThreeDICE::from(&system))))
}

#[cfg(test)]
mod tests {
    use configuration::format::TOML;
    use platform::{Element, ElementKind, Thermal};

    #[test]
    fn new() {
        let config = TOML::open("tests/fixtures/streamer.toml").unwrap()
                                                               .branch("platform")
                                                               .unwrap();
        let platform = Thermal::new(&config).unwrap();
        assert_eq!(platform.elements, &[
            Element { id: 0, kind: ElementKind::Core },
            Element { id: 1, kind: ElementKind::Core },
            Element { id: 2, kind: ElementKind::Core },
            Element { id: 3, kind: ElementKind::Core },
            Element { id: 4, kind: ElementKind::L3 },
        ]);
    }
}
<commit_msg>A cosmetic change<commit_after>use std::path::Path;
use std::str::FromStr;
use temperature::{self, Simulator};

use platform::{Element, ElementKind, Platform, Profile, ProfileBuilder};
use schedule::Decision;
use system::Job;
use {Config, Result};

/// A platform producing power and temperature data.
pub struct Thermal {
    elements: Vec<Element>,
    simulator: Simulator,
    builder: ProfileBuilder,
}

impl Thermal {
    /// Create a platform.
    pub fn new(config: &Config) -> Result<Thermal> {
        let (elements, simulator) = try!(construct_temperature(config.branch("temperature")
                                                                     .as_ref().unwrap_or(config)));

        let builder = try!(construct_power(&elements, config.branch("power").as_ref()
                                                            .unwrap_or(config)));

        Ok(Thermal { elements: elements, simulator: simulator, builder: builder })
    }
}

impl Platform for Thermal {
    type Data = (Profile, Profile);

    #[inline(always)]
    fn elements(&self) -> &[Element] {
        &self.elements
    }

    fn next(&mut self, time: f64) -> Option<Self::Data> {
        let power = self.builder.pull(time);
        let mut temperature = power.clone_zero();
        self.simulator.next(&power, &mut temperature);
        Some((power, temperature))
    }

    fn push(&mut self, job: &Job, decision: &Decision) -> Result<()> {
        let pattern = &job.pattern;
        let (from, onto) = (&pattern.elements, &self.elements);
        for &(i, j) in &decision.mapping {
            let (from, onto) = (&from[i], &onto[j]);
            self.builder.push(onto.id, decision.start, pattern.time_step, &from.dynamic_power);
        }
        Ok(())
    }
}

fn construct_power(elements: &[Element], config: &Config) -> Result<ProfileBuilder> {
    use workload;

    let units = elements.len();
    let time_step = *some!(config.get::<f64>("time_step"), "a time step is required");

    let path = path!(config, "a leakage pattern is required");
    info!(target: "Platform", "Modeling leakage power based on {:?}...", &path);
    let candidates = try!(workload::Element::collect(path));

    let mut leakage_power = vec![0.0; units];
    for i in 0..units {
        if let Some(element) = candidates.iter().find(|element| element.kind == elements[i].kind) {
            leakage_power[i] = element.leakage_power;
        } else {
            raise!("cannot find leakage data for a processing element");
        }
    }

    Ok(ProfileBuilder::new(units, time_step, leakage_power))
}

fn construct_temperature(config: &Config) -> Result<(Vec<Element>, Simulator)> {
    let path = path!(config, "a thermal specification is required");
    info!(target: "Platform", "Modeling temperature based on {:?}...", &path);
    let (elements, circuit) = match path.extension() {
        Some(extension) if extension == "stk" => try!(construct_threed_ice(&path)),
        _ => raise!("the format of {:?} is unknown", &path),
    };
    info!(target: "Platform", "Found {} processing elements and {} thermal nodes.",
          elements.len(), circuit.capacitance.len());

    info!(target: "Platform", "Initializing the temperature simulator...");
    let config = temperature::Config {
        ambience: *some!(config.get::<f64>("ambience"), "an ambient temperature is required"),
        time_step: *some!(config.get::<f64>("time_step"), "a time step is required"),
    };
    let simulator = ok!(Simulator::new(circuit, config));

    Ok((elements, simulator))
}

fn construct_threed_ice(path: &Path) -> Result<(Vec<Element>, temperature::Circuit)> {
    use temperature::circuit::ThreeDICE;
    use threed_ice::{StackElement, System};

    let system = ok!(System::new(path));
    let mut elements = vec![];
    for element in system.stack.elements.iter().rev() {
        let die = match element {
            &StackElement::Die(ref die) => die,
            _ => continue,
        };
        for element in die.floorplan.elements.iter() {
            let id = elements.len();
            let kind = try!(ElementKind::from_str(&element.id));
            elements.push(Element { id: id, kind: kind });
        }
    }
    Ok((elements, ok!(ThreeDICE::from(&system))))
}

#[cfg(test)]
mod tests {
    use configuration::format::TOML;
    use platform::{Element, ElementKind, Thermal};

    #[test]
    fn new() {
        let config = TOML::open("tests/fixtures/streamer.toml").unwrap()
                                                               .branch("platform")
                                                               .unwrap();
        let platform = Thermal::new(&config).unwrap();
        assert_eq!(platform.elements, &[
            Element { id: 0, kind: ElementKind::Core },
            Element { id: 1, kind: ElementKind::Core },
            Element { id: 2, kind: ElementKind::Core },
            Element { id: 3, kind: ElementKind::Core },
            Element { id: 4, kind: ElementKind::L3 },
        ]);
    }
}
<|endoftext|>


<commit_before>// Copyright © 2012 Bart Massey
// [This program is licensed under the "MIT License"]
// Please see the file COPYING in the source
// distribution of this software for license terms.

// CipherSaber
// http://ciphersaber.gurus.com

extern crate getopts;
extern crate rpassword;

use getopts::Options;
use rpassword::read_password_prompt;
use std::env;
use std::fs::File;
use std::io::{stdin, stdout, Read, Write};
use std::path::Path;
use std::error::Error;

fn mkiv(ivb: &mut [u8;10]) {
    // http://rustbyexample.com/std_misc/file/open.html
    let urandom = Path::new("/dev/urandom");
    let mut fd = match File::open(&urandom) {
        Err(why) => panic!("couldn't open {}: {}",
                           urandom.display(),
                           why.description()),
        Ok(file) => file
    };
    fd.read_exact(ivb).expect(&format!("couldn't read {}", urandom.display()));
}

enum Dirn {
    Encrypt,
    Decrypt
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let mut opts = Options::new();
    opts.optflag("e", "encrypt", "encrypt input to output");
    opts.optflag("d", "decrypt", "decrypt input to output");
    opts.optopt("k", "key", "KEY", "key on command line (dangerous)");
    opts.optopt("r", "reps", "N",
                "number of key-scheduling reps (default 20)");
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => panic!(f.to_string())
    };
    let en = matches.opt_present("e");
    let de = matches.opt_present("d");
    if en && de {
        panic!("cannot both encrypt and decrypt");
    }
    if !en && !de {
        panic!("must encrypt or decrypt");
    }
    let dirn = if en {
        Dirn::Encrypt
    } else {
        assert!(de);
        Dirn::Decrypt
    };
    let mut keybytes: Vec<u8> = vec![];
    match matches.opt_str("k") {
        Some(s) => keybytes.extend_from_slice(s.as_bytes()),
        _ => {
            let s = read_password_prompt("key:").expect("password read error");
            keybytes.extend_from_slice(s.as_bytes());
        }
    };
    let reps = match matches.opt_str("r") {
        Some(rs) => rs.trim().parse().expect("bad rep count"),
        _ => 20
    };

    let mut sin = stdin();
    let mut sout = stdout();
    let mut ivb = [0u8;10];
    match dirn {
        Dirn::Encrypt => {
            mkiv(&mut ivb);
            sout.write(&ivb).expect("write failed");
        }
        Dirn::Decrypt => {
            sin.read_exact(&mut ivb).expect("couldn't read iv");
        }
    };
    keybytes.extend_from_slice(&ivb);

    let mut state: [u8;256] = [0u8; 256];
    for k in 0..state.len() {
        state[k] = k as u8;
    }
    let kl = keybytes.len();
    let mut i: usize = 0;
    for _ in 0..reps {
        for j in 0..state.len() {
            i = (i + state[j] as usize + keybytes[j % kl] as usize) & 0xff;
            state.swap(i, j);
        }
    }

    let mut i: usize = 0;
    let mut j: usize = 0;
    for ch in sin.bytes() {
        i = (i + 1) & 0xff;
        j = (j + state[i] as usize) & 0xff;
        let si = state[i];
        let sj = state[j];
        state[i] = sj;
        state[j] = si;
        let plain = ch.unwrap();
        let cipher = state[(si as usize + sj as usize) & 0xff] ^ plain;
        let b = [cipher];
        sout.write(&b).expect("write error");
    }
}
<commit_msg>removed extraneous explicit type<commit_after>// Copyright © 2012 Bart Massey
// [This program is licensed under the "MIT License"]
// Please see the file COPYING in the source
// distribution of this software for license terms.

// CipherSaber
// http://ciphersaber.gurus.com

extern crate getopts;
extern crate rpassword;

use getopts::Options;
use rpassword::read_password_prompt;
use std::env;
use std::fs::File;
use std::io::{stdin, stdout, Read, Write};
use std::path::Path;
use std::error::Error;

fn mkiv(ivb: &mut [u8;10]) {
    // http://rustbyexample.com/std_misc/file/open.html
    let urandom = Path::new("/dev/urandom");
    let mut fd = match File::open(&urandom) {
        Err(why) => panic!("couldn't open {}: {}",
                           urandom.display(),
                           why.description()),
        Ok(file) => file
    };
    fd.read_exact(ivb).expect(&format!("couldn't read {}", urandom.display()));
}

enum Dirn {
    Encrypt,
    Decrypt
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let mut opts = Options::new();
    opts.optflag("e", "encrypt", "encrypt input to output");
    opts.optflag("d", "decrypt", "decrypt input to output");
    opts.optopt("k", "key", "KEY", "key on command line (dangerous)");
    opts.optopt("r", "reps", "N",
                "number of key-scheduling reps (default 20)");
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => panic!(f.to_string())
    };
    let en = matches.opt_present("e");
    let de = matches.opt_present("d");
    if en && de {
        panic!("cannot both encrypt and decrypt");
    }
    if !en && !de {
        panic!("must encrypt or decrypt");
    }
    let dirn = if en {
        Dirn::Encrypt
    } else {
        assert!(de);
        Dirn::Decrypt
    };
    let mut keybytes: Vec<u8> = vec![];
    match matches.opt_str("k") {
        Some(s) => keybytes.extend_from_slice(s.as_bytes()),
        _ => {
            let s = read_password_prompt("key:").expect("password read error");
            keybytes.extend_from_slice(s.as_bytes());
        }
    };
    let reps = match matches.opt_str("r") {
        Some(rs) => rs.trim().parse().expect("bad rep count"),
        _ => 20
    };

    let mut sin = stdin();
    let mut sout = stdout();
    let mut ivb = [0u8;10];
    match dirn {
        Dirn::Encrypt => {
            mkiv(&mut ivb);
            sout.write(&ivb).expect("write failed");
        }
        Dirn::Decrypt => {
            sin.read_exact(&mut ivb).expect("couldn't read iv");
        }
    };
    keybytes.extend_from_slice(&ivb);

    let mut state = [0u8; 256];
    for k in 0..state.len() {
        state[k] = k as u8;
    }
    let kl = keybytes.len();
    let mut i: usize = 0;
    for _ in 0..reps {
        for j in 0..state.len() {
            i = (i + state[j] as usize + keybytes[j % kl] as usize) & 0xff;
            state.swap(i, j);
        }
    }

    let mut i: usize = 0;
    let mut j: usize = 0;
    for ch in sin.bytes() {
        i = (i + 1) & 0xff;
        j = (j + state[i] as usize) & 0xff;
        let si = state[i];
        let sj = state[j];
        state[i] = sj;
        state[j] = si;
        let plain = ch.unwrap();
        let cipher = state[(si as usize + sj as usize) & 0xff] ^ plain;
        let b = [cipher];
        sout.write(&b).expect("write error");
    }
}
<|endoftext|>