<commit_before>use std::collections::HashMap;
use std::collections::LinkedList;
use std::str::FromStr;

use Term::*;

pub type Value = i32;
pub type ForthResult = Result<(), Error>;
type StackResult<T> = Result<T, Error>;

type Stack = LinkedList<Value>;
type Code = LinkedList<Term>;
type Definitions = HashMap<String, Code>;

pub struct Forth {
    code: Code,
    defs: Definitions,
    stack: Stack,
}

#[derive(Debug, PartialEq)]
pub enum Error {
    DivisionByZero,
    StackUnderflow,
    UnknownWord,
    InvalidWord,
}

#[derive(Debug, Clone)]
enum Term {
    Number(Value),
    Word(String),
    StartDefinition,
    EndDefinition,
}

impl FromStr for Term {
    type Err = ();

    fn from_str(s: &str) -> Result<Term, ()> {
        match s {
            ":" => Ok(StartDefinition),
            ";" => Ok(EndDefinition),
            _ => Err(()),
        }.or_else(|_| Value::from_str(s).map(Number))
            .or_else(|_| Ok(Word(s.to_ascii_lowercase())))
    }
}

impl Forth {
    pub fn new() -> Forth {
        Forth {
            code: LinkedList::new(),
            defs: HashMap::new(),
            stack: LinkedList::new(),
        }
    }

    pub fn stack(&self) -> Vec<Value> {
        self.stack.iter().cloned().collect()
    }

    pub fn eval(&mut self, input: &str) -> ForthResult {
        let mut new_code = Forth::into_code(input);
        self.code.append(&mut new_code);
        self.run()
    }

    fn run(&mut self) -> ForthResult {
        while let Some(term) = self.code.pop_front() {
            try!(self.step_term(term))
        }

        Forth::ok()
    }

    fn step_term(&mut self, term: Term) -> ForthResult {
        match term {
            Number(value) => self.push(value),
            Word(word) => self.step_word(word),
            StartDefinition => self.store_definition(),
            EndDefinition => Err(Error::InvalidWord),
        }
    }

    fn step_word(&mut self, word: String) -> ForthResult {
        self.defs
            .get(&word)
            .ok_or(Error::UnknownWord)
            .map(Clone::clone)
            .map(|mut code| self.code.append(&mut code))
            .or_else(|_| self.step_built_in(&word))
    }

    fn step_built_in(&mut self, word: &str) -> ForthResult {
        match word.as_ref() {
            "+" => self.bin_op(|(a, b)| Ok(a + b)),
            "-" => self.bin_op(|(a, b)| Ok(a - b)),
            "*" => self.bin_op(|(a, b)| Ok(a * b)),
            "/" => self.bin_op(|(a, b)| a.checked_div(b).ok_or(Error::DivisionByZero)),
            "dup" => self.pop().and_then(|a| self.push(a).and(self.push(a))),
            "drop" => self.pop().and(Forth::ok()),
            "swap" => self.pop_two()
                .and_then(|(a, b)| self.push(b).and(self.push(a))),
            "over" => self.pop_two()
                .and_then(|(a, b)| self.push(a).and(self.push(b)).and(self.push(a))),
            _ => Err(Error::UnknownWord),
        }
    }

    fn store_definition(&mut self) -> ForthResult {
        let mut def = LinkedList::new();

        loop {
            match self.code.pop_front() {
                Some(EndDefinition) => break,
                Some(term) => def.push_back(term),
                None => return Err(Error::InvalidWord),
            }
        }

        if let Some(Word(name)) = def.pop_front() {
            self.store_word(name, def)
        } else {
            Err(Error::InvalidWord)
        }
    }

    fn push(&mut self, value: Value) -> ForthResult {
        self.stack.push_back(value);
        Forth::ok()
    }

    fn pop(&mut self) -> StackResult<Value> {
        self.stack.pop_back().ok_or(Error::StackUnderflow)
    }

    fn pop_two(&mut self) -> StackResult<(Value, Value)> {
        self.pop().and_then(|b| self.pop().and_then(|a| Ok((a, b))))
    }

    fn bin_op<F>(&mut self, op: F) -> ForthResult
    where
        F: FnOnce((Value, Value)) -> StackResult<Value>,
    {
        self.pop_two()
            .and_then(op)
            .and_then(|value| self.push(value))
    }

    fn store_word(&mut self, name: String, code: Code) -> ForthResult {
        self.defs.insert(name, code);
        Forth::ok()
    }

    fn into_code(input: &str) -> LinkedList<Term> {
        input
            .split(|c: char| c.is_whitespace() || c.is_control())
            .map(Term::from_str)
            .filter(Result::is_ok)
            .map(Result::unwrap)
            .collect()
    }

    fn ok() -> ForthResult {
        Ok(())
    }
}
<commit_msg>forth: Remove unneeded `as_ref`<commit_after>use std::collections::HashMap;
use std::collections::LinkedList;
use std::str::FromStr;

use Term::*;

pub type Value = i32;
pub type ForthResult = Result<(), Error>;
type StackResult<T> = Result<T, Error>;

type Stack = LinkedList<Value>;
type Code = LinkedList<Term>;
type Definitions = HashMap<String, Code>;

pub struct Forth {
    code: Code,
    defs: Definitions,
    stack: Stack,
}

#[derive(Debug, PartialEq)]
pub enum Error {
    DivisionByZero,
    StackUnderflow,
    UnknownWord,
    InvalidWord,
}

#[derive(Debug, Clone)]
enum Term {
    Number(Value),
    Word(String),
    StartDefinition,
    EndDefinition,
}

impl FromStr for Term {
    type Err = ();

    fn from_str(s: &str) -> Result<Term, ()> {
        match s {
            ":" => Ok(StartDefinition),
            ";" => Ok(EndDefinition),
            _ => Err(()),
        }.or_else(|_| Value::from_str(s).map(Number))
            .or_else(|_| Ok(Word(s.to_ascii_lowercase())))
    }
}

impl Forth {
    pub fn new() -> Forth {
        Forth {
            code: LinkedList::new(),
            defs: HashMap::new(),
            stack: LinkedList::new(),
        }
    }

    pub fn stack(&self) -> Vec<Value> {
        self.stack.iter().cloned().collect()
    }

    pub fn eval(&mut self, input: &str) -> ForthResult {
        let mut new_code = Forth::into_code(input);
        self.code.append(&mut new_code);
        self.run()
    }

    fn run(&mut self) -> ForthResult {
        while let Some(term) = self.code.pop_front() {
            try!(self.step_term(term))
        }

        Forth::ok()
    }

    fn step_term(&mut self, term: Term) -> ForthResult {
        match term {
            Number(value) => self.push(value),
            Word(word) => self.step_word(word),
            StartDefinition => self.store_definition(),
            EndDefinition => Err(Error::InvalidWord),
        }
    }

    fn step_word(&mut self, word: String) -> ForthResult {
        self.defs
            .get(&word)
            .ok_or(Error::UnknownWord)
            .map(Clone::clone)
            .map(|mut code| self.code.append(&mut code))
            .or_else(|_| self.step_built_in(&word))
    }

    fn step_built_in(&mut self, word: &str) -> ForthResult {
        match word {
            "+" => self.bin_op(|(a, b)| Ok(a + b)),
            "-" => self.bin_op(|(a, b)| Ok(a - b)),
            "*" => self.bin_op(|(a, b)| Ok(a * b)),
            "/" => self.bin_op(|(a, b)| a.checked_div(b).ok_or(Error::DivisionByZero)),
            "dup" => self.pop().and_then(|a| self.push(a).and(self.push(a))),
            "drop" => self.pop().and(Forth::ok()),
            "swap" => self.pop_two()
                .and_then(|(a, b)| self.push(b).and(self.push(a))),
            "over" => self.pop_two()
                .and_then(|(a, b)| self.push(a).and(self.push(b)).and(self.push(a))),
            _ => Err(Error::UnknownWord),
        }
    }

    fn store_definition(&mut self) -> ForthResult {
        let mut def = LinkedList::new();

        loop {
            match self.code.pop_front() {
                Some(EndDefinition) => break,
                Some(term) => def.push_back(term),
                None => return Err(Error::InvalidWord),
            }
        }

        if let Some(Word(name)) = def.pop_front() {
            self.store_word(name, def)
        } else {
            Err(Error::InvalidWord)
        }
    }

    fn push(&mut self, value: Value) -> ForthResult {
        self.stack.push_back(value);
        Forth::ok()
    }

    fn pop(&mut self) -> StackResult<Value> {
        self.stack.pop_back().ok_or(Error::StackUnderflow)
    }

    fn pop_two(&mut self) -> StackResult<(Value, Value)> {
        self.pop().and_then(|b| self.pop().and_then(|a| Ok((a, b))))
    }

    fn bin_op<F>(&mut self, op: F) -> ForthResult
    where
        F: FnOnce((Value, Value)) -> StackResult<Value>,
    {
        self.pop_two()
            .and_then(op)
            .and_then(|value| self.push(value))
    }

    fn store_word(&mut self, name: String, code: Code) -> ForthResult {
        self.defs.insert(name, code);
        Forth::ok()
    }

    fn into_code(input: &str) -> LinkedList<Term> {
        input
            .split(|c: char| c.is_whitespace() || c.is_control())
            .map(Term::from_str)
            .filter(Result::is_ok)
            .map(Result::unwrap)
            .collect()
    }

    fn ok() -> ForthResult {
        Ok(())
    }
}
<|endoftext|>


<commit_before>//! Management of the directory layout of a build
//!
//! The directory layout is a little tricky at times, hence a separate file to
//! house this logic. The current layout looks like this:
//!
//! ```text
//! # This is the root directory for all output, the top-level package
//! # places all of its output here.
//! target/
//!
//!     # Cache of `rustc -Vv` output for performance.
//!     .rustc-info.json
//!
//!     # All final artifacts are linked into this directory from `deps`.
//!     # Note that named profiles will soon be included as separate directories
//!     # here. They have a restricted format, similar to Rust identifiers, so
//!     # Cargo-specific directories added in the future should use some prefix
//!     # like `.` to avoid name collisions.
//!     debug/  # or release/
//!
//!         # File used to lock the directory to prevent multiple cargo processes
//!         # from using it at the same time.
//!         .cargo-lock
//!
//!         # Hidden directory that holds all of the fingerprint files for all
//!         # packages
//!         .fingerprint/
//!             # Each package is in a separate directory.
//!             # Note that different target kinds have different filename prefixes.
//!             $pkgname-$META/
//!                 # Set of source filenames for this package.
//!                 dep-lib-$targetname
//!                 # Timestamp when this package was last built.
//!                 invoked.timestamp
//!                 # The fingerprint hash.
//!                 lib-$targetname
//!                 # Detailed information used for logging the reason why
//!                 # something is being recompiled.
//!                 lib-$targetname.json
//!                 # The console output from the compiler. This is cached
//!                 # so that warnings can be redisplayed for "fresh" units.
//!                 output-lib-$targetname
//!
//!         # This is the root directory for all rustc artifacts except build
//!         # scripts, examples, and test and bench executables. Almost every
//!         # artifact should have a metadata hash added to its filename to
//!         # prevent collisions. One notable exception is dynamic libraries.
//!         deps/
//!
//!         # Root directory for all compiled examples.
//!         examples/
//!
//!         # Directory used to store incremental data for the compiler (when
//!         # incremental is enabled.
//!         incremental/
//!
//!         # This is the location at which the output of all custom build
//!         # commands are rooted.
//!         build/
//!
//!             # Each package gets its own directory where its build script and
//!             # script output are placed
//!             $pkgname-$META/    # For the build script itself.
//!                 # The build script executable (name may be changed by user).
//!                 build-script-build-$META
//!                 # Hard link to build-script-build-$META.
//!                 build-script-build
//!                 # Dependency information generated by rustc.
//!                 build-script-build-$META.d
//!                 # Debug information, depending on platform and profile
//!                 # settings.
//!                 <debug symbols>
//!
//!             # The package shows up twice with two different metadata hashes.
//!             $pkgname-$META/  # For the output of the build script.
//!                 # Timestamp when the build script was last executed.
//!                 invoked.timestamp
//!                 # Directory where script can output files ($OUT_DIR).
//!                 out/
//!                 # Output from the build script.
//!                 output
//!                 # Path to `out`, used to help when the target directory is
//!                 # moved.
//!                 root-output
//!                 # Stderr output from the build script.
//!                 stderr
//!
//!     # Output from rustdoc
//!     doc/
//!
//!     # Used by `cargo package` and `cargo publish` to build a `.crate` file.
//!     package/
//!
//!     # Experimental feature for generated build scripts.
//!     .metabuild/
//! ```
//!
//! When cross-compiling, the layout is the same, except it appears in
//! `target/$TRIPLE`.

use crate::core::compiler::CompileTarget;
use crate::core::Workspace;
use crate::util::paths;
use crate::util::{CargoResult, FileLock};
use std::path::{Path, PathBuf};

/// Contains the paths of all target output locations.
///
/// See module docs for more information.
pub struct Layout {
    /// The root directory: `/path/to/target`.
    /// If cross compiling: `/path/to/target/$TRIPLE`.
    root: PathBuf,
    /// The final artifact destination: `$root/debug` (or `release`).
    dest: PathBuf,
    /// The directory with rustc artifacts: `$dest/deps`
    deps: PathBuf,
    /// The directory for build scripts: `$dest/build`
    build: PathBuf,
    /// The directory for incremental files: `$dest/incremental`
    incremental: PathBuf,
    /// The directory for fingerprints: `$dest/.fingerprint`
    fingerprint: PathBuf,
    /// The directory for examples: `$dest/examples`
    examples: PathBuf,
    /// The directory for rustdoc output: `$root/doc`
    doc: PathBuf,
    /// The lockfile for a build (`.cargo-lock`). Will be unlocked when this
    /// struct is `drop`ped.
    _lock: FileLock,
}

impl Layout {
    /// Calculate the paths for build output, lock the build directory, and return as a Layout.
    ///
    /// This function will block if the directory is already locked.
    ///
    /// `dest` should be the final artifact directory name. Currently either
    /// "debug" or "release".
    pub fn new(
        ws: &Workspace<'_>,
        target: Option<CompileTarget>,
        dest: &str,
    ) -> CargoResult<Layout> {
        let mut root = ws.target_dir();
        if let Some(target) = target {
            root.push(target.short_name());
        }
        let dest = root.join(dest);
        // If the root directory doesn't already exist go ahead and create it
        // here. Use this opportunity to exclude it from backups as well if the
        // system supports it since this is a freshly created folder.
        if !dest.as_path_unlocked().exists() {
            dest.create_dir()?;
            exclude_from_backups(dest.as_path_unlocked());
        }

        // For now we don't do any more finer-grained locking on the artifact
        // directory, so just lock the entire thing for the duration of this
        // compile.
        let lock = dest.open_rw(".cargo-lock", ws.config(), "build directory")?;
        let root = root.into_path_unlocked();
        let dest = dest.into_path_unlocked();

        Ok(Layout {
            deps: dest.join("deps"),
            build: dest.join("build"),
            incremental: dest.join("incremental"),
            fingerprint: dest.join(".fingerprint"),
            examples: dest.join("examples"),
            doc: root.join("doc"),
            root,
            dest,
            _lock: lock,
        })
    }

    /// Makes sure all directories stored in the Layout exist on the filesystem.
    pub fn prepare(&mut self) -> CargoResult<()> {
        paths::create_dir_all(&self.deps)?;
        paths::create_dir_all(&self.incremental)?;
        paths::create_dir_all(&self.fingerprint)?;
        paths::create_dir_all(&self.examples)?;
        paths::create_dir_all(&self.build)?;

        Ok(())
    }

    /// Fetch the destination path for final artifacts  (`/…/target/debug`).
    pub fn dest(&self) -> &Path {
        &self.dest
    }
    /// Fetch the deps path.
    pub fn deps(&self) -> &Path {
        &self.deps
    }
    /// Fetch the examples path.
    pub fn examples(&self) -> &Path {
        &self.examples
    }
    /// Fetch the doc path.
    pub fn doc(&self) -> &Path {
        &self.doc
    }
    /// Fetch the root path (`/…/target`).
    pub fn root(&self) -> &Path {
        &self.root
    }
    /// Fetch the incremental path.
    pub fn incremental(&self) -> &Path {
        &self.incremental
    }
    /// Fetch the fingerprint path.
    pub fn fingerprint(&self) -> &Path {
        &self.fingerprint
    }
    /// Fetch the build script path.
    pub fn build(&self) -> &Path {
        &self.build
    }
}

/// Marks the directory as excluded from archives/backups.
///
/// This is recommended to prevent derived/temporary files from bloating backups. There are two
/// mechanisms used to achieve this right now:
///
/// * A dedicated resource property excluding from Time Machine backups on macOS
/// * CACHEDIR.TAG files supported by various tools in a platform-independent way
fn exclude_from_backups(path: &Path) {
    exclude_from_time_machine(path);
    let _ = std::fs::write(
        path.join("CACHEDIR.TAG"),
        "Signature: 8a477f597d28d172789f06886806bc55
# This file is a cache directory tag created by cargo.
# For information about cache directory tags see https://bford.info/cachedir/",
    );
    // Similarly to exclude_from_time_machine() we ignore errors here as it's an optional feature.
}

#[cfg(not(target_os = "macos"))]
fn exclude_from_time_machine(path: &Path) {}

#[cfg(target_os = "macos")]
/// Marks files or directories as excluded from Time Machine on macOS
fn exclude_from_time_machine(path: &Path) {
    use core_foundation::base::TCFType;
    use core_foundation::{number, string, url};
    use std::ptr;

    // For compatibility with 10.7 a string is used instead of global kCFURLIsExcludedFromBackupKey
    let is_excluded_key: Result<string::CFString, _> = "NSURLIsExcludedFromBackupKey".parse();
    let path = url::CFURL::from_path(path, false);
    if let (Some(path), Ok(is_excluded_key)) = (path, is_excluded_key) {
        unsafe {
            url::CFURLSetResourcePropertyForKey(
                path.as_concrete_TypeRef(),
                is_excluded_key.as_concrete_TypeRef(),
                number::kCFBooleanTrue as *const _,
                ptr::null_mut(),
            );
        }
    }
    // Errors are ignored, since it's an optional feature and failure
    // doesn't prevent Cargo from working
}
<commit_msg>Revert one unintentional change<commit_after>//! Management of the directory layout of a build
//!
//! The directory layout is a little tricky at times, hence a separate file to
//! house this logic. The current layout looks like this:
//!
//! ```text
//! # This is the root directory for all output, the top-level package
//! # places all of its output here.
//! target/
//!
//!     # Cache of `rustc -Vv` output for performance.
//!     .rustc-info.json
//!
//!     # All final artifacts are linked into this directory from `deps`.
//!     # Note that named profiles will soon be included as separate directories
//!     # here. They have a restricted format, similar to Rust identifiers, so
//!     # Cargo-specific directories added in the future should use some prefix
//!     # like `.` to avoid name collisions.
//!     debug/  # or release/
//!
//!         # File used to lock the directory to prevent multiple cargo processes
//!         # from using it at the same time.
//!         .cargo-lock
//!
//!         # Hidden directory that holds all of the fingerprint files for all
//!         # packages
//!         .fingerprint/
//!             # Each package is in a separate directory.
//!             # Note that different target kinds have different filename prefixes.
//!             $pkgname-$META/
//!                 # Set of source filenames for this package.
//!                 dep-lib-$targetname
//!                 # Timestamp when this package was last built.
//!                 invoked.timestamp
//!                 # The fingerprint hash.
//!                 lib-$targetname
//!                 # Detailed information used for logging the reason why
//!                 # something is being recompiled.
//!                 lib-$targetname.json
//!                 # The console output from the compiler. This is cached
//!                 # so that warnings can be redisplayed for "fresh" units.
//!                 output-lib-$targetname
//!
//!         # This is the root directory for all rustc artifacts except build
//!         # scripts, examples, and test and bench executables. Almost every
//!         # artifact should have a metadata hash added to its filename to
//!         # prevent collisions. One notable exception is dynamic libraries.
//!         deps/
//!
//!         # Root directory for all compiled examples.
//!         examples/
//!
//!         # Directory used to store incremental data for the compiler (when
//!         # incremental is enabled.
//!         incremental/
//!
//!         # This is the location at which the output of all custom build
//!         # commands are rooted.
//!         build/
//!
//!             # Each package gets its own directory where its build script and
//!             # script output are placed
//!             $pkgname-$META/    # For the build script itself.
//!                 # The build script executable (name may be changed by user).
//!                 build-script-build-$META
//!                 # Hard link to build-script-build-$META.
//!                 build-script-build
//!                 # Dependency information generated by rustc.
//!                 build-script-build-$META.d
//!                 # Debug information, depending on platform and profile
//!                 # settings.
//!                 <debug symbols>
//!
//!             # The package shows up twice with two different metadata hashes.
//!             $pkgname-$META/  # For the output of the build script.
//!                 # Timestamp when the build script was last executed.
//!                 invoked.timestamp
//!                 # Directory where script can output files ($OUT_DIR).
//!                 out/
//!                 # Output from the build script.
//!                 output
//!                 # Path to `out`, used to help when the target directory is
//!                 # moved.
//!                 root-output
//!                 # Stderr output from the build script.
//!                 stderr
//!
//!     # Output from rustdoc
//!     doc/
//!
//!     # Used by `cargo package` and `cargo publish` to build a `.crate` file.
//!     package/
//!
//!     # Experimental feature for generated build scripts.
//!     .metabuild/
//! ```
//!
//! When cross-compiling, the layout is the same, except it appears in
//! `target/$TRIPLE`.

use crate::core::compiler::CompileTarget;
use crate::core::Workspace;
use crate::util::paths;
use crate::util::{CargoResult, FileLock};
use std::path::{Path, PathBuf};

/// Contains the paths of all target output locations.
///
/// See module docs for more information.
pub struct Layout {
    /// The root directory: `/path/to/target`.
    /// If cross compiling: `/path/to/target/$TRIPLE`.
    root: PathBuf,
    /// The final artifact destination: `$root/debug` (or `release`).
    dest: PathBuf,
    /// The directory with rustc artifacts: `$dest/deps`
    deps: PathBuf,
    /// The directory for build scripts: `$dest/build`
    build: PathBuf,
    /// The directory for incremental files: `$dest/incremental`
    incremental: PathBuf,
    /// The directory for fingerprints: `$dest/.fingerprint`
    fingerprint: PathBuf,
    /// The directory for examples: `$dest/examples`
    examples: PathBuf,
    /// The directory for rustdoc output: `$root/doc`
    doc: PathBuf,
    /// The lockfile for a build (`.cargo-lock`). Will be unlocked when this
    /// struct is `drop`ped.
    _lock: FileLock,
}

impl Layout {
    /// Calculate the paths for build output, lock the build directory, and return as a Layout.
    ///
    /// This function will block if the directory is already locked.
    ///
    /// `dest` should be the final artifact directory name. Currently either
    /// "debug" or "release".
    pub fn new(
        ws: &Workspace<'_>,
        target: Option<CompileTarget>,
        dest: &str,
    ) -> CargoResult<Layout> {
        let mut root = ws.target_dir();
        if let Some(target) = target {
            root.push(target.short_name());
        }
        let dest = root.join(dest);
        // If the root directory doesn't already exist go ahead and create it
        // here. Use this opportunity to exclude it from backups as well if the
        // system supports it since this is a freshly created folder.
        if !dest.as_path_unlocked().exists() {
            dest.create_dir()?;
            exclude_from_backups(dest.as_path_unlocked());
        }

        // For now we don't do any more finer-grained locking on the artifact
        // directory, so just lock the entire thing for the duration of this
        // compile.
        let lock = dest.open_rw(".cargo-lock", ws.config(), "build directory")?;
        let root = root.into_path_unlocked();
        let dest = dest.into_path_unlocked();

        Ok(Layout {
            deps: dest.join("deps"),
            build: dest.join("build"),
            incremental: dest.join("incremental"),
            fingerprint: dest.join(".fingerprint"),
            examples: dest.join("examples"),
            doc: root.join("doc"),
            root,
            dest,
            _lock: lock,
        })
    }

    /// Makes sure all directories stored in the Layout exist on the filesystem.
    pub fn prepare(&mut self) -> CargoResult<()> {
        paths::create_dir_all(&self.deps)?;
        paths::create_dir_all(&self.incremental)?;
        paths::create_dir_all(&self.fingerprint)?;
        paths::create_dir_all(&self.examples)?;
        paths::create_dir_all(&self.build)?;

        Ok(())
    }

    /// Fetch the destination path for final artifacts  (`/…/target/debug`).
    pub fn dest(&self) -> &Path {
        &self.dest
    }
    /// Fetch the deps path.
    pub fn deps(&self) -> &Path {
        &self.deps
    }
    /// Fetch the examples path.
    pub fn examples(&self) -> &Path {
        &self.examples
    }
    /// Fetch the doc path.
    pub fn doc(&self) -> &Path {
        &self.doc
    }
    /// Fetch the root path (`/…/target`).
    pub fn root(&self) -> &Path {
        &self.root
    }
    /// Fetch the incremental path.
    pub fn incremental(&self) -> &Path {
        &self.incremental
    }
    /// Fetch the fingerprint path.
    pub fn fingerprint(&self) -> &Path {
        &self.fingerprint
    }
    /// Fetch the build script path.
    pub fn build(&self) -> &Path {
        &self.build
    }
}

/// Marks the directory as excluded from archives/backups.
///
/// This is recommended to prevent derived/temporary files from bloating backups. There are two
/// mechanisms used to achieve this right now:
///
/// * A dedicated resource property excluding from Time Machine backups on macOS
/// * CACHEDIR.TAG files supported by various tools in a platform-independent way
fn exclude_from_backups(path: &Path) {
    exclude_from_time_machine(path);
    let _ = std::fs::write(
        path.join("CACHEDIR.TAG"),
        "Signature: 8a477f597d28d172789f06886806bc55
# This file is a cache directory tag created by cargo.
# For information about cache directory tags see https://bford.info/cachedir/",
    );
    // Similarly to exclude_from_time_machine() we ignore errors here as it's an optional feature.
}

#[cfg(not(target_os = "macos"))]
fn exclude_from_time_machine(_: &Path) {}

#[cfg(target_os = "macos")]
/// Marks files or directories as excluded from Time Machine on macOS
fn exclude_from_time_machine(path: &Path) {
    use core_foundation::base::TCFType;
    use core_foundation::{number, string, url};
    use std::ptr;

    // For compatibility with 10.7 a string is used instead of global kCFURLIsExcludedFromBackupKey
    let is_excluded_key: Result<string::CFString, _> = "NSURLIsExcludedFromBackupKey".parse();
    let path = url::CFURL::from_path(path, false);
    if let (Some(path), Ok(is_excluded_key)) = (path, is_excluded_key) {
        unsafe {
            url::CFURLSetResourcePropertyForKey(
                path.as_concrete_TypeRef(),
                is_excluded_key.as_concrete_TypeRef(),
                number::kCFBooleanTrue as *const _,
                ptr::null_mut(),
            );
        }
    }
    // Errors are ignored, since it's an optional feature and failure
    // doesn't prevent Cargo from working
}
<|endoftext|>


<commit_before>//! Management of the directory layout of a build
//!
//! The directory layout is a little tricky at times, hence a separate file to
//! house this logic. The current layout looks like this:
//!
//! ```ignore
//! # This is the root directory for all output, the top-level package
//! # places all of its output here.
//! target/
//!
//!     # This is the root directory for all output of *dependencies*
//!     deps/
//!
//!     # Root directory for all compiled examples
//!     examples/
//!
//!     # This is the location at which the output of all custom build
//!     # commands are rooted
//!     build/
//!
//!         # Each package gets its own directory where its build script and
//!         # script output are placed
//!         $pkg1/
//!         $pkg2/
//!         $pkg3/
//!
//!             # Each directory package has a `out` directory where output
//!             # is placed.
//!             out/
//!
//!     # This is the location at which the output of all old custom build
//!     # commands are rooted
//!     native/
//!
//!         # Each package gets its own directory for where its output is
//!         # placed. We can't track exactly what's getting put in here, so
//!         # we just assume that all relevant output is in these
//!         # directories.
//!         $pkg1/
//!         $pkg2/
//!         $pkg3/
//!
//!     # Directory used to store incremental data for the compiler (when
//!     # incremental is enabled.
//!     incremental/
//!
//!     # Hidden directory that holds all of the fingerprint files for all
//!     # packages
//!     .fingerprint/
//! ```

use std::fs;
use std::io;
use std::path::{Path, PathBuf};

use core::Workspace;
use util::{CargoResult, Config, FileLock, Filesystem};

/// Contains the paths of all target output locations.
///
/// See module docs for more information.
pub struct Layout {
    root: PathBuf,
    deps: PathBuf,
    native: PathBuf,
    build: PathBuf,
    incremental: PathBuf,
    fingerprint: PathBuf,
    examples: PathBuf,
    /// The lockfile for a build, will be unlocked when this struct is `drop`ped.
    _lock: FileLock,
}

pub fn is_bad_artifact_name(name: &str) -> bool {
    ["deps", "examples", "build", "native", "incremental"]
        .iter()
        .any(|&reserved| reserved == name)
}

impl Layout {
    /// Calculate the paths for build output, lock the build directory, and return as a Layout.
    ///
    /// This function will block if the directory is already locked.
    ///
    /// Differs from `at` in that this calculates the root path from the workspace target directory,
    /// adding the target triple and the profile (debug, release, ...).
    pub fn new(ws: &Workspace, triple: Option<&str>, dest: &str) -> CargoResult<Layout> {
        let mut path = ws.target_dir();
        // Flexible target specifications often point at filenames, so interpret
        // the target triple as a Path and then just use the file stem as the
        // component for the directory name.
        if let Some(triple) = triple {
            path.push(Path::new(triple)
                .file_stem()
                .ok_or_else(|| format_err!("invalid target"))?);
        }
        path.push(dest);
        Layout::at(ws.config(), path)
    }

    /// Calculate the paths for build output, lock the build directory, and return as a Layout.
    ///
    /// This function will block if the directory is already locked.
    pub fn at(config: &Config, root: Filesystem) -> CargoResult<Layout> {
        // For now we don't do any more finer-grained locking on the artifact
        // directory, so just lock the entire thing for the duration of this
        // compile.
        let lock = root.open_rw(".cargo-lock", config, "build directory")?;
        let root = root.into_path_unlocked();

        Ok(Layout {
            deps: root.join("deps"),
            native: root.join("native"),
            build: root.join("build"),
            incremental: root.join("incremental"),
            fingerprint: root.join(".fingerprint"),
            examples: root.join("examples"),
            root,
            _lock: lock,
        })
    }

    #[cfg(not(target_os = "macos"))]
    fn exclude_from_backups(&self, _: &Path) {}

    #[cfg(target_os = "macos")]
    /// Marks files or directories as excluded from Time Machine on macOS
    ///
    /// This is recommended to prevent derived/temporary files from bloating backups.
    fn exclude_from_backups(&self, path: &Path) {
        use std::ptr;
        use core_foundation::{number, string, url};
        use core_foundation::base::TCFType;

        // For compatibility with 10.7 a string is used instead of global kCFURLIsExcludedFromBackupKey
        let is_excluded_key: Result<string::CFString, _> = "NSURLIsExcludedFromBackupKey".parse();
        match (url::CFURL::from_path(path, false), is_excluded_key) {
            (Some(path), Ok(is_excluded_key)) => unsafe {
                url::CFURLSetResourcePropertyForKey(
                    path.as_concrete_TypeRef(),
                    is_excluded_key.as_concrete_TypeRef(),
                    number::kCFBooleanTrue as *const _,
                    ptr::null_mut(),
                );
            },
            // Errors are ignored, since it's an optional feature and failure
            // doesn't prevent Cargo from working
            _ => {}
        }
    }

    /// Make sure all directories stored in the Layout exist on the filesystem.
    pub fn prepare(&mut self) -> io::Result<()> {
        if fs::metadata(&self.root).is_err() {
            fs::create_dir_all(&self.root)?;
        }

        self.exclude_from_backups(&self.root);

        mkdir(&self.deps)?;
        mkdir(&self.native)?;
        mkdir(&self.incremental)?;
        mkdir(&self.fingerprint)?;
        mkdir(&self.examples)?;
        mkdir(&self.build)?;

        return Ok(());

        fn mkdir(dir: &Path) -> io::Result<()> {
            if fs::metadata(&dir).is_err() {
                fs::create_dir(dir)?;
            }
            Ok(())
        }
    }

    /// Fetch the root path.
    pub fn dest(&self) -> &Path {
        &self.root
    }
    /// Fetch the deps path.
    pub fn deps(&self) -> &Path {
        &self.deps
    }
    /// Fetch the examples path.
    pub fn examples(&self) -> &Path {
        &self.examples
    }
    /// Fetch the root path.
    pub fn root(&self) -> &Path {
        &self.root
    }
    /// Fetch the incremental path.
    pub fn incremental(&self) -> &Path {
        &self.incremental
    }
    /// Fetch the fingerprint path.
    pub fn fingerprint(&self) -> &Path {
        &self.fingerprint
    }
    /// Fetch the build path.
    pub fn build(&self) -> &Path {
        &self.build
    }
}
<commit_msg>Resolve a single_match lint warning<commit_after>//! Management of the directory layout of a build
//!
//! The directory layout is a little tricky at times, hence a separate file to
//! house this logic. The current layout looks like this:
//!
//! ```ignore
//! # This is the root directory for all output, the top-level package
//! # places all of its output here.
//! target/
//!
//!     # This is the root directory for all output of *dependencies*
//!     deps/
//!
//!     # Root directory for all compiled examples
//!     examples/
//!
//!     # This is the location at which the output of all custom build
//!     # commands are rooted
//!     build/
//!
//!         # Each package gets its own directory where its build script and
//!         # script output are placed
//!         $pkg1/
//!         $pkg2/
//!         $pkg3/
//!
//!             # Each directory package has a `out` directory where output
//!             # is placed.
//!             out/
//!
//!     # This is the location at which the output of all old custom build
//!     # commands are rooted
//!     native/
//!
//!         # Each package gets its own directory for where its output is
//!         # placed. We can't track exactly what's getting put in here, so
//!         # we just assume that all relevant output is in these
//!         # directories.
//!         $pkg1/
//!         $pkg2/
//!         $pkg3/
//!
//!     # Directory used to store incremental data for the compiler (when
//!     # incremental is enabled.
//!     incremental/
//!
//!     # Hidden directory that holds all of the fingerprint files for all
//!     # packages
//!     .fingerprint/
//! ```

use std::fs;
use std::io;
use std::path::{Path, PathBuf};

use core::Workspace;
use util::{CargoResult, Config, FileLock, Filesystem};

/// Contains the paths of all target output locations.
///
/// See module docs for more information.
pub struct Layout {
    root: PathBuf,
    deps: PathBuf,
    native: PathBuf,
    build: PathBuf,
    incremental: PathBuf,
    fingerprint: PathBuf,
    examples: PathBuf,
    /// The lockfile for a build, will be unlocked when this struct is `drop`ped.
    _lock: FileLock,
}

pub fn is_bad_artifact_name(name: &str) -> bool {
    ["deps", "examples", "build", "native", "incremental"]
        .iter()
        .any(|&reserved| reserved == name)
}

impl Layout {
    /// Calculate the paths for build output, lock the build directory, and return as a Layout.
    ///
    /// This function will block if the directory is already locked.
    ///
    /// Differs from `at` in that this calculates the root path from the workspace target directory,
    /// adding the target triple and the profile (debug, release, ...).
    pub fn new(ws: &Workspace, triple: Option<&str>, dest: &str) -> CargoResult<Layout> {
        let mut path = ws.target_dir();
        // Flexible target specifications often point at filenames, so interpret
        // the target triple as a Path and then just use the file stem as the
        // component for the directory name.
        if let Some(triple) = triple {
            path.push(Path::new(triple)
                .file_stem()
                .ok_or_else(|| format_err!("invalid target"))?);
        }
        path.push(dest);
        Layout::at(ws.config(), path)
    }

    /// Calculate the paths for build output, lock the build directory, and return as a Layout.
    ///
    /// This function will block if the directory is already locked.
    pub fn at(config: &Config, root: Filesystem) -> CargoResult<Layout> {
        // For now we don't do any more finer-grained locking on the artifact
        // directory, so just lock the entire thing for the duration of this
        // compile.
        let lock = root.open_rw(".cargo-lock", config, "build directory")?;
        let root = root.into_path_unlocked();

        Ok(Layout {
            deps: root.join("deps"),
            native: root.join("native"),
            build: root.join("build"),
            incremental: root.join("incremental"),
            fingerprint: root.join(".fingerprint"),
            examples: root.join("examples"),
            root,
            _lock: lock,
        })
    }

    #[cfg(not(target_os = "macos"))]
    fn exclude_from_backups(&self, _: &Path) {}

    #[cfg(target_os = "macos")]
    /// Marks files or directories as excluded from Time Machine on macOS
    ///
    /// This is recommended to prevent derived/temporary files from bloating backups.
    fn exclude_from_backups(&self, path: &Path) {
        use std::ptr;
        use core_foundation::{number, string, url};
        use core_foundation::base::TCFType;

        // For compatibility with 10.7 a string is used instead of global kCFURLIsExcludedFromBackupKey
        let is_excluded_key: Result<string::CFString, _> = "NSURLIsExcludedFromBackupKey".parse();
        let path = url::CFURL::from_path(path, false);
        if let (Some(path), Ok(is_excluded_key)) = (path, is_excluded_key) {
            unsafe {
                url::CFURLSetResourcePropertyForKey(
                    path.as_concrete_TypeRef(),
                    is_excluded_key.as_concrete_TypeRef(),
                    number::kCFBooleanTrue as *const _,
                    ptr::null_mut(),
                );
            }
        }
        // Errors are ignored, since it's an optional feature and failure
        // doesn't prevent Cargo from working
    }

    /// Make sure all directories stored in the Layout exist on the filesystem.
    pub fn prepare(&mut self) -> io::Result<()> {
        if fs::metadata(&self.root).is_err() {
            fs::create_dir_all(&self.root)?;
        }

        self.exclude_from_backups(&self.root);

        mkdir(&self.deps)?;
        mkdir(&self.native)?;
        mkdir(&self.incremental)?;
        mkdir(&self.fingerprint)?;
        mkdir(&self.examples)?;
        mkdir(&self.build)?;

        return Ok(());

        fn mkdir(dir: &Path) -> io::Result<()> {
            if fs::metadata(&dir).is_err() {
                fs::create_dir(dir)?;
            }
            Ok(())
        }
    }

    /// Fetch the root path.
    pub fn dest(&self) -> &Path {
        &self.root
    }
    /// Fetch the deps path.
    pub fn deps(&self) -> &Path {
        &self.deps
    }
    /// Fetch the examples path.
    pub fn examples(&self) -> &Path {
        &self.examples
    }
    /// Fetch the root path.
    pub fn root(&self) -> &Path {
        &self.root
    }
    /// Fetch the incremental path.
    pub fn incremental(&self) -> &Path {
        &self.incremental
    }
    /// Fetch the fingerprint path.
    pub fn fingerprint(&self) -> &Path {
        &self.fingerprint
    }
    /// Fetch the build path.
    pub fn build(&self) -> &Path {
        &self.build
    }
}
<|endoftext|>


<commit_before>use std::{
    cell::{Cell, RefCell},
    marker::PhantomData,
    mem::{align_of, size_of},
    rc::Rc,
};

use crate::common::util::{any_as_bytes, Pod};

use failure::Error;

// https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#limits-maxUniformBufferRange
const DYNAMIC_UNIFORM_BUFFER_SIZE: wgpu::BufferAddress = 16384;

// https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#limits-minUniformBufferOffsetAlignment
pub const DYNAMIC_UNIFORM_BUFFER_ALIGNMENT: usize = 256;

/// A handle to a dynamic uniform buffer on the GPU.
///
/// Allows allocation and updating of individual blocks of memory.
pub struct DynamicUniformBuffer<'a, T>
where
    T: Pod,
{
    // keeps track of how many blocks are allocated so we know whether we can
    // clear the buffer or not
    _rc: RefCell<Rc<()>>,

    // represents the data in the buffer, which we don't actually own
    _phantom: PhantomData<&'a [T]>,

    inner: wgpu::Buffer,
    allocated: Cell<wgpu::BufferSize>,
    update_buf: Vec<u8>,
}

impl<'a, T> DynamicUniformBuffer<'a, T>
where
    T: Pod,
{
    pub fn new<'b>(device: &'b wgpu::Device) -> DynamicUniformBuffer<'a, T> {
        // TODO: is this something we can enforce at compile time?
        assert!(align_of::<T>() % DYNAMIC_UNIFORM_BUFFER_ALIGNMENT == 0);

        let inner = device.create_buffer(&wgpu::BufferDescriptor {
            label: Some("dynamic uniform buffer"),
            size: DYNAMIC_UNIFORM_BUFFER_SIZE,
            usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
            mapped_at_creation: false,
        });

        let mut update_buf = Vec::with_capacity(DYNAMIC_UNIFORM_BUFFER_SIZE as usize);
        update_buf.resize(DYNAMIC_UNIFORM_BUFFER_SIZE as usize, 0);

        DynamicUniformBuffer {
            _rc: RefCell::new(Rc::new(())),
            _phantom: PhantomData,
            inner,
            allocated: Cell::new(wgpu::BufferSize(0)),
            update_buf,
        }
    }

    pub fn block_size(&self) -> wgpu::BufferSize {
        wgpu::BufferSize((DYNAMIC_UNIFORM_BUFFER_ALIGNMENT.max(size_of::<T>())) as u64)
    }

    /// Allocates a block of memory in this dynamic uniform buffer with the
    /// specified initial value.
    #[must_use]
    pub fn allocate(&mut self, val: T) -> DynamicUniformBufferBlock<'a, T> {
        trace!("Allocating dynamic uniform block");
        let allocated = self.allocated.get().0;
        let size = self.block_size().0;
        if allocated + size > DYNAMIC_UNIFORM_BUFFER_SIZE {
            panic!(
                "Not enough space to allocate {} bytes in dynamic uniform buffer",
                size
            );
        }

        let addr = allocated;
        self.allocated.set(wgpu::BufferSize(allocated + size));

        let block = DynamicUniformBufferBlock {
            _rc: self._rc.borrow().clone(),
            _phantom: PhantomData,
            addr,
        };

        self.write_block(&block, val);
        block
    }

    pub fn write_block(&mut self, block: &DynamicUniformBufferBlock<'a, T>, val: T) {
        let start = block.addr as usize;
        let end = start + self.block_size().0 as usize;
        let mut slice = &mut self.update_buf[start..end];
        slice.copy_from_slice(unsafe { any_as_bytes(&val) });
    }

    /// Removes all allocations from the underlying buffer.
    ///
    /// Returns an error if the buffer is currently mapped or there are
    /// outstanding allocated blocks.
    pub fn clear(&self) -> Result<(), Error> {
        let mut out = self._rc.replace(Rc::new(()));
        match Rc::try_unwrap(out) {
            // no outstanding blocks
            Ok(()) => {
                self.allocated.set(wgpu::BufferSize(0));
                Ok(())
            }
            Err(rc) => {
                let _ = self._rc.replace(rc);
                bail!("Can't clear uniform buffer: there are outstanding references to allocated blocks.");
            }
        }
    }

    pub fn flush(&self, queue: &wgpu::Queue) {
        queue.write_buffer(&self.inner, 0, &self.update_buf);
    }

    pub fn buffer(&self) -> &wgpu::Buffer {
        &self.inner
    }
}

/// An address into a dynamic uniform buffer.
#[derive(Debug)]
pub struct DynamicUniformBufferBlock<'a, T> {
    _rc: Rc<()>,
    _phantom: PhantomData<&'a T>,

    addr: wgpu::BufferAddress,
}

impl<'a, T> DynamicUniformBufferBlock<'a, T> {
    pub fn offset(&self) -> wgpu::DynamicOffset {
        self.addr as wgpu::DynamicOffset
    }
}
<commit_msg>Raise DynamicUniformBuffer size limit<commit_after>use std::{
    cell::{Cell, RefCell},
    marker::PhantomData,
    mem::{align_of, size_of},
    rc::Rc,
};

use crate::common::util::{any_as_bytes, Pod};

use failure::Error;

// minimum limit is 16384:
// https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#limits-maxUniformBufferRange
// but https://vulkan.gpuinfo.org/displaydevicelimit.php?name=maxUniformBufferRange&platform=windows indicates
// that a limit of 65536 or higher is more common
const DYNAMIC_UNIFORM_BUFFER_SIZE: wgpu::BufferAddress = 65536;

// https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#limits-minUniformBufferOffsetAlignment
pub const DYNAMIC_UNIFORM_BUFFER_ALIGNMENT: usize = 256;

/// A handle to a dynamic uniform buffer on the GPU.
///
/// Allows allocation and updating of individual blocks of memory.
pub struct DynamicUniformBuffer<'a, T>
where
    T: Pod,
{
    // keeps track of how many blocks are allocated so we know whether we can
    // clear the buffer or not
    _rc: RefCell<Rc<()>>,

    // represents the data in the buffer, which we don't actually own
    _phantom: PhantomData<&'a [T]>,

    inner: wgpu::Buffer,
    allocated: Cell<wgpu::BufferSize>,
    update_buf: Vec<u8>,
}

impl<'a, T> DynamicUniformBuffer<'a, T>
where
    T: Pod,
{
    pub fn new<'b>(device: &'b wgpu::Device) -> DynamicUniformBuffer<'a, T> {
        // TODO: is this something we can enforce at compile time?
        assert!(align_of::<T>() % DYNAMIC_UNIFORM_BUFFER_ALIGNMENT == 0);

        let inner = device.create_buffer(&wgpu::BufferDescriptor {
            label: Some("dynamic uniform buffer"),
            size: DYNAMIC_UNIFORM_BUFFER_SIZE,
            usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
            mapped_at_creation: false,
        });

        let mut update_buf = Vec::with_capacity(DYNAMIC_UNIFORM_BUFFER_SIZE as usize);
        update_buf.resize(DYNAMIC_UNIFORM_BUFFER_SIZE as usize, 0);

        DynamicUniformBuffer {
            _rc: RefCell::new(Rc::new(())),
            _phantom: PhantomData,
            inner,
            allocated: Cell::new(wgpu::BufferSize(0)),
            update_buf,
        }
    }

    pub fn block_size(&self) -> wgpu::BufferSize {
        wgpu::BufferSize((DYNAMIC_UNIFORM_BUFFER_ALIGNMENT.max(size_of::<T>())) as u64)
    }

    /// Allocates a block of memory in this dynamic uniform buffer with the
    /// specified initial value.
    #[must_use]
    pub fn allocate(&mut self, val: T) -> DynamicUniformBufferBlock<'a, T> {
        trace!("Allocating dynamic uniform block");
        let allocated = self.allocated.get().0;
        let size = self.block_size().0;
        if allocated + size > DYNAMIC_UNIFORM_BUFFER_SIZE {
            panic!(
                "Not enough space to allocate {} bytes in dynamic uniform buffer",
                size
            );
        }

        let addr = allocated;
        self.allocated.set(wgpu::BufferSize(allocated + size));

        let block = DynamicUniformBufferBlock {
            _rc: self._rc.borrow().clone(),
            _phantom: PhantomData,
            addr,
        };

        self.write_block(&block, val);
        block
    }

    pub fn write_block(&mut self, block: &DynamicUniformBufferBlock<'a, T>, val: T) {
        let start = block.addr as usize;
        let end = start + self.block_size().0 as usize;
        let mut slice = &mut self.update_buf[start..end];
        slice.copy_from_slice(unsafe { any_as_bytes(&val) });
    }

    /// Removes all allocations from the underlying buffer.
    ///
    /// Returns an error if the buffer is currently mapped or there are
    /// outstanding allocated blocks.
    pub fn clear(&self) -> Result<(), Error> {
        let mut out = self._rc.replace(Rc::new(()));
        match Rc::try_unwrap(out) {
            // no outstanding blocks
            Ok(()) => {
                self.allocated.set(wgpu::BufferSize(0));
                Ok(())
            }
            Err(rc) => {
                let _ = self._rc.replace(rc);
                bail!("Can't clear uniform buffer: there are outstanding references to allocated blocks.");
            }
        }
    }

    pub fn flush(&self, queue: &wgpu::Queue) {
        queue.write_buffer(&self.inner, 0, &self.update_buf);
    }

    pub fn buffer(&self) -> &wgpu::Buffer {
        &self.inner
    }
}

/// An address into a dynamic uniform buffer.
#[derive(Debug)]
pub struct DynamicUniformBufferBlock<'a, T> {
    _rc: Rc<()>,
    _phantom: PhantomData<&'a T>,

    addr: wgpu::BufferAddress,
}

impl<'a, T> DynamicUniformBufferBlock<'a, T> {
    pub fn offset(&self) -> wgpu::DynamicOffset {
        self.addr as wgpu::DynamicOffset
    }
}
<|endoftext|>


<commit_before>//! Additional combinators for testing futures.

mod assert_unmoved;
pub use self::assert_unmoved::AssertUnmoved;

mod pending_once;
pub use self::pending_once::PendingOnce;

use futures_core::future::Future;
use futures_executor;
use std::thread;

pub use crate::interleave_pending::InterleavePending;

/// Additional combinators for testing futures.
pub trait FutureTestExt: Future {
    /// Asserts that the given is not moved after being polled.
    ///
    /// A check for movement is performed each time the future is polled
    /// and when `Drop` is called.
    ///
    /// Aside from keeping track of the location at which the future was first
    /// polled and providing assertions, this future adds no runtime behavior
    /// and simply delegates to the child future.
    fn assert_unmoved(self) -> AssertUnmoved<Self>
    where
        Self: Sized,
    {
        AssertUnmoved::new(self)
    }

    /// Introduces one [`Poll::Pending`](futures_core::task::Poll::Pending)
    /// before polling the given future.
    ///
    /// # Examples
    ///
    /// ```
    /// use futures::task::Poll;
    /// use futures::future::FutureExt;
    /// use futures_test::task::noop_context;
    /// use futures_test::future::FutureTestExt;
    /// use futures::pin_mut;
    ///
    /// let future = (async { 5 }).pending_once();
    /// pin_mut!(future);
    ///
    /// let mut cx = noop_context();
    ///
    /// assert_eq!(future.poll_unpin(&mut cx), Poll::Pending);
    /// assert_eq!(future.poll_unpin(&mut cx), Poll::Ready(5));
    /// ```
    fn pending_once(self) -> PendingOnce<Self>
    where
        Self: Sized,
    {
        PendingOnce::new(self)
    }

    /// Runs this future on a dedicated executor running in a background thread.
    ///
    /// # Examples
    ///
    /// ```
    /// # futures::executor::block_on(async {
    /// use futures::channel::oneshot;
    /// use futures_test::future::FutureTestExt;
    ///
    /// let (tx, rx) = oneshot::channel::<i32>();
    ///
    /// (async { tx.send(5).unwrap() }).run_in_background();
    ///
    /// assert_eq!(rx.await, Ok(5));
    /// # });
    /// ```
    fn run_in_background(self)
    where
        Self: Sized + Send + 'static,
        Self::Output: Send,
    {
        thread::spawn(|| futures_executor::block_on(self));
    }

    /// Introduces an extra [`Poll::Pending`](futures_core::task::Poll::Pending)
    /// in between each call to poll.
    ///
    /// # Examples
    ///
    /// ```
    /// use futures::task::Poll;
    /// use futures::future::{self, Future};
    /// use futures_test::task::noop_context;
    /// use futures_test::future::FutureTestExt;
    /// use futures::pin_mut;
    ///
    /// let future = future::ready(1).interleave_pending();
    /// pin_mut!(future);
    ///
    /// let mut cx = noop_context();
    ///
    /// assert_eq!(future.as_mut().poll(&mut cx), Poll::Pending);
    /// assert_eq!(future.as_mut().poll(&mut cx), Poll::Ready(1));
    /// ```
    fn interleave_pending(self) -> InterleavePending<Self>
    where
        Self: Sized,
    {
        InterleavePending::new(self)
    }
}

impl<Fut> FutureTestExt for Fut where Fut: Future {}
<commit_msg>Fix cargo clippy error<commit_after>//! Additional combinators for testing futures.

mod assert_unmoved;
pub use self::assert_unmoved::AssertUnmoved;

mod pending_once;
pub use self::pending_once::PendingOnce;

use futures_core::future::Future;
use std::thread;

pub use crate::interleave_pending::InterleavePending;

/// Additional combinators for testing futures.
pub trait FutureTestExt: Future {
    /// Asserts that the given is not moved after being polled.
    ///
    /// A check for movement is performed each time the future is polled
    /// and when `Drop` is called.
    ///
    /// Aside from keeping track of the location at which the future was first
    /// polled and providing assertions, this future adds no runtime behavior
    /// and simply delegates to the child future.
    fn assert_unmoved(self) -> AssertUnmoved<Self>
    where
        Self: Sized,
    {
        AssertUnmoved::new(self)
    }

    /// Introduces one [`Poll::Pending`](futures_core::task::Poll::Pending)
    /// before polling the given future.
    ///
    /// # Examples
    ///
    /// ```
    /// use futures::task::Poll;
    /// use futures::future::FutureExt;
    /// use futures_test::task::noop_context;
    /// use futures_test::future::FutureTestExt;
    /// use futures::pin_mut;
    ///
    /// let future = (async { 5 }).pending_once();
    /// pin_mut!(future);
    ///
    /// let mut cx = noop_context();
    ///
    /// assert_eq!(future.poll_unpin(&mut cx), Poll::Pending);
    /// assert_eq!(future.poll_unpin(&mut cx), Poll::Ready(5));
    /// ```
    fn pending_once(self) -> PendingOnce<Self>
    where
        Self: Sized,
    {
        PendingOnce::new(self)
    }

    /// Runs this future on a dedicated executor running in a background thread.
    ///
    /// # Examples
    ///
    /// ```
    /// # futures::executor::block_on(async {
    /// use futures::channel::oneshot;
    /// use futures_test::future::FutureTestExt;
    ///
    /// let (tx, rx) = oneshot::channel::<i32>();
    ///
    /// (async { tx.send(5).unwrap() }).run_in_background();
    ///
    /// assert_eq!(rx.await, Ok(5));
    /// # });
    /// ```
    fn run_in_background(self)
    where
        Self: Sized + Send + 'static,
        Self::Output: Send,
    {
        thread::spawn(|| futures_executor::block_on(self));
    }

    /// Introduces an extra [`Poll::Pending`](futures_core::task::Poll::Pending)
    /// in between each call to poll.
    ///
    /// # Examples
    ///
    /// ```
    /// use futures::task::Poll;
    /// use futures::future::{self, Future};
    /// use futures_test::task::noop_context;
    /// use futures_test::future::FutureTestExt;
    /// use futures::pin_mut;
    ///
    /// let future = future::ready(1).interleave_pending();
    /// pin_mut!(future);
    ///
    /// let mut cx = noop_context();
    ///
    /// assert_eq!(future.as_mut().poll(&mut cx), Poll::Pending);
    /// assert_eq!(future.as_mut().poll(&mut cx), Poll::Ready(1));
    /// ```
    fn interleave_pending(self) -> InterleavePending<Self>
    where
        Self: Sized,
    {
        InterleavePending::new(self)
    }
}

impl<Fut> FutureTestExt for Fut where Fut: Future {}
<|endoftext|>


<commit_before>use crate::gen::{CfgEvaluator, CfgResult};
use once_cell::sync::OnceCell;
use std::borrow::Borrow;
use std::cmp::Ordering;
use std::collections::{BTreeMap as Map, BTreeSet as Set};
use std::env;

static ENV: OnceCell<CargoEnv> = OnceCell::new();

struct CargoEnv {
    features: Set<Name>,
    cfgs: Map<Name, String>,
}

pub(super) struct CargoEnvCfgEvaluator;

impl CfgEvaluator for CargoEnvCfgEvaluator {
    fn eval(&self, name: &str, query_value: Option<&str>) -> CfgResult {
        let env = ENV.get_or_init(CargoEnv::load);
        if name == "feature" {
            if let Some(query_value) = query_value {
                CfgResult::from(env.features.contains(Lookup::new(query_value)))
            } else {
                let msg = "expected `feature = \"...\"`".to_owned();
                CfgResult::Undetermined { msg }
            }
        } else {
            match env.cfgs.get(Lookup::new(name)) {
                Some(cargo_value) => {
                    if let Some(query_value) = query_value {
                        CfgResult::from(cargo_value.split(',').any(|value| value == query_value))
                    } else {
                        CfgResult::True
                    }
                }
                None => CfgResult::False,
            }
        }
    }
}

impl CargoEnv {
    fn load() -> Self {
        const CARGO_FEATURE_PREFIX: &str = "CARGO_FEATURE_";
        const CARGO_CFG_PREFIX: &str = "CARGO_CFG_";

        let mut features = Set::new();
        let mut cfgs = Map::new();
        for (k, v) in env::vars_os() {
            let k = match k.to_str() {
                Some(k) => k,
                None => continue,
            };
            let v = match v.into_string() {
                Ok(v) => v,
                Err(_) => continue,
            };
            if let Some(feature_name) = k.strip_prefix(CARGO_FEATURE_PREFIX) {
                let feature_name = Name(feature_name.to_owned());
                features.insert(feature_name);
            } else if let Some(cfg_name) = k.strip_prefix(CARGO_CFG_PREFIX) {
                let cfg_name = Name(cfg_name.to_owned());
                cfgs.insert(cfg_name, v);
            }
        }
        CargoEnv { features, cfgs }
    }
}

struct Name(String);

impl Ord for Name {
    fn cmp(&self, rhs: &Self) -> Ordering {
        Lookup::new(&self.0).cmp(Lookup::new(&rhs.0))
    }
}

impl PartialOrd for Name {
    fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
        Some(self.cmp(rhs))
    }
}

impl Eq for Name {}

impl PartialEq for Name {
    fn eq(&self, rhs: &Self) -> bool {
        Lookup::new(&self.0).eq(Lookup::new(&rhs.0))
    }
}

#[repr(transparent)]
struct Lookup(str);

impl Lookup {
    fn new(name: &str) -> &Self {
        unsafe { &*(name as *const str as *const Self) }
    }
}

impl Borrow<Lookup> for Name {
    fn borrow(&self) -> &Lookup {
        Lookup::new(&self.0)
    }
}

impl Ord for Lookup {
    fn cmp(&self, rhs: &Self) -> Ordering {
        self.0
            .bytes()
            .map(CaseAgnosticByte)
            .cmp(rhs.0.bytes().map(CaseAgnosticByte))
    }
}

impl PartialOrd for Lookup {
    fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
        Some(self.cmp(rhs))
    }
}

impl Eq for Lookup {}

impl PartialEq for Lookup {
    fn eq(&self, rhs: &Self) -> bool {
        self.0
            .bytes()
            .map(CaseAgnosticByte)
            .eq(rhs.0.bytes().map(CaseAgnosticByte))
    }
}

struct CaseAgnosticByte(u8);

impl Ord for CaseAgnosticByte {
    fn cmp(&self, rhs: &Self) -> Ordering {
        self.0.to_ascii_lowercase().cmp(&rhs.0.to_ascii_lowercase())
    }
}

impl PartialOrd for CaseAgnosticByte {
    fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
        Some(self.cmp(rhs))
    }
}

impl Eq for CaseAgnosticByte {}

impl PartialEq for CaseAgnosticByte {
    fn eq(&self, rhs: &Self) -> bool {
        self.cmp(rhs) == Ordering::Equal
    }
}
<commit_msg>Disallow cfg(test) inside Cargo builds<commit_after>use crate::gen::{CfgEvaluator, CfgResult};
use once_cell::sync::OnceCell;
use std::borrow::Borrow;
use std::cmp::Ordering;
use std::collections::{BTreeMap as Map, BTreeSet as Set};
use std::env;

static ENV: OnceCell<CargoEnv> = OnceCell::new();

struct CargoEnv {
    features: Set<Name>,
    cfgs: Map<Name, String>,
}

pub(super) struct CargoEnvCfgEvaluator;

impl CfgEvaluator for CargoEnvCfgEvaluator {
    fn eval(&self, name: &str, query_value: Option<&str>) -> CfgResult {
        let env = ENV.get_or_init(CargoEnv::load);
        if name == "feature" {
            if let Some(query_value) = query_value {
                CfgResult::from(env.features.contains(Lookup::new(query_value)))
            } else {
                let msg = "expected `feature = \"...\"`".to_owned();
                CfgResult::Undetermined { msg }
            }
        } else if name == "test" && query_value.is_none() {
            let msg = "cfg(test) is not supported because Cargo runs your build script only once across the lib and test build of the same crate".to_owned();
            CfgResult::Undetermined { msg }
        } else {
            match env.cfgs.get(Lookup::new(name)) {
                Some(cargo_value) => {
                    if let Some(query_value) = query_value {
                        CfgResult::from(cargo_value.split(',').any(|value| value == query_value))
                    } else {
                        CfgResult::True
                    }
                }
                None => CfgResult::False,
            }
        }
    }
}

impl CargoEnv {
    fn load() -> Self {
        const CARGO_FEATURE_PREFIX: &str = "CARGO_FEATURE_";
        const CARGO_CFG_PREFIX: &str = "CARGO_CFG_";

        let mut features = Set::new();
        let mut cfgs = Map::new();
        for (k, v) in env::vars_os() {
            let k = match k.to_str() {
                Some(k) => k,
                None => continue,
            };
            let v = match v.into_string() {
                Ok(v) => v,
                Err(_) => continue,
            };
            if let Some(feature_name) = k.strip_prefix(CARGO_FEATURE_PREFIX) {
                let feature_name = Name(feature_name.to_owned());
                features.insert(feature_name);
            } else if let Some(cfg_name) = k.strip_prefix(CARGO_CFG_PREFIX) {
                let cfg_name = Name(cfg_name.to_owned());
                cfgs.insert(cfg_name, v);
            }
        }
        CargoEnv { features, cfgs }
    }
}

struct Name(String);

impl Ord for Name {
    fn cmp(&self, rhs: &Self) -> Ordering {
        Lookup::new(&self.0).cmp(Lookup::new(&rhs.0))
    }
}

impl PartialOrd for Name {
    fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
        Some(self.cmp(rhs))
    }
}

impl Eq for Name {}

impl PartialEq for Name {
    fn eq(&self, rhs: &Self) -> bool {
        Lookup::new(&self.0).eq(Lookup::new(&rhs.0))
    }
}

#[repr(transparent)]
struct Lookup(str);

impl Lookup {
    fn new(name: &str) -> &Self {
        unsafe { &*(name as *const str as *const Self) }
    }
}

impl Borrow<Lookup> for Name {
    fn borrow(&self) -> &Lookup {
        Lookup::new(&self.0)
    }
}

impl Ord for Lookup {
    fn cmp(&self, rhs: &Self) -> Ordering {
        self.0
            .bytes()
            .map(CaseAgnosticByte)
            .cmp(rhs.0.bytes().map(CaseAgnosticByte))
    }
}

impl PartialOrd for Lookup {
    fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
        Some(self.cmp(rhs))
    }
}

impl Eq for Lookup {}

impl PartialEq for Lookup {
    fn eq(&self, rhs: &Self) -> bool {
        self.0
            .bytes()
            .map(CaseAgnosticByte)
            .eq(rhs.0.bytes().map(CaseAgnosticByte))
    }
}

struct CaseAgnosticByte(u8);

impl Ord for CaseAgnosticByte {
    fn cmp(&self, rhs: &Self) -> Ordering {
        self.0.to_ascii_lowercase().cmp(&rhs.0.to_ascii_lowercase())
    }
}

impl PartialOrd for CaseAgnosticByte {
    fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
        Some(self.cmp(rhs))
    }
}

impl Eq for CaseAgnosticByte {}

impl PartialEq for CaseAgnosticByte {
    fn eq(&self, rhs: &Self) -> bool {
        self.cmp(rhs) == Ordering::Equal
    }
}
<|endoftext|>


<commit_before>extern crate crusty_chip;
extern crate getopts;
extern crate sfml;

use getopts::Options;

fn usage(progname: &str, opts: &Options) -> String {
    let brief = format!("{} rom_file", progname);
    format!("Usage: {}", opts.usage(&brief))
}

fn run() -> i32 {
    use crusty_chip::{decode, VirtualMachine, DISPLAY_HEIGHT, DISPLAY_WIDTH};
    use sfml::graphics::{Color, RenderTarget, RenderWindow, Sprite, Texture, Transformable};
    use sfml::system::Clock;
    use sfml::window::{ContextSettings, Event, Style, VideoMode};
    use std::fs::File;
    use std::io::Read;

    let mut args = std::env::args();
    let progname = args.next().expect("Missing program name?");
    let mut opts = Options::new();
    opts.optflag("", "pause", "Start in a paused state");

    let matches = match opts.parse(args) {
        Ok(matches) => matches,
        Err(e) => {
            eprintln!("{}\n\n{}", e, usage(&progname, &opts));
            return 1;
        }
    };

    let mut paused = matches.opt_present("pause");

    let filename = match matches.free.get(0) {
        Some(filename) => filename,
        None => {
            eprintln!("Required filename as first positional argument.\n");
            eprintln!("{}", usage(&progname, &opts));
            return 1;
        }
    };

    let mut clock = Clock::start();

    let mut file = match File::open(&filename) {
        Ok(f) => f,
        Err(e) => {
            eprintln!("Failed to open \"{}\": {}", filename, e);
            return 1;
        }
    };

    if file.metadata().unwrap().len() > crusty_chip::MEM_SIZE as u64 {
        eprintln!(
            "File \"{}\" is too big to be a proper CHIP-8 ROM.",
            filename
        );
        return 1;
    }

    let mut data = [0; crusty_chip::MEM_SIZE];
    // TODO: Dunno if this always reads the whole file
    let bytes_read = file.read(&mut data)
        .unwrap_or_else(|e| panic!("Failed to read rom: {}", e));

    let scale = 10;

    let mut ch8 = VirtualMachine::new();
    match ch8.load_rom(&data[..bytes_read]) {
        Ok(data) => data,
        Err(e) => {
            eprintln!("Error loading rom: \"{}\". Aborting.", e);
            return 1;
        }
    }

    let ctx = ContextSettings::default();
    let mut win = RenderWindow::new(
        VideoMode::new(
            DISPLAY_WIDTH as u32 * scale,
            DISPLAY_HEIGHT as u32 * scale,
            32,
        ),
        "CrustyChip",
        Style::CLOSE,
        &ctx,
    );

    let mut tex = Texture::new(DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32).unwrap();

    win.clear(&Color::BLACK);
    win.display();
    let mut saved_states = [None; 10];
    let mut printed_info = false;
    let mut cycles_made: u64 = 0;

    loop {
        let mut advance = false;
        let mut redisplay = false;
        while let Some(event) = win.poll_event() {
            use sfml::window::Key;
            fn key_mapping(code: Key) -> Option<usize> {
                match code {
                    Key::Num1 => Some(1),
                    Key::Num2 => Some(2),
                    Key::Num3 => Some(3),
                    Key::Num4 => Some(0xC),
                    Key::Q => Some(4),
                    Key::W => Some(5),
                    Key::E => Some(6),
                    Key::R => Some(0xD),
                    Key::A => Some(7),
                    Key::S => Some(8),
                    Key::D => Some(9),
                    Key::F => Some(0xE),
                    Key::Z => Some(0xA),
                    Key::X => Some(0),
                    Key::C => Some(0xB),
                    Key::V => Some(0xF),
                    _ => None,
                }
            }
            match event {
                Event::Closed => return 0,
                Event::KeyPressed {
                    code, ctrl, shift, ..
                } => {
                    if code == Key::P {
                        paused = !paused;
                    } else if code == Key::R && ctrl {
                        ch8 = VirtualMachine::new();
                        ch8.load_rom(&data).expect("ROM data too big? It changed?");
                    } else if code == Key::Period {
                        advance = true;
                    } else if let Some(key) = key_mapping(code) {
                        ch8.press_key(key);
                    }
                    macro_rules! state_key (
                        ($s: expr, $k: ident) => (
                            if code == Key::$k {
                                if shift {
                                    saved_states[$s] = Some(ch8);
                                    eprintln!("Saved state {}.", $s);
                                } else if let Some(state) = saved_states[$s] {
                                    ch8 = state;
                                    eprintln!("Loaded state {}.", $s);
                                }
                            }
                        )
                    );
                    state_key!(0, F1);
                    state_key!(1, F2);
                    state_key!(2, F3);
                    state_key!(3, F4);
                    state_key!(4, F5);
                    state_key!(5, F6);
                    state_key!(6, F7);
                    state_key!(7, F8);
                    state_key!(8, F9);
                    state_key!(9, F10);
                }
                Event::KeyReleased { code, .. } => if let Some(key) = key_mapping(code) {
                    ch8.release_key(key);
                },
                Event::GainedFocus => redisplay = true,
                _ => {}
            }
        }

        if redisplay {
            win.display();
        }

        if clock.elapsed_time().as_seconds() >= 1.0 / 60.0 {
            ch8.decrement_timers();
            clock.restart();
        }

        if paused {
            std::thread::sleep(std::time::Duration::from_millis(25));
        }

        if paused && !printed_info {
            let raw_ins = ch8.get_ins();
            println!(
                "Cycle {}, pc @ {:x}, ins: {:?} ({:x})",
                cycles_made,
                ch8.pc(),
                decode(raw_ins),
                raw_ins
            );
            printed_info = true;
        }

        if !paused || advance {
            ch8.do_cycle();
            cycles_made += 1;
            printed_info = false;
        }

        if ch8.display_updated() {
            let mut pixels = [255u8; DISPLAY_WIDTH * DISPLAY_HEIGHT * 4];

            for (i, b) in ch8.display().iter().enumerate() {
                let idx = i * 4;
                if *b == 0u8 {
                    for p in pixels[idx..idx + 3].iter_mut() {
                        *p = 0;
                    }
                }
            }

            tex.update_from_pixels(&pixels, DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32, 0, 0);
            let mut sprite = Sprite::with_texture(&tex);
            sprite.set_scale((scale as f32, scale as f32));
            win.draw(&sprite);
            win.display();
        }
    }
}

fn main() {
    std::process::exit(run());
}
<commit_msg>Handle loading roms more robustly<commit_after>extern crate crusty_chip;
extern crate getopts;
extern crate sfml;

use getopts::Options;

fn usage(progname: &str, opts: &Options) -> String {
    let brief = format!("{} rom_file", progname);
    format!("Usage: {}", opts.usage(&brief))
}

fn run() -> i32 {
    use crusty_chip::{decode, VirtualMachine, DISPLAY_HEIGHT, DISPLAY_WIDTH};
    use sfml::graphics::{Color, RenderTarget, RenderWindow, Sprite, Texture, Transformable};
    use sfml::system::Clock;
    use sfml::window::{ContextSettings, Event, Style, VideoMode};
    use std::fs::File;
    use std::io::Read;

    let mut args = std::env::args();
    let progname = args.next().expect("Missing program name?");
    let mut opts = Options::new();
    opts.optflag("", "pause", "Start in a paused state");

    let matches = match opts.parse(args) {
        Ok(matches) => matches,
        Err(e) => {
            eprintln!("{}\n\n{}", e, usage(&progname, &opts));
            return 1;
        }
    };

    let mut paused = matches.opt_present("pause");

    let filename = match matches.free.get(0) {
        Some(filename) => filename,
        None => {
            eprintln!("Required filename as first positional argument.\n");
            eprintln!("{}", usage(&progname, &opts));
            return 1;
        }
    };

    let mut clock = Clock::start();

    let mut file = match File::open(&filename) {
        Ok(f) => f,
        Err(e) => {
            eprintln!("Failed to open \"{}\": {}", filename, e);
            return 1;
        }
    };

    if file.metadata().unwrap().len() > crusty_chip::MEM_SIZE as u64 {
        eprintln!(
            "File \"{}\" is too big to be a proper CHIP-8 ROM.",
            filename
        );
        return 1;
    }

    let mut data = Vec::new();
    // TODO: Dunno if this always reads the whole file
    file.read_to_end(&mut data)
        .unwrap_or_else(|e| panic!("Failed to read rom: {}", e));

    let scale = 10;

    let mut ch8 = VirtualMachine::new();
    match ch8.load_rom(&data) {
        Ok(data) => data,
        Err(e) => {
            eprintln!("Error loading rom: \"{}\". Aborting.", e);
            return 1;
        }
    }

    let ctx = ContextSettings::default();
    let mut win = RenderWindow::new(
        VideoMode::new(
            DISPLAY_WIDTH as u32 * scale,
            DISPLAY_HEIGHT as u32 * scale,
            32,
        ),
        "CrustyChip",
        Style::CLOSE,
        &ctx,
    );

    let mut tex = Texture::new(DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32).unwrap();

    win.clear(&Color::BLACK);
    win.display();
    let mut saved_states = [None; 10];
    let mut printed_info = false;
    let mut cycles_made: u64 = 0;

    loop {
        let mut advance = false;
        let mut redisplay = false;
        while let Some(event) = win.poll_event() {
            use sfml::window::Key;
            fn key_mapping(code: Key) -> Option<usize> {
                match code {
                    Key::Num1 => Some(1),
                    Key::Num2 => Some(2),
                    Key::Num3 => Some(3),
                    Key::Num4 => Some(0xC),
                    Key::Q => Some(4),
                    Key::W => Some(5),
                    Key::E => Some(6),
                    Key::R => Some(0xD),
                    Key::A => Some(7),
                    Key::S => Some(8),
                    Key::D => Some(9),
                    Key::F => Some(0xE),
                    Key::Z => Some(0xA),
                    Key::X => Some(0),
                    Key::C => Some(0xB),
                    Key::V => Some(0xF),
                    _ => None,
                }
            }
            match event {
                Event::Closed => return 0,
                Event::KeyPressed {
                    code, ctrl, shift, ..
                } => {
                    if code == Key::P {
                        paused = !paused;
                    } else if code == Key::R && ctrl {
                        ch8 = VirtualMachine::new();
                        ch8.load_rom(&data).expect("ROM data too big? It changed?");
                    } else if code == Key::Period {
                        advance = true;
                    } else if let Some(key) = key_mapping(code) {
                        ch8.press_key(key);
                    }
                    macro_rules! state_key (
                        ($s: expr, $k: ident) => (
                            if code == Key::$k {
                                if shift {
                                    saved_states[$s] = Some(ch8);
                                    eprintln!("Saved state {}.", $s);
                                } else if let Some(state) = saved_states[$s] {
                                    ch8 = state;
                                    eprintln!("Loaded state {}.", $s);
                                }
                            }
                        )
                    );
                    state_key!(0, F1);
                    state_key!(1, F2);
                    state_key!(2, F3);
                    state_key!(3, F4);
                    state_key!(4, F5);
                    state_key!(5, F6);
                    state_key!(6, F7);
                    state_key!(7, F8);
                    state_key!(8, F9);
                    state_key!(9, F10);
                }
                Event::KeyReleased { code, .. } => if let Some(key) = key_mapping(code) {
                    ch8.release_key(key);
                },
                Event::GainedFocus => redisplay = true,
                _ => {}
            }
        }

        if redisplay {
            win.display();
        }

        if clock.elapsed_time().as_seconds() >= 1.0 / 60.0 {
            ch8.decrement_timers();
            clock.restart();
        }

        if paused {
            std::thread::sleep(std::time::Duration::from_millis(25));
        }

        if paused && !printed_info {
            let raw_ins = ch8.get_ins();
            println!(
                "Cycle {}, pc @ {:x}, ins: {:?} ({:x})",
                cycles_made,
                ch8.pc(),
                decode(raw_ins),
                raw_ins
            );
            printed_info = true;
        }

        if !paused || advance {
            ch8.do_cycle();
            cycles_made += 1;
            printed_info = false;
        }

        if ch8.display_updated() {
            let mut pixels = [255u8; DISPLAY_WIDTH * DISPLAY_HEIGHT * 4];

            for (i, b) in ch8.display().iter().enumerate() {
                let idx = i * 4;
                if *b == 0u8 {
                    for p in pixels[idx..idx + 3].iter_mut() {
                        *p = 0;
                    }
                }
            }

            tex.update_from_pixels(&pixels, DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32, 0, 0);
            let mut sprite = Sprite::with_texture(&tex);
            sprite.set_scale((scale as f32, scale as f32));
            win.draw(&sprite);
            win.display();
        }
    }
}

fn main() {
    std::process::exit(run());
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use std::rc::{Rc, Weak};
use entity::{Vec3f64, Entity};

struct Address {
    x: u64,
    y: u64,
    z: u64,
    depth: u8,
}

struct Element {
    name: String,
}

pub enum ChunkOption {
    Local(Rc<LocalChunk>),
    Remote(Rc<RemoteChunk>)
}

pub enum ChildOption {
    Local(Rc<LocalChunk>),
    Remote(Rc<RemoteChunk>),
    None
}

pub enum ParentOption {
    Local(Weak<LocalChunk>),
    Remote(Rc<RemoteChunk>),
    None
}

pub struct LocalChunk {
    address: Address,
    center: Vec3f64,
    children: [ChildOption; 8],
    child_number: Option<u8>,
    entities: Vec<Rc<Entity>>,
    mass: f64,
    parent: ParentOption,
    scale: u8,
    structure: u64,
    summary: Rc<Element>,
}

pub struct RemoteChunk {
    connection: i32,
}

impl Address {
    fn from_string(address: String) -> Option<Address> {
        let mut xyz: (u64, u64, u64) = (1, 1, 1);
        let mut xyz_add: (u64, u64, u64);

        for (index, character) in address.chars().enumerate() {
            if index > 63 {
                break;
            }
            xyz_add =  match character.to_digit(8) {
                Some(0) => (0, 0, 0),
                Some(1) => (0, 0, 1),
                Some(2) => (0, 1, 0),
                Some(3) => (0, 1, 1),
                Some(4) => (1, 0, 0),
                Some(5) => (1, 0, 1),
                Some(6) => (1, 1, 0),
                Some(7) => (1, 1, 1),
                _ => return None,
            };
            xyz = (xyz.0 << 1, xyz.1 << 1, xyz.2 << 1);
            xyz = (xyz.0 + xyz_add.0, xyz.1 + xyz_add.1, xyz.2 + xyz_add.2);
        }
        Some(Address {x: xyz.0, y: xyz.1, z: xyz.2, depth: address.len() as u8})
    }
}

impl ToString for Address {
    fn to_string(&self) -> String {
        String::from_str("")
    }
}

impl PartialEq for Address {
    fn eq(&self, other: &Self) -> bool {
        (((self.x == other.x) && (self.y == other.y)) && (self.z == other.z))
    }
}

pub trait Chunk {
    fn get_child(&self, x: u8, y: u8, z: u8) -> ChildOption;
    fn tick(&self, time_delta: f64);
}

impl Chunk for LocalChunk {
    fn get_child(&self, x: u8, y: u8, z: u8) -> ChildOption {

        let index = match (x, y, z) {
            (0, 0, 0) => Some(0),
            (0, 0, 1) => Some(1),
            (0, 1, 0) => Some(2),
            (0, 1, 1) => Some(3),
            (1, 0, 0) => Some(4),
            (1, 0, 1) => Some(5),
            (1, 1, 0) => Some(6),
            (1, 1, 1) => Some(7),
            _ => None,
        };

        match index {
            Some(i) => match self.children[i] {
                ChildOption::Local(ref chunk) => ChildOption::Local(chunk.clone()),
                ChildOption::Remote(ref chunk) => ChildOption::Remote(chunk.clone()),
                ChildOption::None => ChildOption::None
            },
            None => ChildOption::None
        }
    }

    fn tick(&self, time_delta: f64) {
    }
}

impl Chunk for RemoteChunk {
    fn get_child(&self, x: u8, y: u8, z: u8) -> ChildOption {
        ChildOption::None
    }
    fn tick (&self, time_delta: f64) {
    }
}

<commit_msg>Lineage stuff?<commit_after>#![allow(dead_code)]

use std::rc::{Rc, Weak};
use entity::{Vec3f64, Entity};

struct Address {
    x: u64,
    y: u64,
    z: u64,
    depth: u8,
}

pub enum AddressLineage {
    Ancestor,
    Descendant,
    Same,
    None
}

struct Element {
    name: String,
}

pub enum ChunkOption {
    Local(Rc<LocalChunk>),
    Remote(Rc<RemoteChunk>)
}

pub enum ChildOption {
    Local(Rc<LocalChunk>),
    Remote(Rc<RemoteChunk>),
    None
}

pub enum ParentOption {
    Local(Weak<LocalChunk>),
    Remote(Rc<RemoteChunk>),
    None
}

pub struct LocalChunk {
    address: Address,
    center: Vec3f64,
    children: [ChildOption; 8],
    child_number: Option<u8>,
    entities: Vec<Rc<Entity>>,
    mass: f64,
    parent: ParentOption,
    scale: u8,
    structure: u64,
    summary: Rc<Element>,
}

pub struct RemoteChunk {
    connection: i32,
}

impl Address {
    fn from_string(address: String) -> Option<Address> {
        let mut xyz: (u64, u64, u64) = (1, 1, 1);
        let mut xyz_add: (u64, u64, u64);

        for (index, character) in address.chars().enumerate() {
            if index > 63 {
                break;
            }
            xyz_add =  match character.to_digit(8) {
                Some(0) => (0, 0, 0),
                Some(1) => (0, 0, 1),
                Some(2) => (0, 1, 0),
                Some(3) => (0, 1, 1),
                Some(4) => (1, 0, 0),
                Some(5) => (1, 0, 1),
                Some(6) => (1, 1, 0),
                Some(7) => (1, 1, 1),
                _ => return None,
            };
            xyz = (xyz.0 << 1, xyz.1 << 1, xyz.2 << 1);
            xyz = (xyz.0 + xyz_add.0, xyz.1 + xyz_add.1, xyz.2 + xyz_add.2);
        }
        Some(Address {x: xyz.0, y: xyz.1, z: xyz.2, depth: address.len() as u8})
    }

    fn lineage(a: Address, b: Address) -> AddressLineage {
        if a.depth == b.depth {
            if a == b {
                AddressLineage::Same
            }
            else {
                AddressLineage::None
            }
        }
        else {
            if a.depth > b.depth {
                //FIXME
                AddressLineage::Ancestor

            }
            else { // a.depth < b.depth
                //FIXME
                AddressLineage::Descendant
            }
        }
    }
}

impl ToString for Address {
    fn to_string(&self) -> String {
        String::from_str("")
    }
}

impl PartialEq for Address {
    fn eq(&self, other: &Self) -> bool {
        (((self.x == other.x) && (self.y == other.y)) && (self.z == other.z))
    }
}

pub trait Chunk {
    fn get_child(&self, x: u8, y: u8, z: u8) -> ChildOption;
    fn tick(&self, time_delta: f64);
}

impl Chunk for LocalChunk {
    fn get_child(&self, x: u8, y: u8, z: u8) -> ChildOption {

        let index = match (x, y, z) {
            (0, 0, 0) => Some(0),
            (0, 0, 1) => Some(1),
            (0, 1, 0) => Some(2),
            (0, 1, 1) => Some(3),
            (1, 0, 0) => Some(4),
            (1, 0, 1) => Some(5),
            (1, 1, 0) => Some(6),
            (1, 1, 1) => Some(7),
            _ => None,
        };

        match index {
            Some(i) => match self.children[i] {
                ChildOption::Local(ref chunk) => ChildOption::Local(chunk.clone()),
                ChildOption::Remote(ref chunk) => ChildOption::Remote(chunk.clone()),
                ChildOption::None => ChildOption::None
            },
            None => ChildOption::None
        }
    }

    fn tick(&self, time_delta: f64) {
    }
}

impl Chunk for RemoteChunk {
    fn get_child(&self, x: u8, y: u8, z: u8) -> ChildOption {
        ChildOption::None
    }
    fn tick (&self, time_delta: f64) {
    }
}

<|endoftext|>


<commit_before>//! The datatable module.
//!
//! Contains the DataTable struct and provides methods
//! for converting the tables to various formats.

use std::str::FromStr;
use std::error::Error;
use std::fmt;
use std::vec::IntoIter;
use std;

/// A data table consisting of varying column types and headers.
pub struct DataTable {
    /// Vector of DataColumns.
    pub data_cols: Vec<DataColumn>,
}

impl DataTable {
    /// Constructs an empty DataTable
    pub fn empty() -> DataTable {
        DataTable { data_cols: Vec::new() }
    }

    /// The number of columns in the DataTable.
    pub fn cols(&self) -> usize {
        self.data_cols.len()
    }

    /// The number of rows in the DataTable.
    pub fn rows(&self) -> usize {
        if self.data_cols.len() > 0 {
            return self.data_cols[0].len();
        }

        0usize
    }

    /// Shrinks the table and it's underlying columns.
    pub fn shrink_to_fit(&mut self) {
        for col in self.data_cols.iter_mut() {
            col.shrink_to_fit();
        }

        self.data_cols.shrink_to_fit();
    }

    /// Consumes self and attempts to convert the DataTable into a single Vec.
    ///
    /// Uses column major ordering.
    ///
    /// # Failures
    ///
    /// - DataCastError : Returned when the data cannot be cast into the requested type.
    pub fn into_consistent_data<T: FromStr>(self) -> Result<Vec<T>, DataError> {
        let mut table_data = Vec::with_capacity(self.cols() * self.rows());
        for d in self.data_cols.into_iter() {
            match d.into_vec() {
                Ok(x) => table_data.extend(x),
                Err(e) => return Err(e),
            }
        }

        Ok(table_data)
    }

    /// Attempts to convert the DataTable into a single Vec.
    ///
    /// Uses column major ordering. Returns an Option.
    pub fn consistent_data<T: FromStr>(&self) -> Option<Vec<T>> {
        let mut table_data = Vec::with_capacity(self.cols() * self.rows());
        for d in self.data_cols.iter() {
            match d.cast() {
                Some(x) => table_data.extend(x),
                None => return None,
            }
        }

        Some(table_data)
    }
}

/// Errors related to Data functions.
#[derive(Debug)]
pub enum DataError {
    /// An error for attempting to cast data types within DataTable.
    DataCastError,
}

impl fmt::Display for DataError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &DataError::DataCastError => write!(f, "DataCastError"),
        }
    }
}

impl Error for DataError {
    fn description(&self) -> &str {
        match self {
            &DataError::DataCastError => "Failed to cast data.",
        }
    }
}

/// A data column consisting of Strings.
pub struct DataColumn {
    /// The name associated with the DataColumn.
    pub name: Option<String>,
    data: Vec<String>,
}

impl DataColumn {
    /// Constructs an empty data column.
    pub fn empty() -> DataColumn {
        DataColumn {
            name: None,
            data: Vec::new(),
        }
    }

    /// Gets the length of the data column.
    pub fn len(&self) -> usize {
        self.data.len()
    }

    /// Gets an immutable reference to the underlying data.
    pub fn data(&self) -> &Vec<String> {
        &self.data
    }

    /// Pushes a new &str to the column.
    pub fn push(&mut self, val: &str) {
        self.data.push(val.to_owned());
    }

    /// Shrink the column to fit the data.
    pub fn shrink_to_fit(&mut self) {
        self.data.shrink_to_fit();
    }

    /// Consumes self and returns a Vec of the requested type.
    ///
    /// # Failures
    ///
    /// - DataCastError : Returned when the data cannot be parsed to the requested type.
    pub fn into_vec<T: FromStr>(self) -> Result<Vec<T>, DataError> {
        let mut casted_data = Vec::<T>::with_capacity(self.data.len());

        for d in self.data.into_iter() {
            match T::from_str(&d[..]) {
                Ok(x) => casted_data.push(x),
                Err(_) => return Err(DataError::DataCastError),
            }
        }

        Ok(casted_data)
    }

    /// Cast the data to the requested type.
    ///
    /// Returns a Vec of the requested type wrapped in an option.
    pub fn cast<T: FromStr>(&self) -> Option<Vec<T>> {
        let mut casted_data = Vec::<T>::with_capacity(self.data.len());

        for d in self.data.iter() {
            match T::from_str(&d[..]) {
                Ok(x) => casted_data.push(x),
                Err(_) => return None,
            }
        }

        Some(casted_data)
    }

    /// Consumes self and returns an iterator which parses
    /// the data to the specified type returning results.
    ///
    /// The iterator will return a result on `next()` detailing
    /// the outcome of the parse.
    pub fn into_iter_cast<U: FromStr>
        (self)
         -> std::iter::Map<IntoIter<String>, fn(String) -> Result<U, <U as FromStr>::Err>>
        where U: FromStr
    {
        from_str_iter::<_, U>(self.data.into_iter())
    }
}

/// Converts the iterator to a FromStr iterator.
fn from_str_iter<I, U>
    (iter: I)
     -> std::iter::Map<I, fn(<I as Iterator>::Item) -> Result<U, <U as FromStr>::Err>>
    where I: Iterator,
          <I as Iterator>::Item: AsRef<str>,
          U: FromStr
{
    fn from_str_fn<T, U>(item: T) -> Result<U, <U as FromStr>::Err>
        where T: AsRef<str>,
              U: FromStr
    {
        FromStr::from_str(item.as_ref())
    }
    iter.map(from_str_fn)
}
<commit_msg>Cleanup and allowing parsed indexing<commit_after>//! The datatable module.
//!
//! Contains the DataTable struct and provides methods
//! for converting the tables to various formats.

use std::str::FromStr;
use std::error::Error;
use std::fmt;
use std::vec::IntoIter;
use std;

/// A data table consisting of varying column types and headers.
pub struct DataTable {
    /// Vector of DataColumns.
    pub data_cols: Vec<DataColumn>,
}

impl DataTable {
    /// Constructs an empty DataTable
    pub fn empty() -> DataTable {
        DataTable { data_cols: Vec::new() }
    }

    /// The number of columns in the DataTable.
    pub fn cols(&self) -> usize {
        self.data_cols.len()
    }

    /// The number of rows in the DataTable.
    pub fn rows(&self) -> usize {
        if self.data_cols.len() > 0 {
            return self.data_cols[0].len();
        }

        0usize
    }

    /// Shrinks the table and it's underlying columns.
    pub fn shrink_to_fit(&mut self) {
        for col in self.data_cols.iter_mut() {
            col.shrink_to_fit();
        }

        self.data_cols.shrink_to_fit();
    }

    /// Consumes self and attempts to convert the DataTable into a single Vec.
    ///
    /// Uses column major ordering.
    ///
    /// # Failures
    ///
    /// - DataCastError : Returned when the data cannot be cast into the requested type.
    pub fn into_consistent_data<T: FromStr>(self) -> Result<Vec<T>, DataError> {
        let mut table_data = Vec::with_capacity(self.cols() * self.rows());
        for d in self.data_cols.into_iter() {
            match d.into_vec() {
                Ok(x) => table_data.extend(x),
                Err(e) => return Err(e),
            }
        }

        Ok(table_data)
    }

    /// Attempts to convert the DataTable into a single Vec.
    ///
    /// Uses column major ordering. Returns an Option.
    pub fn consistent_data<T: FromStr>(&self) -> Option<Vec<T>> {
        let mut table_data = Vec::with_capacity(self.cols() * self.rows());
        for d in self.data_cols.iter() {
            match d.cast() {
                Some(x) => table_data.extend(x),
                None => return None,
            }
        }

        Some(table_data)
    }
}

/// Errors related to Data functions.
#[derive(Debug)]
pub enum DataError {
    /// An error for attempting to cast data types within DataTable.
    DataCastError,
}

impl fmt::Display for DataError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &DataError::DataCastError => write!(f, "DataCastError"),
        }
    }
}

impl Error for DataError {
    fn description(&self) -> &str {
        match self {
            &DataError::DataCastError => "Failed to cast data.",
        }
    }
}

/// A data column consisting of Strings.
pub struct DataColumn {
    /// The name associated with the DataColumn.
    pub name: Option<String>,
    data: Vec<String>,
}

impl DataColumn {
    /// Constructs an empty data column.
    pub fn empty() -> DataColumn {
        DataColumn {
            name: None,
            data: Vec::new(),
        }
    }

    /// Gets the length of the data column.
    pub fn len(&self) -> usize {
        self.data.len()
    }

    /// Gets an immutable reference to the underlying data.
    pub fn data(&self) -> &Vec<String> {
        &self.data
    }

    /// Pushes a new &str to the column.
    pub fn push(&mut self, val: &str) {
        self.data.push(val.to_owned());
    }

    pub fn get_as<T: FromStr>(&self, idx: usize) -> Result<T, DataError> {
        match T::from_str(self.data[idx].as_ref()) {
            Ok(x) => Ok(x),
            Err(_) => Err(DataError::DataCastError),
        }
    }

    /// Shrink the column to fit the data.
    pub fn shrink_to_fit(&mut self) {
        self.data.shrink_to_fit();
    }

    /// Consumes self and returns a Vec of the requested type.
    ///
    /// # Failures
    ///
    /// - DataCastError : Returned when the data cannot be parsed to the requested type.
    pub fn into_vec<T: FromStr>(self) -> Result<Vec<T>, DataError> {
        let mut casted_data = Vec::<T>::with_capacity(self.data.len());

        for d in self.data.into_iter() {
            match T::from_str(d.as_ref()) {
                Ok(x) => casted_data.push(x),
                Err(_) => return Err(DataError::DataCastError),
            }
        }

        Ok(casted_data)
    }

    /// Cast the data to the requested type.
    ///
    /// Returns a Vec of the requested type wrapped in an option.
    pub fn cast<T: FromStr>(&self) -> Option<Vec<T>> {
        let mut casted_data = Vec::<T>::with_capacity(self.data.len());

        for d in self.data.iter() {
            match T::from_str(&d[..]) {
                Ok(x) => casted_data.push(x),
                Err(_) => return None,
            }
        }

        Some(casted_data)
    }

    /// Consumes self and returns an iterator which parses
    /// the data to the specified type returning results.
    ///
    /// The iterator will return a result on `next()` detailing
    /// the outcome of the parse.
    pub fn into_iter_cast<U: FromStr>
        (self)
         -> std::iter::Map<IntoIter<String>, fn(String) -> Result<U, <U as FromStr>::Err>>
        where U: FromStr
    {
        from_str_iter::<_, U>(self.data.into_iter())
    }
}

/// Converts the iterator to a FromStr iterator.
fn from_str_iter<I, U>
    (iter: I)
     -> std::iter::Map<I, fn(<I as Iterator>::Item) -> Result<U, <U as FromStr>::Err>>
    where I: Iterator,
          <I as Iterator>::Item: AsRef<str>,
          U: FromStr
{
    fn from_str_fn<T, U>(item: T) -> Result<U, <U as FromStr>::Err>
        where T: AsRef<str>,
              U: FromStr
    {
        FromStr::from_str(item.as_ref())
    }
    iter.map(from_str_fn)
}
<|endoftext|>