<commit_before>use alloc::arc::Arc;
use alloc::boxed::Box;
use collections::{BTreeMap, Vec, VecDeque};
use spin::Mutex;

use arch;
use syscall::data::Event;
use super::file::File;
use super::memory::{Grant, Memory, SharedMemory};

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Status {
    Runnable,
    Blocked,
    Exited(usize)
}

/// A context, which identifies either a process or a thread
#[derive(Debug)]
pub struct Context {
    /// The ID of this context
    pub id: usize,
    /// Status of context
    pub status: Status,
    /// Context running or not
    pub running: bool,
    /// The architecture specific context
    pub arch: arch::context::Context,
    /// Kernel FX
    pub kfx: Option<Box<[u8]>>,
    /// Kernel stack
    pub kstack: Option<Box<[u8]>>,
    /// Executable image
    pub image: Vec<SharedMemory>,
    /// User heap
    pub heap: Option<SharedMemory>,
    /// User stack
    pub stack: Option<Memory>,
    /// User grants
    pub grants: Arc<Mutex<Vec<Grant>>>,
    /// The current working directory
    pub cwd: Arc<Mutex<Vec<u8>>>,
    /// Kernel events
    pub events: Arc<Mutex<VecDeque<Event>>>,
    /// The process environment
    pub env: Arc<Mutex<BTreeMap<Box<[u8]>, Arc<Mutex<Vec<u8>>>>>>,
    /// The open files in the scheme
    pub files: Arc<Mutex<Vec<Option<File>>>>
}

impl Context {
    /// Create a new context
    pub fn new(id: usize) -> Context {
        Context {
            id: id,
            status: Status::Blocked,
            running: false,
            arch: arch::context::Context::new(),
            kfx: None,
            kstack: None,
            image: Vec::new(),
            heap: None,
            stack: None,
            grants: Arc::new(Mutex::new(Vec::new())),
            cwd: Arc::new(Mutex::new(Vec::new())),
            events: Arc::new(Mutex::new(VecDeque::new())),
            env: Arc::new(Mutex::new(BTreeMap::new())),
            files: Arc::new(Mutex::new(Vec::new()))
        }
    }

    pub fn canonicalize(&self, path: &[u8]) -> Vec<u8> {
        if path.iter().position(|&b| b == b':').is_none() {
            let cwd = self.cwd.lock();
            if path == b"." {
                cwd.clone()
            } else if path == b".." {
                cwd[..cwd[..cwd.len() - 1]
                                   .iter().rposition(|&b| b == b'/' || b == b':')
                                   .map_or(cwd.len(), |i| i + 1)]
                   .to_vec()
            } else if path.starts_with(b"./") {
                let mut canon = cwd.clone();
                canon.extend_from_slice(&path[2..]);
                canon
            } else if path.starts_with(b"../") {
                let mut canon = cwd[..cwd[..cwd.len() - 1]
                                   .iter().rposition(|&b| b == b'/' || b == b':')
                                   .map_or(cwd.len(), |i| i + 1)]
                   .to_vec();
                canon.extend_from_slice(&path[3..]);
                canon
            } else if path.starts_with(b"/") {
                let mut canon = cwd[..cwd.iter().position(|&b| b == b':').map_or(1, |i| i + 1)].to_vec();
                canon.extend_from_slice(&path);
                canon
            } else {
                let mut canon = cwd.clone();
                canon.extend_from_slice(&path);
                canon
            }
        } else {
            path.to_vec()
        }
    }

    /// Add a file to the lowest available slot.
    /// Return the file descriptor number or None if no slot was found
    pub fn add_file(&self, file: File) -> Option<usize> {
        let mut files = self.files.lock();
        for (i, mut file_option) in files.iter_mut().enumerate() {
            if file_option.is_none() {
                *file_option = Some(file);
                return Some(i);
            }
        }
        let len = files.len();
        if len < super::CONTEXT_MAX_FILES {
            files.push(Some(file));
            Some(len)
        } else {
            None
        }
    }

    /// Get a file
    pub fn get_file(&self, i: usize) -> Option<File> {
        let files = self.files.lock();
        if i < files.len() {
            files[i]
        } else {
            None
        }
    }

    /// Remove a file
    // TODO: adjust files vector to smaller size if possible
    pub fn remove_file(&self, i: usize) -> Option<File> {
        let mut files = self.files.lock();
        if i < files.len() {
            files[i].take()
        } else {
            None
        }
    }
}
<commit_msg>Fix CWD without trainling slash<commit_after>use alloc::arc::Arc;
use alloc::boxed::Box;
use collections::{BTreeMap, Vec, VecDeque};
use spin::Mutex;

use arch;
use syscall::data::Event;
use super::file::File;
use super::memory::{Grant, Memory, SharedMemory};

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Status {
    Runnable,
    Blocked,
    Exited(usize)
}

/// A context, which identifies either a process or a thread
#[derive(Debug)]
pub struct Context {
    /// The ID of this context
    pub id: usize,
    /// Status of context
    pub status: Status,
    /// Context running or not
    pub running: bool,
    /// The architecture specific context
    pub arch: arch::context::Context,
    /// Kernel FX
    pub kfx: Option<Box<[u8]>>,
    /// Kernel stack
    pub kstack: Option<Box<[u8]>>,
    /// Executable image
    pub image: Vec<SharedMemory>,
    /// User heap
    pub heap: Option<SharedMemory>,
    /// User stack
    pub stack: Option<Memory>,
    /// User grants
    pub grants: Arc<Mutex<Vec<Grant>>>,
    /// The current working directory
    pub cwd: Arc<Mutex<Vec<u8>>>,
    /// Kernel events
    pub events: Arc<Mutex<VecDeque<Event>>>,
    /// The process environment
    pub env: Arc<Mutex<BTreeMap<Box<[u8]>, Arc<Mutex<Vec<u8>>>>>>,
    /// The open files in the scheme
    pub files: Arc<Mutex<Vec<Option<File>>>>
}

impl Context {
    /// Create a new context
    pub fn new(id: usize) -> Context {
        Context {
            id: id,
            status: Status::Blocked,
            running: false,
            arch: arch::context::Context::new(),
            kfx: None,
            kstack: None,
            image: Vec::new(),
            heap: None,
            stack: None,
            grants: Arc::new(Mutex::new(Vec::new())),
            cwd: Arc::new(Mutex::new(Vec::new())),
            events: Arc::new(Mutex::new(VecDeque::new())),
            env: Arc::new(Mutex::new(BTreeMap::new())),
            files: Arc::new(Mutex::new(Vec::new()))
        }
    }

    pub fn canonicalize(&self, path: &[u8]) -> Vec<u8> {
        if path.iter().position(|&b| b == b':').is_none() {
            let cwd = self.cwd.lock();
            if path == b"." {
                cwd.clone()
            } else if path == b".." {
                cwd[..cwd[..cwd.len() - 1]
                                   .iter().rposition(|&b| b == b'/' || b == b':')
                                   .map_or(cwd.len(), |i| i + 1)]
                   .to_vec()
            } else if path.starts_with(b"./") {
                let mut canon = cwd.clone();
                canon.extend_from_slice(&path[2..]);
                canon
            } else if path.starts_with(b"../") {
                let mut canon = cwd[..cwd[..cwd.len() - 1]
                                   .iter().rposition(|&b| b == b'/' || b == b':')
                                   .map_or(cwd.len(), |i| i + 1)]
                   .to_vec();
                canon.extend_from_slice(&path[3..]);
                canon
            } else if path.starts_with(b"/") {
                let mut canon = cwd[..cwd.iter().position(|&b| b == b':').map_or(1, |i| i + 1)].to_vec();
                canon.extend_from_slice(&path);
                canon
            } else {
                let mut canon = cwd.clone();
                if ! canon.ends_with(b"/") {
                    canon.push(b'/');
                }
                canon.extend_from_slice(&path);
                canon
            }
        } else {
            path.to_vec()
        }
    }

    /// Add a file to the lowest available slot.
    /// Return the file descriptor number or None if no slot was found
    pub fn add_file(&self, file: File) -> Option<usize> {
        let mut files = self.files.lock();
        for (i, mut file_option) in files.iter_mut().enumerate() {
            if file_option.is_none() {
                *file_option = Some(file);
                return Some(i);
            }
        }
        let len = files.len();
        if len < super::CONTEXT_MAX_FILES {
            files.push(Some(file));
            Some(len)
        } else {
            None
        }
    }

    /// Get a file
    pub fn get_file(&self, i: usize) -> Option<File> {
        let files = self.files.lock();
        if i < files.len() {
            files[i]
        } else {
            None
        }
    }

    /// Remove a file
    // TODO: adjust files vector to smaller size if possible
    pub fn remove_file(&self, i: usize) -> Option<File> {
        let mut files = self.files.lock();
        if i < files.len() {
            files[i].take()
        } else {
            None
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};
use std::os;
use std::str;

use core::{Package, PackageId, PackageSet, Resolve, Target};
use util;
use util::{CargoResult, ChainError, internal, Config};

use super::layout::{Layout, LayoutProxy};

#[deriving(Show)]
pub enum PlatformRequirement {
    Target,
    Plugin,
    PluginAndTarget,
}

pub struct Context<'a, 'b> {
    pub primary: bool,
    pub rustc_version: String,
    pub config: &'b mut Config<'b>,
    pub resolve: &'a Resolve,

    env: &'a str,
    host: Layout,
    target: Option<Layout>,
    host_dylib: (String, String),
    package_set: &'a PackageSet,
    target_dylib: (String, String),
    target_exe: String,
    requirements: HashMap<(&'a PackageId, &'a str), PlatformRequirement>,
}

impl<'a, 'b> Context<'a, 'b> {
    pub fn new(env: &'a str, resolve: &'a Resolve, deps: &'a PackageSet,
               config: &'b mut Config<'b>,
               host: Layout, target: Option<Layout>)
               -> CargoResult<Context<'a, 'b>> {
        let (target_dylib, target_exe) =
                try!(Context::filename_parts(config.target()));
        let host_dylib = if config.target().is_none() {
            target_dylib.clone()
        } else {
            let (dylib, _) = try!(Context::filename_parts(None));
            dylib
        };
        Ok(Context {
            rustc_version: try!(Context::rustc_version()),
            env: env,
            host: host,
            target: target,
            primary: false,
            resolve: resolve,
            package_set: deps,
            config: config,
            target_dylib: target_dylib,
            target_exe: target_exe,
            host_dylib: host_dylib,
            requirements: HashMap::new(),
        })
    }

    /// Run `rustc` to figure out what its current version string is
    fn rustc_version() -> CargoResult<String> {
        let output = try!(util::process("rustc").arg("-v").arg("verbose")
                               .exec_with_output());
        Ok(String::from_utf8(output.output).unwrap())
    }

    /// Run `rustc` to discover the dylib prefix/suffix for the target
    /// specified as well as the exe suffix
    fn filename_parts(target: Option<&str>)
                      -> CargoResult<((String, String), String)> {
        let process = util::process("rustc")
                           .arg("-")
                           .arg("--crate-name").arg("-")
                           .arg("--crate-type").arg("dylib")
                           .arg("--print-file-name");
        let process = match target {
            Some(s) => process.arg("--target").arg(s),
            None => process,
        };
        let output = try!(process.exec_with_output());

        let output = str::from_utf8(output.output.as_slice()).unwrap();
        let dylib_parts: Vec<&str> = output.trim().split('-').collect();
        assert!(dylib_parts.len() == 2,
                "rustc --print-file-name output has changed");
        let exe_suffix = match target {
            None => os::consts::EXE_SUFFIX,
            Some(s) if s.contains("win32") || s.contains("windows") => ".exe",
            Some(_) => "",
        };

        Ok(((dylib_parts[0].to_string(), dylib_parts[1].to_string()),
            exe_suffix.to_string()))
    }

    /// Prepare this context, ensuring that all filesystem directories are in
    /// place.
    pub fn prepare(&mut self, pkg: &'a Package) -> CargoResult<()> {
        try!(self.host.prepare().chain_error(|| {
            internal(format!("couldn't prepare build directories for `{}`",
                             pkg.get_name()))
        }));
        match self.target {
            Some(ref mut target) => {
                try!(target.prepare().chain_error(|| {
                    internal(format!("couldn't prepare build directories \
                                      for `{}`", pkg.get_name()))
                }));
            }
            None => {}
        }

        let targets = pkg.get_targets().iter();
        for target in targets.filter(|t| t.get_profile().is_compile()) {
            self.build_requirements(pkg, target, Target, &mut HashSet::new());
        }

        Ok(())
    }

    fn build_requirements(&mut self, pkg: &'a Package, target: &'a Target,
                          req: PlatformRequirement,
                          visiting: &mut HashSet<&'a PackageId>) {
        if !visiting.insert(pkg.get_package_id()) { return }

        let key = (pkg.get_package_id(), target.get_name());
        let req = if target.get_profile().is_plugin() {Plugin} else {req};
        self.requirements.insert_or_update_with(key, req, |_, v| {
            *v = v.combine(req);
        });

        for &(pkg, dep) in self.dep_targets(pkg).iter() {
            self.build_requirements(pkg, dep, req, visiting);
        }

        visiting.remove(&pkg.get_package_id());
    }

    pub fn get_requirement(&self, pkg: &'a Package,
                           target: &'a Target) -> PlatformRequirement {
        self.requirements.find(&(pkg.get_package_id(), target.get_name()))
            .map(|a| *a).unwrap_or(Target)
    }

    /// Switch this context over to being the primary compilation unit,
    /// affecting the output of `dest()` and such.
    pub fn primary(&mut self) {
        self.primary = true;
    }

    /// Returns the appropriate directory layout for either a plugin or not.
    pub fn layout<'a>(&'a self, plugin: bool) -> LayoutProxy<'a> {
        if plugin {
            LayoutProxy::new(&self.host, self.primary)
        } else {
            LayoutProxy::new(self.target.as_ref().unwrap_or(&self.host),
                             self.primary)
        }
    }

    /// Return the (prefix, suffix) pair for dynamic libraries.
    ///
    /// If `plugin` is true, the pair corresponds to the host platform,
    /// otherwise it corresponds to the target platform.
    fn dylib<'a>(&'a self, plugin: bool) -> (&'a str, &'a str) {
        let pair = if plugin {&self.host_dylib} else {&self.target_dylib};
        (pair.ref0().as_slice(), pair.ref1().as_slice())
    }

    /// Return the exact filename of the target.
    pub fn target_filenames(&self, target: &Target) -> Vec<String> {
        let stem = target.file_stem();

        let mut ret = Vec::new();
        if target.is_dylib() {
            let (prefix, suffix) = self.dylib(target.get_profile().is_plugin());
            ret.push(format!("{}{}{}", prefix, stem, suffix));
        }
        if target.is_rlib() {
            ret.push(format!("lib{}.rlib", stem));
        }
        if target.is_bin() {
            ret.push(format!("{}{}", stem, self.target_exe));
        }
        assert!(ret.len() > 0);
        return ret;
    }

    /// For a package, return all targets which are registered as dependencies
    /// for that package.
    pub fn dep_targets(&self, pkg: &Package) -> Vec<(&'a Package, &'a Target)> {
        let deps = match self.resolve.deps(pkg.get_package_id()) {
            None => return vec!(),
            Some(deps) => deps,
        };
        deps.map(|pkg_id| self.get_package(pkg_id))
        .filter_map(|pkg| {
            pkg.get_targets().iter().find(|&t| self.is_relevant_target(t))
               .map(|t| (pkg, t))
        })
        .collect()
    }

    /// Gets a package for the given package id.
    pub fn get_package(&self, id: &PackageId) -> &'a Package {
        self.package_set.iter()
            .find(|pkg| id == pkg.get_package_id())
            .expect("Should have found package")
    }

    pub fn is_relevant_target(&self, target: &Target) -> bool {
        target.is_lib() && match self.env {
            "test" => target.get_profile().is_compile(),
            _ => target.get_profile().get_env() == self.env,
        }
    }
}

impl PlatformRequirement {
    fn combine(self, other: PlatformRequirement) -> PlatformRequirement {
        match (self, other) {
            (Target, Target) => Target,
            (Plugin, Plugin) => Plugin,
            _ => PluginAndTarget,
        }
    }
}
<commit_msg>Fix failure on second run of 'cargo test'<commit_after>use std::collections::{HashMap, HashSet};
use std::os;
use std::str;

use core::{Package, PackageId, PackageSet, Resolve, Target};
use util;
use util::{CargoResult, ChainError, internal, Config};

use super::layout::{Layout, LayoutProxy};

#[deriving(Show)]
pub enum PlatformRequirement {
    Target,
    Plugin,
    PluginAndTarget,
}

pub struct Context<'a, 'b> {
    pub primary: bool,
    pub rustc_version: String,
    pub config: &'b mut Config<'b>,
    pub resolve: &'a Resolve,

    env: &'a str,
    host: Layout,
    target: Option<Layout>,
    host_dylib: (String, String),
    package_set: &'a PackageSet,
    target_dylib: (String, String),
    target_exe: String,
    requirements: HashMap<(&'a PackageId, &'a str), PlatformRequirement>,
}

impl<'a, 'b> Context<'a, 'b> {
    pub fn new(env: &'a str, resolve: &'a Resolve, deps: &'a PackageSet,
               config: &'b mut Config<'b>,
               host: Layout, target: Option<Layout>)
               -> CargoResult<Context<'a, 'b>> {
        let (target_dylib, target_exe) =
                try!(Context::filename_parts(config.target()));
        let host_dylib = if config.target().is_none() {
            target_dylib.clone()
        } else {
            let (dylib, _) = try!(Context::filename_parts(None));
            dylib
        };
        Ok(Context {
            rustc_version: try!(Context::rustc_version()),
            env: env,
            host: host,
            target: target,
            primary: false,
            resolve: resolve,
            package_set: deps,
            config: config,
            target_dylib: target_dylib,
            target_exe: target_exe,
            host_dylib: host_dylib,
            requirements: HashMap::new(),
        })
    }

    /// Run `rustc` to figure out what its current version string is
    fn rustc_version() -> CargoResult<String> {
        let output = try!(util::process("rustc").arg("-v").arg("verbose")
                               .exec_with_output());
        Ok(String::from_utf8(output.output).unwrap())
    }

    /// Run `rustc` to discover the dylib prefix/suffix for the target
    /// specified as well as the exe suffix
    fn filename_parts(target: Option<&str>)
                      -> CargoResult<((String, String), String)> {
        let process = util::process("rustc")
                           .arg("-")
                           .arg("--crate-name").arg("-")
                           .arg("--crate-type").arg("dylib")
                           .arg("--print-file-name");
        let process = match target {
            Some(s) => process.arg("--target").arg(s),
            None => process,
        };
        let output = try!(process.exec_with_output());

        let output = str::from_utf8(output.output.as_slice()).unwrap();
        let dylib_parts: Vec<&str> = output.trim().split('-').collect();
        assert!(dylib_parts.len() == 2,
                "rustc --print-file-name output has changed");
        let exe_suffix = match target {
            None => os::consts::EXE_SUFFIX,
            Some(s) if s.contains("win32") || s.contains("windows") => ".exe",
            Some(_) => "",
        };

        Ok(((dylib_parts[0].to_string(), dylib_parts[1].to_string()),
            exe_suffix.to_string()))
    }

    /// Prepare this context, ensuring that all filesystem directories are in
    /// place.
    pub fn prepare(&mut self, pkg: &'a Package) -> CargoResult<()> {
        try!(self.host.prepare().chain_error(|| {
            internal(format!("couldn't prepare build directories for `{}`",
                             pkg.get_name()))
        }));
        match self.target {
            Some(ref mut target) => {
                try!(target.prepare().chain_error(|| {
                    internal(format!("couldn't prepare build directories \
                                      for `{}`", pkg.get_name()))
                }));
            }
            None => {}
        }

        let targets = pkg.get_targets().iter();
        for target in targets.filter(|t| t.get_profile().is_compile()) {
            self.build_requirements(pkg, target, Target, &mut HashSet::new());
        }

        Ok(())
    }

    fn build_requirements(&mut self, pkg: &'a Package, target: &'a Target,
                          req: PlatformRequirement,
                          visiting: &mut HashSet<&'a PackageId>) {
        if !visiting.insert(pkg.get_package_id()) { return }

        let key = (pkg.get_package_id(), target.get_name());
        let req = if target.get_profile().is_plugin() {Plugin} else {req};
        self.requirements.insert_or_update_with(key, req, |_, v| {
            *v = v.combine(req);
        });

        for &(pkg, dep) in self.dep_targets(pkg).iter() {
            self.build_requirements(pkg, dep, req, visiting);
        }

        visiting.remove(&pkg.get_package_id());
    }

    pub fn get_requirement(&self, pkg: &'a Package,
                           target: &'a Target) -> PlatformRequirement {
        self.requirements.find(&(pkg.get_package_id(), target.get_name()))
            .map(|a| *a).unwrap_or(Target)
    }

    /// Switch this context over to being the primary compilation unit,
    /// affecting the output of `dest()` and such.
    pub fn primary(&mut self) {
        self.primary = true;
    }

    /// Returns the appropriate directory layout for either a plugin or not.
    pub fn layout<'a>(&'a self, plugin: bool) -> LayoutProxy<'a> {
        if plugin {
            LayoutProxy::new(&self.host, self.primary)
        } else {
            LayoutProxy::new(self.target.as_ref().unwrap_or(&self.host),
                             self.primary)
        }
    }

    /// Return the (prefix, suffix) pair for dynamic libraries.
    ///
    /// If `plugin` is true, the pair corresponds to the host platform,
    /// otherwise it corresponds to the target platform.
    fn dylib<'a>(&'a self, plugin: bool) -> (&'a str, &'a str) {
        let pair = if plugin {&self.host_dylib} else {&self.target_dylib};
        (pair.ref0().as_slice(), pair.ref1().as_slice())
    }

    /// Return the exact filename of the target.
    pub fn target_filenames(&self, target: &Target) -> Vec<String> {
        let stem = target.file_stem();

        let mut ret = Vec::new();
        if target.is_dylib() {
            let (prefix, suffix) = self.dylib(target.get_profile().is_plugin());
            ret.push(format!("{}{}{}", prefix, stem, suffix));
        }
        if target.is_rlib() {
            if target.get_profile().is_test() {
                ret.push(format!("{}{}", stem, self.target_exe));
            } else {
                ret.push(format!("lib{}.rlib", stem));
            }
        }
        if target.is_bin() {
            ret.push(format!("{}{}", stem, self.target_exe));
        }
        assert!(ret.len() > 0);
        return ret;
    }

    /// For a package, return all targets which are registered as dependencies
    /// for that package.
    pub fn dep_targets(&self, pkg: &Package) -> Vec<(&'a Package, &'a Target)> {
        let deps = match self.resolve.deps(pkg.get_package_id()) {
            None => return vec!(),
            Some(deps) => deps,
        };
        deps.map(|pkg_id| self.get_package(pkg_id))
        .filter_map(|pkg| {
            pkg.get_targets().iter().find(|&t| self.is_relevant_target(t))
               .map(|t| (pkg, t))
        })
        .collect()
    }

    /// Gets a package for the given package id.
    pub fn get_package(&self, id: &PackageId) -> &'a Package {
        self.package_set.iter()
            .find(|pkg| id == pkg.get_package_id())
            .expect("Should have found package")
    }

    pub fn is_relevant_target(&self, target: &Target) -> bool {
        target.is_lib() && match self.env {
            "test" => target.get_profile().is_compile(),
            _ => target.get_profile().get_env() == self.env,
        }
    }
}

impl PlatformRequirement {
    fn combine(self, other: PlatformRequirement) -> PlatformRequirement {
        match (self, other) {
            (Target, Target) => Target,
            (Plugin, Plugin) => Plugin,
            _ => PluginAndTarget,
        }
    }
}
<|endoftext|>


<commit_before>use std;
use std::collections::BTreeMap;
use std::default::Default;
use std::fs::File;
use std::io::{Read, Write};
use std::path::{Path, PathBuf};

use digest::Digest;
use ignore::WalkBuilder;
use serde_bytes;
use serde_cbor;
use serde_json;

use sha2;
use sha3;

use error;

#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
pub struct Database(BTreeMap<PathBuf, Entry>);

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum Entry {
    File(HashSums),
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct HashSums {
    sha2: HashSum,
    sha3: HashSum,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct HashSum(#[serde(with = "serde_bytes")] Vec<u8>);

#[derive(Default)]
struct Hashers {
    sha2: sha2::Sha256,
    sha3: sha3::Sha3_256,
}

impl Hashers {
    fn input(&mut self, input: &[u8]) {
        self.sha2.input(input);
        self.sha3.input(input);
    }
    fn result(self) -> HashSums {
        HashSums {
            sha2: HashSum(Vec::from(self.sha2.result().as_slice())),
            sha3: HashSum(Vec::from(self.sha3.result().as_slice())),
        }
    }
}

fn compute_hashes<P>(path: P) -> Result<HashSums, error::Error>
where
    P: AsRef<Path>
{
    let mut f = File::open(path)?;

    let mut hashers = Hashers::default();

    let mut buffer = [0; 4096];
    loop {
        let n = f.read(&mut buffer[..])?;
        if n == 0 { break }
        hashers.input(&buffer[0..n]);
    }
    Ok(hashers.result())
}

impl Database {
    fn insert(&mut self, path: PathBuf, entry: Entry) {
        self.0.insert(path, entry);
    }

    pub fn build<P>(path: P) -> Result<Database, error::Error>
    where
        P: AsRef<Path>
    {
        let mut database = Database::default();
        for entry in WalkBuilder::new(&path).build() {
            let entry = entry?;
            if entry.file_type().map_or(false, |t| t.is_file()) {
                let hashes = compute_hashes(entry.path())?;
                let result = Entry::File(hashes);
                let short_path = entry.path().strip_prefix(&path)?;
                database.insert(short_path.to_owned(), result);
            }
        }
        Ok(database)
    }

    pub fn dump_json<P>(&self, path: P) -> Result<(), error::Error>
    where
        P: AsRef<Path>
    {
        let json = serde_json::to_string(self)?;
        let mut f = File::create(path)?;
        write!(f, "{}", json)?;
        Ok(())
    }

    pub fn dump_cbor<P>(&self, path: P) -> Result<(), error::Error>
    where
        P: AsRef<Path>
    {
        let cbor = serde_cbor::to_vec(self)?;
        let mut f = File::create(path)?;
        f.write_all(cbor.as_slice())?;
        Ok(())
    }
}

impl std::fmt::Display for Database {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        for (path, entry) in self.0.iter() {
            match entry {
                &Entry::File(ref hashes) => {
                    let hash: Vec<_> = hashes.sha2.0.iter().map(
                        |b| format!("{:02x}", b)).collect();
                    writeln!(f, "{} {}", hash.join(""), Path::new(path).display())?
                }
            }
        }
        Ok(())
    }
}
<commit_msg>Switch database to a tree that matches the directory structure.<commit_after>use std::collections::BTreeMap;
use std::default::Default;
use std::fs::File;
use std::io::{Read, Write};
use std::path::{Path, PathBuf};

use digest::Digest;
use ignore::WalkBuilder;
use serde_bytes;
use serde_cbor;
use serde_json;

use sha2;
use sha3;

use error;

#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
pub struct Database(Entry);

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum Entry {
    Directory(BTreeMap<PathBuf, Entry>),
    File(HashSums),
}

impl Default for Entry {
    fn default() -> Entry {
        Entry::Directory(BTreeMap::default())
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct HashSums {
    sha2: HashSum,
    sha3: HashSum,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct HashSum(#[serde(with = "serde_bytes")] Vec<u8>);

#[derive(Default)]
struct Hashers {
    sha2: sha2::Sha256,
    sha3: sha3::Sha3_256,
}

impl Hashers {
    fn input(&mut self, input: &[u8]) {
        self.sha2.input(input);
        self.sha3.input(input);
    }
    fn result(self) -> HashSums {
        HashSums {
            sha2: HashSum(Vec::from(self.sha2.result().as_slice())),
            sha3: HashSum(Vec::from(self.sha3.result().as_slice())),
        }
    }
}

fn compute_hashes<P>(path: P) -> Result<HashSums, error::Error>
where
    P: AsRef<Path>
{
    let mut f = File::open(path)?;

    let mut hashers = Hashers::default();

    let mut buffer = [0; 4096];
    loop {
        let n = f.read(&mut buffer[..])?;
        if n == 0 { break }
        hashers.input(&buffer[0..n]);
    }
    Ok(hashers.result())
}

trait BTreeMapExt<K, V> where K: Ord, V: Default {
    fn get_mut_default(&mut self, key: K) -> &mut V;
}

impl<K, V> BTreeMapExt<K, V> for BTreeMap<K, V>
where
    K: Ord + Clone,
    V: Default,
{
    fn get_mut_default(&mut self, key: K) -> &mut V {
        if self.contains_key(&key) {
            match self.get_mut(&key) {
                Some(value) => value,
                None => unreachable!(), // Already checked that key exists
            }
        } else {
            {
                // FIXME: Would prefer to avoid the clone
                match self.insert(key.clone(), V::default()) {
                    Some(_) => unreachable!(), // Already checked for key
                    None => (),
                }
            }
            {
                match self.get_mut(&key) {
                    Some(value) => value,
                    None => unreachable!(), // Already checked that key exists
                }
            }
        }
    }
}

impl Entry {
    fn insert(&mut self, path: PathBuf, file: Entry) {
        // Inner nodes in the tree should always be directories. If
        // the node is not a directory, that means we are inserting a
        // duplicate file. However, this function is only called from
        // the directory walker, which makes it impossible to observe
        // any duplicates. (And the database, after construction, is
        // always immutable.)
        match self {
            &mut Entry::Directory(ref mut entries) => {
                let mut components = path.components();
                let count = components.clone().count();
                let first = Path::new(components.next().expect("unreachable").as_os_str()).to_owned();
                let rest = components.as_path().to_owned();
                if count > 1 {
                    let mut subentry = entries.get_mut_default(first);
                    subentry.insert(rest, file);
                } else {
                    match entries.insert(first, file) {
                        Some(_) => unreachable!(), // See above
                        None => (),
                    }
                }
            }
            &mut Entry::File(_) => unreachable!()
        }
    }
}

impl Database {
    fn insert(&mut self, path: PathBuf, entry: Entry) {
        self.0.insert(path, entry);
    }

    pub fn build<P>(path: P) -> Result<Database, error::Error>
    where
        P: AsRef<Path>
    {
        let mut database = Database::default();
        for entry in WalkBuilder::new(&path).build() {
            let entry = entry?;
            if entry.file_type().map_or(false, |t| t.is_file()) {
                let hashes = compute_hashes(entry.path())?;
                let result = Entry::File(hashes);
                let short_path = entry.path().strip_prefix(&path)?;
                database.insert(short_path.to_owned(), result);
            }
        }
        Ok(database)
    }

    pub fn dump_json<P>(&self, path: P) -> Result<(), error::Error>
    where
        P: AsRef<Path>
    {
        let json = serde_json::to_string(self)?;
        let mut f = File::create(path)?;
        write!(f, "{}", json)?;
        Ok(())
    }

    pub fn dump_cbor<P>(&self, path: P) -> Result<(), error::Error>
    where
        P: AsRef<Path>
    {
        let cbor = serde_cbor::to_vec(self)?;
        let mut f = File::create(path)?;
        f.write_all(cbor.as_slice())?;
        Ok(())
    }
}

// impl std::fmt::Display for Database {
//     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
//         for (path, entry) in self.0.iter() {
//             match entry {
//                 &Entry::File(ref hashes) => {
//                     let hash: Vec<_> = hashes.sha2.0.iter().map(
//                         |b| format!("{:02x}", b)).collect();
//                     writeln!(f, "{} {}", hash.join(""), Path::new(path).display())?
//                 }
//             }
//         }
//         Ok(())
//     }
// }
<|endoftext|>


<commit_before>use std::io::{File, BufferedReader};
use std::io::SeekStyle::SeekSet;
use error::{CTResult, CTDatabaseError, CTSyntaxError};
use error::CTError::{DatabaseError, SyntaxError};
use token::Token;
use token::TokenKind::Elem;

#[derive(Show, PartialEq)]
pub struct ElemData {
    short_name: String,
    long_name: String,
    mass: f64,
    atomic_num: u16,
}

pub struct ElemDatabase {
    db: BufferedReader<File>,
}

impl ElemDatabase {
    pub fn open(path: &str) -> CTResult<ElemDatabase> {
        match File::open(&Path::new(path)) {
            Ok(db_file) => Ok(ElemDatabase { db: BufferedReader::new(db_file) }),
            Err(_) => Err(DatabaseError(CTDatabaseError {
                desc: format!("Could not open database file. Expected at: {:?}", path)
            })),
        }
    }

    pub fn get_single_data(&mut self, elem: &Token) -> CTResult<ElemData> {
        // we return to the beginning of the underlying file, since the data
        // might lie on a line we have previously read past
        self.db.get_mut().seek(0, SeekSet).ok().expect("Internal error reading database");
        let mut line_iter = self.db.lines();
        let short_name = match elem.tok {
            Elem(ref name) => name.as_slice(),
            _ => unreachable!(),
        };
        // TODO: Make this cleaner, and avoid returns
        loop {
            match line_iter.next() {
                Some(Ok(ref line)) if line.starts_with(short_name) => return decode_line(line),
                Some(Err(_)) => return Err(DatabaseError(CTDatabaseError {
                    desc: "Error reading the database".to_string()
                })),
                None => return Err(SyntaxError(CTSyntaxError {
                    desc: format!("Could not find element: {:?}", short_name),
                    pos: elem.pos,
                    len: elem.len,
                })),
                _ => (),
            }
        }
    }
}

pub fn decode_line(line: &String) -> CTResult<ElemData> {
    let data: Vec<&str> = line.trim().split(';').collect();
    if data.len() < 4 {
        Err(DatabaseError(CTDatabaseError {
            desc: "Missing field in database".to_string()
        }))
    } else {
        let mass = data[1].parse::<f64>();
        let atomic_num = data[3].parse::<u16>();
        if let (Some(m), Some(an)) = (mass, atomic_num) {
            Ok(ElemData {
                short_name: data[0].to_string(),
                long_name: data[2].to_string(),
                mass: m,
                atomic_num: an,
            })
        } else {
            Err(DatabaseError(CTDatabaseError {
                desc: "Field in database corrupted".to_string()
            }))
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn decode() {
        let raw_result = decode_line(&"A;123.456789;Abba;12".to_string());
        let expected = ElemData {
            short_name: "A".to_string(),
            long_name: "Abba".to_string(),
            mass: 123.456789,
            atomic_num: 12,
        };
        assert_eq!(Ok(expected), raw_result);
    }

    #[test]
    fn missing_field() {
        assert!(decode_line(&"A;".to_string()).is_err());
    }

    #[test]
    fn field_corrupted() {
        assert!(decode_line(&"A;not a number;Abba;12".to_string()).is_err());
    }
}<commit_msg>Rework tests to use get_single data<commit_after>use std::io::{File, BufferedReader};
use std::io::SeekStyle::SeekSet;
use error::{CTResult, CTDatabaseError, CTSyntaxError};
use error::CTError::{DatabaseError, SyntaxError};
use token::Token;
use token::TokenKind::Elem;

#[derive(Show, PartialEq)]
pub struct ElemData {
    short_name: String,
    long_name: String,
    mass: f64,
    atomic_num: u16,
}

pub struct ElemDatabase {
    db: BufferedReader<File>,
}

impl ElemDatabase {
    pub fn open(path: &str) -> CTResult<ElemDatabase> {
        match File::open(&Path::new(path)) {
            Ok(db_file) => Ok(ElemDatabase { db: BufferedReader::new(db_file) }),
            Err(_) => Err(DatabaseError(CTDatabaseError {
                desc: format!("Could not open database file. Expected at: {:?}", path)
            })),
        }
    }

    pub fn get_single_data(&mut self, elem: &Token) -> CTResult<ElemData> {
        // we return to the beginning of the underlying file, since the data
        // might lie on a line we have previously read past
        self.db.get_mut().seek(0, SeekSet).ok().expect("Internal error reading database");
        let mut line_iter = self.db.lines();
        let short_name = match elem.tok {
            Elem(ref name) => name.as_slice(),
            _ => unreachable!(),
        };
        // TODO: Make this cleaner, and avoid returns
        loop {
            match line_iter.next() {
                Some(Ok(ref line)) if line.starts_with(short_name) => return decode_line(line),
                Some(Err(_)) => return Err(DatabaseError(CTDatabaseError {
                    desc: "Error reading the database".to_string()
                })),
                None => return Err(SyntaxError(CTSyntaxError {
                    desc: format!("Could not find element: {:?}", short_name),
                    pos: elem.pos,
                    len: elem.len,
                })),
                _ => (),
            }
        }
    }
}

fn decode_line(line: &String) -> CTResult<ElemData> {
    let data: Vec<&str> = line.trim().split(';').collect();
    if data.len() < 4 {
        Err(DatabaseError(CTDatabaseError {
            desc: "Missing field in database".to_string()
        }))
    } else {
        let mass = data[1].parse::<f64>();
        let atomic_num = data[3].parse::<u16>();
        if let (Some(m), Some(an)) = (mass, atomic_num) {
            Ok(ElemData {
                short_name: data[0].to_string(),
                long_name: data[2].to_string(),
                mass: m,
                atomic_num: an,
            })
        } else {
            Err(DatabaseError(CTDatabaseError {
                desc: "Field in database corrupted".to_string()
            }))
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::io::File;
    use std::io::fs;
    use token::Token;
    use token::TokenKind::Elem;

    fn make_dummy_db(name: &str, contents: &str) -> ElemDatabase {
        if let Err(e) = File::create(&Path::new(name)).and_then(|mut f| f.write_str(contents)) {
            // if we can't make the database we can't test, so just abort here
            panic!("Could not create dummy database: {:?}", e.desc);
        }
        ElemDatabase::open(name).unwrap()
    }

    fn remove_dummy_db(name: &str) {
        if let Err(e) = fs::unlink(&Path::new(name)) {
            // if we can't remove the database something is wrong, and we abort the test
            panic!("Could not remove dummy database: {:?}", e.desc);
        }
    }

    #[test]
    fn decode() {
        let db_name = "decode_test_db";
        let mut db = make_dummy_db(db_name, "A;123.456789;Abba;12");
        let raw_result = db.get_single_data(&Token { tok: Elem("A".to_string()), pos: 0, len: 2 });
        let expected = ElemData {
            short_name: "A".to_string(),
            long_name: "Abba".to_string(),
            mass: 123.456789,
            atomic_num: 12,
        };
        remove_dummy_db(db_name);
        assert_eq!(Ok(expected), raw_result);
    }

    #[test]
    fn missing_field() {
        let db_name = "missing_field_db";
        let mut db = make_dummy_db(db_name, "A;");
        let result = db.get_single_data(&Token { tok: Elem("A".to_string()), pos: 0, len: 2 });
        remove_dummy_db(db_name);
        assert!(result.is_err());
    }

    #[test]
    fn field_corrupted() {
        let db_name = "field_corrupted_db";
        let mut db = make_dummy_db(db_name, "A;not a number;Abba;12");
        let result = db.get_single_data(&Token { tok: Elem("A".to_string()), pos: 0, len: 2 });
        remove_dummy_db(db_name);
        assert!(result.is_err());
    }
}<|endoftext|>


<commit_before>use update_client::*;
use errors::*;

use std;
use std::collections::{HashMap, HashSet};
use std::sync::{Arc, Mutex};

pub trait Database {
    fn update(&mut self, &FetchResponse) -> Result<()>;
}

pub struct HashDB {
    inner_db: Arc<Mutex<HashMap<ThreatDescriptor, Vec<String>>>>,
}

impl HashDB {
    pub fn new() -> HashDB {
        HashDB { inner_db: Arc::new(Mutex::new(HashMap::new())) }
    }

    fn remove(&mut self,
              removal_map: &HashMap<ThreatDescriptor, (ResponseType, HashSet<usize>)>)
              -> Result<()> {

        for (descriptor, &(_response_type, ref removals)) in removal_map {
            if removals.is_empty() {
                continue;
            }

            let mut cur_map = self.inner_db.lock().expect("Failed to attain lock for inner_db");

            let cur_hashes = match cur_map.get_mut(descriptor) {
                Some(h) => h,
                None => continue,
            };

            let new_hashes: Vec<String> = cur_hashes.iter()
                                                    .enumerate()
                                                    .filter_map(|(ix, s)| {
                                                        if removals.contains(&ix) {
                                                            Some(s.clone())
                                                        } else {
                                                            None
                                                        }
                                                    })
                                                    .collect();

            *cur_hashes = new_hashes;
        }

        Ok(())
    }
}

impl Database for HashDB {
    fn update(&mut self, res: &FetchResponse) -> Result<()> {
        let rem_indices = try!(removals(res));

        let add_prefixes = try!(additions(res));

        try!(self.remove(&rem_indices));

        // for (descriptor, (response_type, additions)) in add_prefixes {
        //     if additions.is_empty() {
        //         continue;
        //     }
        //
        // }

        Ok(())
    }
}

fn additions(fetch_response: &FetchResponse)
             -> Result<HashMap<ThreatDescriptor, (ResponseType, Vec<String>)>> {

    let mut threat_map = HashMap::new();

    for response in &fetch_response.list_update_responses {
        let mut hash_prefixes = Vec::new();

        // Each set of additions will contain a string. This string is the concatenated list of
        // hash prefixes. In a single 'addition' threat entry the prefix size is the same for all
        // hashes, but the prefix size may vary across threat entries.
        for threat_entry in &response.additions {
            if let CompressionType::Raw = threat_entry.compression_type {

                let raw_hashes = &threat_entry.raw_hashes;

                let init = raw_hashes.raw_hashes.as_bytes();
                let mut ix = 0;
                loop {
                    if ix == init.len() {
                        break;
                    }

                    let char_slice =
                        try!(String::from_utf8(init[ix..ix + raw_hashes.prefix_size as usize]
                                                   .to_vec())
                                 .chain_err(|| "could not convert hash to utf8 string"));
                    ix = ix + raw_hashes.prefix_size as usize;
                    hash_prefixes.push(char_slice);
                }
            }
        }
        hash_prefixes.sort();
        threat_map.insert(ThreatDescriptor {
                              threat_type: response.threat_type,
                              platform_type: response.platform_type,
                              threat_entry_type: response.threat_entry_type,
                          },
                          (response.response_type, hash_prefixes));
    }
    Ok(threat_map)
}

fn removals(fetch_response: &FetchResponse)
            -> Result<HashMap<ThreatDescriptor, (ResponseType, HashSet<usize>)>> {

    let mut threat_map = HashMap::new();

    for response in &fetch_response.list_update_responses {
        let mut raw_indices = HashSet::new();

        for threat_entry in &response.removals {
            if let CompressionType::Raw = threat_entry.compression_type {

                for raw in threat_entry.raw_indices.indices.clone() {
                    raw_indices.insert(raw);
                }
            }
        }

        threat_map.insert(ThreatDescriptor {
                              threat_type: response.threat_type,
                              platform_type: response.platform_type,
                              threat_entry_type: response.threat_entry_type,
                          },
                          (response.response_type, raw_indices));
    }
    Ok(threat_map)
}
<commit_msg>Handle additions updates to HashDB.<commit_after>use update_client::*;
use errors::*;

use std;
use std::collections::{HashMap, HashSet};
use std::sync::{Arc, Mutex};

pub trait Database {
    fn update(&mut self, &FetchResponse) -> Result<()>;
}

pub struct HashDB {
    inner_db: Arc<Mutex<HashMap<ThreatDescriptor, Vec<String>>>>,
}

impl HashDB {
    pub fn new() -> HashDB {
        HashDB { inner_db: Arc::new(Mutex::new(HashMap::new())) }
    }

    fn remove(&mut self,
              removal_map: &HashMap<ThreatDescriptor, (ResponseType, HashSet<usize>)>)
              -> Result<()> {

        for (descriptor, &(_response_type, ref removals)) in removal_map {
            if removals.is_empty() {
                continue;
            }

            let mut cur_map = self.inner_db.lock().expect("Failed to attain lock for inner_db");

            let cur_hashes = match cur_map.get_mut(descriptor) {
                Some(h) => h,
                None => continue,
            };

            let new_hashes: Vec<String> = cur_hashes.iter()
                                                    .enumerate()
                                                    .filter_map(|(ix, s)| {
                                                        if removals.contains(&ix) {
                                                            Some(s.clone())
                                                        } else {
                                                            None
                                                        }
                                                    })
                                                    .collect();

            *cur_hashes = new_hashes;
        }

        Ok(())
    }

    fn add(&mut self,
           addition_map: &HashMap<ThreatDescriptor, (ResponseType, Vec<String>)>)
           -> Result<()> {

        for (descriptor, &(response_type, ref additions)) in addition_map {
            if additions.is_empty() {
                continue;
            }

            let mut cur_map = self.inner_db.lock().expect("Failed to attain lock for inner_db");

            if let ResponseType::PartialUpdate = response_type {

                let mut cur_hashes = match cur_map.get_mut(descriptor) {
                    Some(h) => h,
                    None => continue,
                };

                cur_hashes.extend_from_slice(&additions[..]);

                cur_hashes.sort();
            } else if let ResponseType::FullUpdate = response_type {

                let mut cur_hashes = match cur_map.get_mut(descriptor) {
                    Some(h) => h,
                    None => continue,
                };
                *cur_hashes = additions.clone();
            }
        }

        Ok(())
    }
}

impl Database for HashDB {
    fn update(&mut self, res: &FetchResponse) -> Result<()> {
        let rem_indices = try!(removals(res));

        let add_prefixes = try!(additions(res));

        try!(self.remove(&rem_indices));

        // for (descriptor, (response_type, additions)) in add_prefixes {
        //     if additions.is_empty() {
        //         continue;
        //     }
        //
        // }

        Ok(())
    }
}

fn additions(fetch_response: &FetchResponse)
             -> Result<HashMap<ThreatDescriptor, (ResponseType, Vec<String>)>> {

    let mut threat_map = HashMap::new();

    for response in &fetch_response.list_update_responses {
        let mut hash_prefixes = Vec::new();

        // Each set of additions will contain a string. This string is the concatenated list of
        // hash prefixes. In a single 'addition' threat entry the prefix size is the same for all
        // hashes, but the prefix size may vary across threat entries.
        for threat_entry in &response.additions {
            if let CompressionType::Raw = threat_entry.compression_type {

                let raw_hashes = &threat_entry.raw_hashes;

                let init = raw_hashes.raw_hashes.as_bytes();
                let mut ix = 0;
                loop {
                    if ix == init.len() {
                        break;
                    }

                    let char_slice =
                        try!(String::from_utf8(init[ix..ix + raw_hashes.prefix_size as usize]
                                                   .to_vec())
                                 .chain_err(|| "could not convert hash to utf8 string"));
                    ix = ix + raw_hashes.prefix_size as usize;
                    hash_prefixes.push(char_slice);
                }
            }
        }
        hash_prefixes.sort();
        threat_map.insert(ThreatDescriptor {
                              threat_type: response.threat_type,
                              platform_type: response.platform_type,
                              threat_entry_type: response.threat_entry_type,
                          },
                          (response.response_type, hash_prefixes));
    }
    Ok(threat_map)
}

fn removals(fetch_response: &FetchResponse)
            -> Result<HashMap<ThreatDescriptor, (ResponseType, HashSet<usize>)>> {

    let mut threat_map = HashMap::new();

    for response in &fetch_response.list_update_responses {
        let mut raw_indices = HashSet::new();

        for threat_entry in &response.removals {
            if let CompressionType::Raw = threat_entry.compression_type {

                for raw in threat_entry.raw_indices.indices.clone() {
                    raw_indices.insert(raw);
                }
            }
        }

        threat_map.insert(ThreatDescriptor {
                              threat_type: response.threat_type,
                              platform_type: response.platform_type,
                              threat_entry_type: response.threat_entry_type,
                          },
                          (response.response_type, raw_indices));
    }
    Ok(threat_map)
}
<|endoftext|>


<commit_before>use error::{ToResult, ToError};
use std::cell::Cell;
use std::path::PathBuf;
use std::collections::BTreeMap;
use std::fs::{File, OpenOptions};
use std::io::{BufReader, BufWriter, ErrorKind};
use bincode::SizeLimit::Infinite;
use bincode::rustc_serialize::{encode_into, decode_from};

pub type Bookmarks = BTreeMap<String, Bookmark>;

#[derive(Debug)]
pub struct Database {
    location: PathBuf,
    bookmarks: Bookmarks,
}

impl Database {
    fn new(location: PathBuf, bookmarks: Bookmarks) -> Database {
        Database {
            location: location,
            bookmarks: bookmarks,
        }
    }

    pub fn open(directory: PathBuf) -> ToResult<Database> {
        let bookmarks = match File::open(&directory) {
            Ok(file) => {
                let mut reader = BufReader::new(file);
                let bookmarks: Bookmarks = match decode_from(&mut reader, Infinite) {
                    Ok(value) => value,
                    Err(err) => panic!("ERROR DECODING: {:?}", err),
                };

                bookmarks
            }
            Err(ref err) if err.kind() == ErrorKind::NotFound => Bookmarks::new(),
            Err(err) => return Err(ToError::Io(err)),
        };

        return Ok(Database::new(directory, bookmarks));
    }

    // TODO: add a check to verify the db is open.
    // TODO: add check to verify value is a valid directory.
    pub fn put(mut self, key: String, value: PathBuf) -> ToResult<()> {
        println!("put: {:?}: {:?}", key, value);

        // let bookmark = match self.get(key) {
        //     Some(bookmark) => {
        //         Bookmark::new(key.clone(), value);
        //     },
        //     None => {
        //         Bookmark::new(key.clone(), value);
        //     }
        // };

        // update a key, guarding against the key possibly not being set
        // let stat = player_stats.entry("attack").or_insert(100);
        // *stat += random_stat_buff();

        let mut bookmark =  match self.get(&key) {
            Some(bookmark) => bookmark.to_owned(),
            None => {
                panic!("omg");
            },
        };

        println!("bookmark: {:?}", bookmark);

        bookmark.directory = value;

        println!("bookmark: {:?}", bookmark);

        // let bookmark = Bookmark::new(key.clone(), value);

        match self.close() {
            Ok(value) => return Ok(value),
            Err(err) => panic!("Failed to close: {:?}", err),
        };
    }

    pub fn get(&self, key: &String) -> Option<&Bookmark> {
        return self.bookmarks.get(key);
    }

    fn close(&self) -> ToResult<()> {
        // return Ok(());
        let mut options = OpenOptions::new();
                options.write(true);

        let file = match options.open(&self.location) {
            Ok(file) => file,
            // Does not exist, create it.
            Err(_) => {
                options.create(true);
                try!(options.open(&self.location))
            }
        };

        let mut writer = BufWriter::new(file);
        match encode_into(&self.bookmarks, &mut writer, Infinite) {
            Ok(_) => println!("successful encode"),
            Err(err) => panic!("ERROR ECODING: {:?}", err),
        }

        return Ok(());
    }
}

#[derive(Copy, Debug, RustcEncodable, RustcDecodable, PartialEq)]
pub struct Bookmark {
    pub name: String,
    pub directory: Cell<PathBuf>,
    created_at: i64,
    updted_at: i64,
    accessed_at: Option<i64>,
}

impl Bookmark {
    pub fn new(name: String, directory: PathBuf) -> Bookmark {
        let now = 0;

        return Bookmark {
            name: name,
            directory: Cell::new(directory),
            created_at: now,
            updted_at: now,
            accessed_at: None,
        };
    }
}
<commit_msg>put works =)<commit_after>use error::{ToResult, ToError};
use std::cell::Cell;
use std::path::PathBuf;
use std::collections::BTreeMap;
use std::fs::{File, OpenOptions};
use std::io::{BufReader, BufWriter, ErrorKind};
use bincode::SizeLimit::Infinite;
use bincode::rustc_serialize::{encode_into, decode_from};

pub type Bookmarks = BTreeMap<String, Bookmark>;

#[derive(Debug)]
pub struct Database {
    location: PathBuf,
    bookmarks: Bookmarks,
}

impl Database {
    fn new(location: PathBuf, bookmarks: Bookmarks) -> Database {
        Database {
            location: location,
            bookmarks: bookmarks,
        }
    }

    pub fn open(directory: PathBuf) -> ToResult<Database> {
        let bookmarks = match File::open(&directory) {
            Ok(file) => {
                let mut reader = BufReader::new(file);
                let bookmarks: Bookmarks = match decode_from(&mut reader, Infinite) {
                    Ok(value) => value,
                    Err(err) => panic!("ERROR DECODING: {:?}", err),
                };

                bookmarks
            },
            Err(ref err) if err.kind() == ErrorKind::NotFound => Bookmarks::new(),
            Err(err) => return Err(ToError::Io(err)),
        };

        return Ok(Database::new(directory, bookmarks));
    }

    // TODO: add a check to verify the db is open.
    // TODO: add check to verify value is a valid directory.
    pub fn put(&mut self, key: String, value: PathBuf) -> ToResult<()> {
        println!("put: {:?}: {:?}", key, value);

        if self.bookmarks.contains_key(&key) {
            if let Some(bookmark) = self.bookmarks.get_mut(&key) {
                bookmark.directory = value;
            }
        } else {
            let bookmark = Bookmark::new(key.clone(), value);
            self.bookmarks.insert(key, bookmark);
        }

        match self.close() {
            Ok(value) => return Ok(value),
            Err(err) => panic!("Failed to close: {:?}", err),
        };
    }

    pub fn get(&self, key: &String) -> Option<&Bookmark> {
        return self.bookmarks.get(key);
    }

    fn close(&self) -> ToResult<()> {
        // return Ok(());
        let mut options = OpenOptions::new();
                options.write(true);

        let file = match options.open(&self.location) {
            Ok(file) => file,
            // Does not exist, create it.
            Err(_) => {
                options.create(true);
                try!(options.open(&self.location))
            }
        };

        let mut writer = BufWriter::new(file);
        match encode_into(&self.bookmarks, &mut writer, Infinite) {
            Ok(_) => println!("successful encode"),
            Err(err) => panic!("ERROR ECODING: {:?}", err),
        }

        return Ok(());
    }
}

#[derive(Debug, RustcEncodable, RustcDecodable, PartialEq)]
pub struct Bookmark {
    pub name: String,
    pub directory: PathBuf,
    created_at: i64,
    updted_at: i64,
    accessed_at: Option<i64>,
}

impl Bookmark {
    pub fn new(name: String, directory: PathBuf) -> Bookmark {
        let now = 0;

        return Bookmark {
            name: name,
            directory: directory,
            created_at: now,
            updted_at: now,
            accessed_at: None,
        };
    }
}
<|endoftext|>


<commit_before>extern crate rand;

use self::rand::{thread_rng, Rng};
use card;

mod tests;

pub struct Deck {
    pub cards: Vec<card::Card>
}

impl Deck {
    pub fn new() -> Deck {
        let mut cards: Vec<card::Card> = vec![];

        for value in 0..13 {
            for suit in 0..4 {
                let value = match value {
                    0   =>  card::Value::Two,
                    1   =>  card::Value::Three,
                    2   =>  card::Value::Four,
                    3   =>  card::Value::Five,
                    4   =>  card::Value::Six,
                    5   =>  card::Value::Seven,
                    6   =>  card::Value::Eight,
                    7   =>  card::Value::Nine,
                    8   =>  card::Value::Ten,
                    9   =>  card::Value::Jack,
                    10  =>  card::Value::Queen,
                    11  =>  card::Value::King,
                    12  =>  card::Value::Ace,
                    _   =>  card::Value::None
                };
                let suit = match suit {
                    0   =>  card::Suit::Diamonds,
                    1   =>  card::Suit::Clubs,
                    2   =>  card::Suit::Hearts,
                    3   =>  card::Suit::Spades,
                    _   =>  card::Suit::None
                };
                cards.push(card::Card {
                    value: value,
                    suit: suit
                });
            }
        }

        thread_rng().shuffle(&mut cards);

        Deck {
            cards: cards
        }
    }

    pub fn draw(&mut self) -> card::Card {
        let idx = self.cards.len() - 1;
        self.cards.remove(idx)
    }
}
<commit_msg>draw() now returns an Option in case the deck is empty<commit_after>extern crate rand;

use self::rand::{thread_rng, Rng};
use card;

mod tests;

pub struct Deck {
    pub cards: Vec<card::Card>
}

impl Deck {
    pub fn new() -> Deck {
        let mut cards: Vec<card::Card> = vec![];

        for value in 0..13 {
            for suit in 0..4 {
                let value = match value {
                    0   =>  card::Value::Two,
                    1   =>  card::Value::Three,
                    2   =>  card::Value::Four,
                    3   =>  card::Value::Five,
                    4   =>  card::Value::Six,
                    5   =>  card::Value::Seven,
                    6   =>  card::Value::Eight,
                    7   =>  card::Value::Nine,
                    8   =>  card::Value::Ten,
                    9   =>  card::Value::Jack,
                    10  =>  card::Value::Queen,
                    11  =>  card::Value::King,
                    12  =>  card::Value::Ace,
                    _   =>  card::Value::None
                };
                let suit = match suit {
                    0   =>  card::Suit::Diamonds,
                    1   =>  card::Suit::Clubs,
                    2   =>  card::Suit::Hearts,
                    3   =>  card::Suit::Spades,
                    _   =>  card::Suit::None
                };
                cards.push(card::Card {
                    value: value,
                    suit: suit
                });
            }
        }

        thread_rng().shuffle(&mut cards);

        Deck {
            cards: cards
        }
    }

    pub fn draw(&mut self) -> Option<card::Card> {
        let len = self.cards.len();
        if len == 0 {
            None
        } else {
            Some(self.cards.remove(len - 1))
        }
    }
}
<|endoftext|>


<commit_before>extern crate gfx;

use std::collections::HashMap;

use gfx::Slice;
use gfx::handle::Buffer;
use gfx::traits::FactoryExt;
use gfx::pso::PipelineState;
use cgmath::*;

use graphics_defs::*;
use polyomino::*;
use shape::*;

#[derive(Clone, Copy)]
pub enum VertexType {
    FillVertex = 0,
    OutlineVertex,
}

gfx_defines! {
    vertex ShapeVertex {
        pos: [f32; 2] = "a_Pos",
        vertex_type: u32 = "a_VertexType",
    }

    pipeline shape_pipe {
        vbuf: gfx::VertexBuffer<ShapeVertex> = (),
        fill_color: gfx::Global<[f32; 3]> = "i_FillColor",
        outline_color: gfx::Global<[f32; 3]> = "i_OutlineColor",
        out: gfx::RenderTarget<ColorFormat> = "Target0",
    }
}

// const WHITE: [f32; 3] = [1.0, 1.0, 1.0];

pub struct Director<'a, R: gfx::Resources> {
    shape_pso: PipelineState<R, shape_pipe::Meta>,
    // shape_vertex_buffer:
    // shape_slice: Slice<R>,
    game_state: &'a GameState,
    precomputed_polyomino_meshes: HashMap<Polyomino, (Buffer<R, ShapeVertex>, Slice<R>)>,
}

impl<'a, R: gfx::Resources> Director<'a, R> {
    pub fn new<F: gfx::traits::Factory<R>>(u: &'a GameState, factory: &mut F) -> Director<'a, R> {
        // TODO: will one day have to make this choose the right
        // shaders for the platform.
        let shape_pso = factory
            .create_pipeline_simple(
                include_bytes!(concat!(
                    env!("CARGO_MANIFEST_DIR"),
                    "/src/shaders/shape_150.glslv"
                )),
                include_bytes!(concat!(
                    env!("CARGO_MANIFEST_DIR"),
                    "/src/shaders/shape_150.glslf"
                )),
                shape_pipe::new(),
            )
            .unwrap();

        let c = Director::build_mesh_cache(u, factory);

        Director {
            shape_pso: shape_pso,
            // shape_vertex_buffer: vertex_buffer,
            // shape_slice: slice,
            game_state: u,
            precomputed_polyomino_meshes: c,
        }
    }

    // TODO: would be best if this was all packed into one VB
    fn build_mesh_cache<F: gfx::traits::Factory<R>>(
        gs: &'a GameState,
        factory: &mut F,
    ) -> HashMap<Polyomino, (Buffer<R, ShapeVertex>, Slice<R>)> {
        let mut result = HashMap::new();

        for (_, s) in &gs.universe.shapes {
            if result.contains_key(&s.polyomino) {
                continue;
            }

            result.insert(
                s.polyomino.clone(),
                Director::build_polyomino_mesh(&s.polyomino, factory),
            );
        }

        result
    }

    fn build_polyomino_mesh<F: gfx::traits::Factory<R>>(
        p: &Polyomino,
        factory: &mut F,
    ) -> (Buffer<R, ShapeVertex>, Slice<R>) {
        let mut vertices = vec![];
        let mut indices = vec![];

        for pos in &p.squares {
            let (ref mut newverts, ref mut newindices) =
                generate_bordered_square(pos.cast(), 0.5, 0.02);

            vertices.append(newverts);
            indices.append(newindices);
        }

        factory.create_vertex_buffer_with_slice(&vertices, &*indices)
    }

    pub fn draw<C: gfx::CommandBuffer<R>>(
        &self,
        encoder: &mut gfx::Encoder<R, C>,
        target: &gfx::handle::RenderTargetView<R, ColorFormat>,
    ) -> () {
        // for (_, s) in &self.game_state.universe.shapes {
        // }
        let s = &self.game_state.player_chunk();
        let &(ref vb, ref slice) = self.precomputed_polyomino_meshes.get(&s.polyomino).unwrap();

        let data = shape_pipe::Data {
            vbuf: vb.clone(),
            out: target.clone(),
            fill_color: [1.0, 1.0, 1.0],
            outline_color: [0.5, 0.5, 0.5],
        };

        encoder.draw(&slice, &self.shape_pso, &data);
    }
}

// USE MATH COORDINATES
// X RIGHT
// Y UP
// ALWAYS COUNTER-CLOCKWISE
fn quad_indices(ll: u16, lr: u16, ur: u16, ul: u16) -> [u16; 6] {
    [ll, lr, ur, ll, ur, ul]
}

fn generate_quad(
    ll: [f32; 2],
    lr: [f32; 2],
    ur: [f32; 2],
    ul: [f32; 2],
    vt: VertexType,
) -> (Vec<ShapeVertex>, Vec<u16>) {
    let vertices = vec![
        // For fill
        ShapeVertex {
            pos: ll,
            vertex_type: vt as u32
        },
        ShapeVertex {
            pos: lr,
            vertex_type: vt as u32,
        },
        ShapeVertex {
            pos: ur,
            vertex_type: vt as u32,
        },
        ShapeVertex {
            pos: ul,
            vertex_type: vt as u32,
        },
    ];
    let mut indices = vec![];
    indices.extend_from_slice(&quad_indices(0, 1, 2, 3));

    (vertices, indices)
}

fn rect_vertices(ll: [f32; 2], ur: [f32; 2]) -> ([f32; 2], [f32; 2], [f32; 2], [f32; 2]) {
    (ll, [ur[0], ll[1]], ur, [ll[0], ur[1]])
}

fn generate_bordered_square(
    offset: Vector2<f32>,
    size: f32,
    border_width: f32,
) -> (Vec<ShapeVertex>, Vec<u16>) {
    let (ll, lr, ur, ul) = rect_vertices([offset[0], offset[1]], [offset[0] + size, offset[1] + size]);
    let (ill, ilr, iur, iul) = rect_vertices(
            [offset[0] + border_width, offset[1] + border_width],
            [offset[0] + size - border_width, offset[1] + size - border_width],
        );

    use director::VertexType::*;
    let (mut fv, mut fi) = generate_quad(ll, lr, ur, ul, FillVertex);

    let (mut bv, mut bi) = generate_quad(ll, lr, ilr, ill, OutlineVertex); // TODO adjust indices
    let (mut rv, mut ri) = generate_quad(lr, ur, iur, ilr, OutlineVertex);
    let (mut tv, mut ti) = generate_quad(ur, ul, iul, iur, OutlineVertex);
    let (mut lv, mut li) = generate_quad(ul, ll, ill, iul, OutlineVertex);

    let mut vertices = vec![];

    vertices.append(&mut fv);
    vertices.append(&mut bv);
    vertices.append(&mut rv);
    vertices.append(&mut tv);
    vertices.append(&mut lv);

    let mut indices = vec![];

    indices.append(&mut fi);
    indices.append(&mut bi.iter().map(|&x| x + 4).collect());
    indices.append(&mut ri.iter().map(|&x| x + 8).collect());
    indices.append(&mut ti.iter().map(|&x| x + 12).collect());
    indices.append(&mut li.iter().map(|&x| x + 16).collect());

    (vertices, indices)
}
<commit_msg>Possibly more idiomatic<commit_after>extern crate gfx;

use std::collections::HashMap;

use gfx::Slice;
use gfx::handle::Buffer;
use gfx::traits::FactoryExt;
use gfx::pso::PipelineState;
use cgmath::*;

use graphics_defs::*;
use polyomino::*;
use shape::*;

#[derive(Clone, Copy)]
pub enum VertexType {
    FillVertex = 0,
    OutlineVertex,
}

gfx_defines! {
    vertex ShapeVertex {
        pos: [f32; 2] = "a_Pos",
        vertex_type: u32 = "a_VertexType",
    }

    pipeline shape_pipe {
        vbuf: gfx::VertexBuffer<ShapeVertex> = (),
        fill_color: gfx::Global<[f32; 3]> = "i_FillColor",
        outline_color: gfx::Global<[f32; 3]> = "i_OutlineColor",
        out: gfx::RenderTarget<ColorFormat> = "Target0",
    }
}

// const WHITE: [f32; 3] = [1.0, 1.0, 1.0];

pub struct Director<'a, R: gfx::Resources> {
    shape_pso: PipelineState<R, shape_pipe::Meta>,
    // shape_vertex_buffer:
    // shape_slice: Slice<R>,
    game_state: &'a GameState,
    precomputed_polyomino_meshes: HashMap<Polyomino, (Buffer<R, ShapeVertex>, Slice<R>)>,
}

impl<'a, R: gfx::Resources> Director<'a, R> {
    pub fn new<F: gfx::traits::Factory<R>>(u: &'a GameState, factory: &mut F) -> Director<'a, R> {
        // TODO: will one day have to make this choose the right
        // shaders for the platform.
        let shape_pso = factory
            .create_pipeline_simple(
                include_bytes!(concat!(
                    env!("CARGO_MANIFEST_DIR"),
                    "/src/shaders/shape_150.glslv"
                )),
                include_bytes!(concat!(
                    env!("CARGO_MANIFEST_DIR"),
                    "/src/shaders/shape_150.glslf"
                )),
                shape_pipe::new(),
            )
            .unwrap();

        let c = Director::build_mesh_cache(u, factory);

        Director {
            shape_pso: shape_pso,
            // shape_vertex_buffer: vertex_buffer,
            // shape_slice: slice,
            game_state: u,
            precomputed_polyomino_meshes: c,
        }
    }

    // TODO: would be best if this was all packed into one VB
    fn build_mesh_cache<F: gfx::traits::Factory<R>>(
        gs: &'a GameState,
        factory: &mut F,
    ) -> HashMap<Polyomino, (Buffer<R, ShapeVertex>, Slice<R>)> {
        let mut result = HashMap::new();

        for (_, s) in &gs.universe.shapes {
            if result.contains_key(&s.polyomino) {
                continue;
            }

            result.insert(
                s.polyomino.clone(),
                Director::build_polyomino_mesh(&s.polyomino, factory),
            );
        }

        result
    }

    fn build_polyomino_mesh<F: gfx::traits::Factory<R>>(
        p: &Polyomino,
        factory: &mut F,
    ) -> (Buffer<R, ShapeVertex>, Slice<R>) {
        let mut vertices = vec![];
        let mut indices = vec![];

        for pos in &p.squares {
            let (ref mut newverts, ref mut newindices) =
                generate_bordered_square(pos.cast(), 0.5, 0.02);

            vertices.append(newverts);
            indices.append(newindices);
        }

        factory.create_vertex_buffer_with_slice(&vertices, &*indices)
    }

    pub fn draw<C: gfx::CommandBuffer<R>>(
        &self,
        encoder: &mut gfx::Encoder<R, C>,
        target: &gfx::handle::RenderTargetView<R, ColorFormat>,
    ) -> () {
        // for (_, s) in &self.game_state.universe.shapes {
        // }
        let s = &self.game_state.player_chunk();
        let &(ref vb, ref slice) = self.precomputed_polyomino_meshes.get(&s.polyomino).unwrap();

        let data = shape_pipe::Data {
            vbuf: vb.clone(),
            out: target.clone(),
            fill_color: [1.0, 1.0, 1.0],
            outline_color: [0.5, 0.5, 0.5],
        };

        encoder.draw(&slice, &self.shape_pso, &data);
    }
}

// USE MATH COORDINATES
// X RIGHT
// Y UP
// ALWAYS COUNTER-CLOCKWISE
fn quad_indices(ll: u16, lr: u16, ur: u16, ul: u16) -> [u16; 6] {
    [ll, lr, ur, ll, ur, ul]
}

fn generate_quad(
    ll: [f32; 2],
    lr: [f32; 2],
    ur: [f32; 2],
    ul: [f32; 2],
    vt: VertexType,
) -> (Vec<ShapeVertex>, Vec<u16>) {
    let vertices = vec![
        // For fill
        ShapeVertex {
            pos: ll,
            vertex_type: vt as u32
        },
        ShapeVertex {
            pos: lr,
            vertex_type: vt as u32,
        },
        ShapeVertex {
            pos: ur,
            vertex_type: vt as u32,
        },
        ShapeVertex {
            pos: ul,
            vertex_type: vt as u32,
        },
    ];
    let mut indices = vec![];
    indices.extend_from_slice(&quad_indices(0, 1, 2, 3));

    (vertices, indices)
}

fn rect_vertices(ll: [f32; 2], ur: [f32; 2]) -> ([f32; 2], [f32; 2], [f32; 2], [f32; 2]) {
    (ll, [ur[0], ll[1]], ur, [ll[0], ur[1]])
}

fn generate_bordered_square(
    offset: Vector2<f32>,
    size: f32,
    border_width: f32,
) -> (Vec<ShapeVertex>, Vec<u16>) {
    let (ll, lr, ur, ul) = rect_vertices([offset[0], offset[1]], [offset[0] + size, offset[1] + size]);
    let (ill, ilr, iur, iul) = rect_vertices(
            [offset[0] + border_width, offset[1] + border_width],
            [offset[0] + size - border_width, offset[1] + size - border_width],
        );

    use director::VertexType::*;
    let (fv, fi) = generate_quad(ll, lr, ur, ul, FillVertex);

    let (bv, bi) = generate_quad(ll, lr, ilr, ill, OutlineVertex); // TODO adjust indices
    let (rv, ri) = generate_quad(lr, ur, iur, ilr, OutlineVertex);
    let (tv, ti) = generate_quad(ur, ul, iul, iur, OutlineVertex);
    let (lv, li) = generate_quad(ul, ll, ill, iul, OutlineVertex);

    let mut vertices = vec![];

    vertices.extend(fv);
    vertices.extend(bv);
    vertices.extend(rv);
    vertices.extend(tv);
    vertices.extend(lv);

    let mut indices = vec![];

    indices.extend(fi);
    indices.extend(bi.iter().map(|&x| x + 4));
    indices.extend(ri.iter().map(|&x| x + 8));
    indices.extend(ti.iter().map(|&x| x + 12));
    indices.extend(li.iter().map(|&x| x + 16));

    (vertices, indices)
}
<|endoftext|>


<commit_before>use crate::future::poll_fn;
use crate::time::{sleep_until, Duration, Instant, Sleep};

use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};

/// Creates new `Interval` that yields with interval of `duration`. The first
/// tick completes immediately.
///
/// An interval will tick indefinitely. At any time, the `Interval` value can be
/// dropped. This cancels the interval.
///
/// This function is equivalent to `interval_at(Instant::now(), period)`.
///
/// # Panics
///
/// This function panics if `period` is zero.
///
/// # Examples
///
/// ```
/// use tokio::time::{self, Duration};
///
/// #[tokio::main]
/// async fn main() {
///     let mut interval = time::interval(Duration::from_millis(10));
///
///     interval.tick().await;
///     interval.tick().await;
///     interval.tick().await;
///
///     // approximately 20ms have elapsed.
/// }
/// ```
///
/// A simple example using `interval` to execute a task every two seconds.
///
/// The difference between `interval` and [`sleep`] is that an `interval`
/// measures the time since the last tick, which means that `.tick().await`
/// may wait for a shorter time than the duration specified for the interval
/// if some time has passed between calls to `.tick().await`.
///
/// If the tick in the example below was replaced with [`sleep`], the task
/// would only be executed once every three seconds, and not every two
/// seconds.
///
/// ```
/// use tokio::time;
///
/// async fn task_that_takes_a_second() {
///     println!("hello");
///     time::sleep(time::Duration::from_secs(1)).await
/// }
///
/// #[tokio::main]
/// async fn main() {
///     let mut interval = time::interval(time::Duration::from_secs(2));
///     for _i in 0..5 {
///         interval.tick().await;
///         task_that_takes_a_second().await;
///     }
/// }
/// ```
///
/// [`sleep`]: crate::time::sleep()
pub fn interval(period: Duration) -> Interval {
    assert!(period > Duration::new(0, 0), "`period` must be non-zero.");

    interval_at(Instant::now(), period)
}

/// Creates new `Interval` that yields with interval of `period` with the
/// first tick completing at `start`.
///
/// An interval will tick indefinitely. At any time, the `Interval` value can be
/// dropped. This cancels the interval.
///
/// # Panics
///
/// This function panics if `period` is zero.
///
/// # Examples
///
/// ```
/// use tokio::time::{interval_at, Duration, Instant};
///
/// #[tokio::main]
/// async fn main() {
///     let start = Instant::now() + Duration::from_millis(50);
///     let mut interval = interval_at(start, Duration::from_millis(10));
///
///     interval.tick().await;
///     interval.tick().await;
///     interval.tick().await;
///
///     // approximately 70ms have elapsed.
/// }
/// ```
pub fn interval_at(start: Instant, period: Duration) -> Interval {
    assert!(period > Duration::new(0, 0), "`period` must be non-zero.");

    Interval {
        delay: Box::pin(sleep_until(start)),
        period,
    }
}

/// Stream returned by [`interval`](interval) and [`interval_at`](interval_at).
#[derive(Debug)]
pub struct Interval {
    /// Future that completes the next time the `Interval` yields a value.
    delay: Pin<Box<Sleep>>,

    /// The duration between values yielded by `Interval`.
    period: Duration,
}

impl Interval {
    fn poll_tick(&mut self, cx: &mut Context<'_>) -> Poll<Instant> {
        // Wait for the delay to be done
        ready!(Pin::new(&mut self.delay).poll(cx));

        // Get the `now` by looking at the `delay` deadline
        let now = self.delay.deadline();

        // The next interval value is `duration` after the one that just
        // yielded.
        let next = now + self.period;
        self.delay.as_mut().reset(next);

        // Return the current instant
        Poll::Ready(now)
    }

    /// Completes when the next instant in the interval has been reached.
    ///
    /// # Examples
    ///
    /// ```
    /// use tokio::time;
    ///
    /// use std::time::Duration;
    ///
    /// #[tokio::main]
    /// async fn main() {
    ///     let mut interval = time::interval(Duration::from_millis(10));
    ///
    ///     interval.tick().await;
    ///     interval.tick().await;
    ///     interval.tick().await;
    ///
    ///     // approximately 20ms have elapsed.
    /// }
    /// ```
    pub async fn tick(&mut self) -> Instant {
        poll_fn(|cx| self.poll_tick(cx)).await
    }
}
<commit_msg>time: make Interval::poll_tick() public (#3316)<commit_after>use crate::future::poll_fn;
use crate::time::{sleep_until, Duration, Instant, Sleep};

use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};

/// Creates new `Interval` that yields with interval of `duration`. The first
/// tick completes immediately.
///
/// An interval will tick indefinitely. At any time, the `Interval` value can be
/// dropped. This cancels the interval.
///
/// This function is equivalent to `interval_at(Instant::now(), period)`.
///
/// # Panics
///
/// This function panics if `period` is zero.
///
/// # Examples
///
/// ```
/// use tokio::time::{self, Duration};
///
/// #[tokio::main]
/// async fn main() {
///     let mut interval = time::interval(Duration::from_millis(10));
///
///     interval.tick().await;
///     interval.tick().await;
///     interval.tick().await;
///
///     // approximately 20ms have elapsed.
/// }
/// ```
///
/// A simple example using `interval` to execute a task every two seconds.
///
/// The difference between `interval` and [`sleep`] is that an `interval`
/// measures the time since the last tick, which means that `.tick().await`
/// may wait for a shorter time than the duration specified for the interval
/// if some time has passed between calls to `.tick().await`.
///
/// If the tick in the example below was replaced with [`sleep`], the task
/// would only be executed once every three seconds, and not every two
/// seconds.
///
/// ```
/// use tokio::time;
///
/// async fn task_that_takes_a_second() {
///     println!("hello");
///     time::sleep(time::Duration::from_secs(1)).await
/// }
///
/// #[tokio::main]
/// async fn main() {
///     let mut interval = time::interval(time::Duration::from_secs(2));
///     for _i in 0..5 {
///         interval.tick().await;
///         task_that_takes_a_second().await;
///     }
/// }
/// ```
///
/// [`sleep`]: crate::time::sleep()
pub fn interval(period: Duration) -> Interval {
    assert!(period > Duration::new(0, 0), "`period` must be non-zero.");

    interval_at(Instant::now(), period)
}

/// Creates new `Interval` that yields with interval of `period` with the
/// first tick completing at `start`.
///
/// An interval will tick indefinitely. At any time, the `Interval` value can be
/// dropped. This cancels the interval.
///
/// # Panics
///
/// This function panics if `period` is zero.
///
/// # Examples
///
/// ```
/// use tokio::time::{interval_at, Duration, Instant};
///
/// #[tokio::main]
/// async fn main() {
///     let start = Instant::now() + Duration::from_millis(50);
///     let mut interval = interval_at(start, Duration::from_millis(10));
///
///     interval.tick().await;
///     interval.tick().await;
///     interval.tick().await;
///
///     // approximately 70ms have elapsed.
/// }
/// ```
pub fn interval_at(start: Instant, period: Duration) -> Interval {
    assert!(period > Duration::new(0, 0), "`period` must be non-zero.");

    Interval {
        delay: Box::pin(sleep_until(start)),
        period,
    }
}

/// Stream returned by [`interval`](interval) and [`interval_at`](interval_at).
#[derive(Debug)]
pub struct Interval {
    /// Future that completes the next time the `Interval` yields a value.
    delay: Pin<Box<Sleep>>,

    /// The duration between values yielded by `Interval`.
    period: Duration,
}

impl Interval {
    /// Completes when the next instant in the interval has been reached.
    ///
    /// # Examples
    ///
    /// ```
    /// use tokio::time;
    ///
    /// use std::time::Duration;
    ///
    /// #[tokio::main]
    /// async fn main() {
    ///     let mut interval = time::interval(Duration::from_millis(10));
    ///
    ///     interval.tick().await;
    ///     interval.tick().await;
    ///     interval.tick().await;
    ///
    ///     // approximately 20ms have elapsed.
    /// }
    /// ```
    pub async fn tick(&mut self) -> Instant {
        poll_fn(|cx| self.poll_tick(cx)).await
    }

    /// Poll for the next instant in the interval to be reached.
    ///
    /// This method can return the following values:
    ///
    ///  * `Poll::Pending` if the next instant has not yet been reached.
    ///  * `Poll::Ready(instant)` if the next instant has been reached.
    ///
    /// When this method returns `Poll::Pending`, the current task is scheduled
    /// to receive a wakeup when the instant has elapsed. Note that on multiple
    /// calls to `poll_tick`, only the `Waker` from the `Context` passed to the
    /// most recent call is scheduled to receive a wakeup.
    pub fn poll_tick(&mut self, cx: &mut Context<'_>) -> Poll<Instant> {
        // Wait for the delay to be done
        ready!(Pin::new(&mut self.delay).poll(cx));

        // Get the `now` by looking at the `delay` deadline
        let now = self.delay.deadline();

        // The next interval value is `duration` after the one that just
        // yielded.
        let next = now + self.period;
        self.delay.as_mut().reset(next);

        // Return the current instant
        Poll::Ready(now)
    }
}
<|endoftext|>


<commit_before>use cgmath::{Matrix2, Point2, Vector2};
use cgmath::Angle;
use cgmath::Deg;
use gfx;
use gfx::Resources;
use gfx::traits::FactoryExt;

use crate::graphics::orientation::Orientation;
use crate::graphics::texture::Texture;
use crate::shaders::VertexData;

const DEFAULT_INDEX_DATA: &[u16] = &[0, 1, 2, 2, 3, 0];

pub enum Geometry {
  Triangle,
  Rectangle,
}

fn triangle_mesh(w: f32, h: f32) -> [VertexData; 3] {
  [
    VertexData::new([-w * 2.0, -h], [0.0, 0.0]),
    VertexData::new([0.0, 0.0], [0.5, 1.0]),
    VertexData::new([w * 2.0, -h], [0.0, 1.0]),
  ]
}

fn rectangle_mesh(w: f32, h: f32) -> [VertexData; 4] {
  [
    VertexData::new([-w, -h], [0.0, 1.0]),
    VertexData::new([w, -h], [1.0, 1.0]),
    VertexData::new([w, h], [1.0, 0.0]),
    VertexData::new([-w, h], [0.0, 0.0]),
  ]
}

fn edit_vertices(w: f32,
                 h: f32,
                 geometry: Geometry,
                 scale: Option<Matrix2<f32>>,
                 rotation: Option<f32>,
                 orientation: Option<Orientation>) -> Vec<VertexData> {
  let mesh = match geometry {
    Geometry::Rectangle => rectangle_mesh(w, h).to_vec(),
    Geometry::Triangle => triangle_mesh(w, h).to_vec(),
  };

  let scale_matrix = scale.unwrap_or_else(|| Matrix2::new(1.0, 0.0, 0.0, 1.0));

  let rot = rotation.unwrap_or(0.0);

  mesh.iter()
    .map(|el| {
      let cos = Angle::cos(Deg(rot));
      let sin = Angle::sin(Deg(rot));

      let x_skew = match orientation {
        Some(Orientation::UpLeft) => Angle::tan(Deg(50.0)),
        Some(Orientation::UpRight) => Angle::tan(Deg(-50.0)),
        _ => 0.0,
      };

      let y_skew = match orientation {
        Some(Orientation::DownRight) => Angle::tan(Deg(-22.0)),
        Some(Orientation::DownLeft) => Angle::tan(Deg(20.0)),
        _ => 0.0,
      };
      let skew_matrix = Matrix2::<f32>::new(1.0, y_skew, x_skew, 1.0);
      let rotation_matrix = Matrix2::<f32>::new(cos, -sin, sin, cos);
      let translate = match orientation {
        Some(Orientation::UpLeft) => Vector2::<f32>::new(0.0, -20.0),
        Some(Orientation::UpRight) => Vector2::<f32>::new(-2.0, -22.0),
        Some(Orientation::DownLeft) => Vector2::<f32>::new(0.0, -14.0),
        Some(Orientation::DownRight) => Vector2::<f32>::new(-4.0, -14.0),
        Some(Orientation::Normal) => Vector2::<f32>::new(-4.0, 4.0),
        Some(Orientation::Left) => Vector2::<f32>::new(-47.0, -36.0),
        Some(Orientation::Right) => Vector2::<f32>::new(58.0, -40.0),
        Some(Orientation::Down) => Vector2::<f32>::new(-1.0, 7.0),
        Some(Orientation::Up) => Vector2::<f32>::new(-2.0, -8.0),
        None => Vector2::<f32>::new(0.0, 0.0),
      };

      let edited_vertex_data =
        translate +
          (scale_matrix *
            (skew_matrix *
              (rotation_matrix * Vector2::<f32>::new(el.pos[0] as f32, el.pos[1] as f32))));

      VertexData { pos: [edited_vertex_data.x, edited_vertex_data.y], uv: el.uv }
    })
    .collect::<Vec<VertexData>>()
}

#[derive(Clone)]
pub struct PlainMesh<R> where R: Resources {
  pub slice: gfx::Slice<R>,
  pub vertex_buffer: gfx::handle::Buffer<R, VertexData>,
}

impl<R> PlainMesh<R> where R: gfx::Resources {
  pub fn new<F>(factory: &mut F, vertices: &[VertexData], indices: &[u16]) -> PlainMesh<R> where F: gfx::Factory<R> {
    let (vertex_buffer, slice) = factory.create_vertex_buffer_with_slice(vertices, indices);
    PlainMesh {
      slice,
      vertex_buffer,
    }
  }

  pub fn new_with_data<F>(factory: &mut F, size: Point2<f32>, scale: Option<Matrix2<f32>>, rotation: Option<f32>, orientation: Option<Orientation>) -> PlainMesh<R> where F: gfx::Factory<R> {
    let w = size.x;
    let h = size.y;

    let vertex_data = edit_vertices(w, h, Geometry::Rectangle, scale, rotation, orientation);

    let (vertex_buffer, slice) = factory.create_vertex_buffer_with_slice(&vertex_data[..], DEFAULT_INDEX_DATA);
    PlainMesh {
      slice,
      vertex_buffer,
    }
  }
}

#[derive(Clone)]
pub struct TexturedMesh<R> where R: Resources {
  pub slice: gfx::Slice<R>,
  pub vertex_buffer: gfx::handle::Buffer<R, VertexData>,
  pub texture: Texture<R>,
}

impl<R> TexturedMesh<R> where R: gfx::Resources {
  pub fn new<F>(factory: &mut F, vertices: &[VertexData], indices: &[u16], texture: Texture<R>) -> TexturedMesh<R> where F: gfx::Factory<R> {
    let mesh = PlainMesh::new(factory, vertices, indices);
    TexturedMesh {
      slice: mesh.slice,
      vertex_buffer: mesh.vertex_buffer,
      texture,
    }
  }
}

#[derive(Clone)]
pub struct RectangularTexturedMesh<R> where R: Resources {
  pub mesh: TexturedMesh<R>,
  pub size: Point2<f32>,
}

impl<R> RectangularTexturedMesh<R> where R: gfx::Resources {
  pub fn new<F>(factory: &mut F,
                texture: Texture<R>,
                geometry: Geometry,
                size: Point2<f32>,
                scale: Option<Matrix2<f32>>,
                rotation: Option<f32>,
                orientation: Option<Orientation>) -> RectangularTexturedMesh<R> where F: gfx::Factory<R> {
    let vertex_data = edit_vertices(size.x, size.y, geometry, scale, rotation, orientation);

    let mesh = TexturedMesh::new(factory, &vertex_data, &DEFAULT_INDEX_DATA, texture);
    RectangularTexturedMesh {
      mesh,
      size,
    }
  }
}
<commit_msg>Get rid of DEFAULT_INDEX_DATA<commit_after>use cgmath::{Matrix2, Point2, Vector2};
use cgmath::Angle;
use cgmath::Deg;
use gfx;
use gfx::Resources;
use gfx::traits::FactoryExt;

use crate::graphics::orientation::Orientation;
use crate::graphics::texture::Texture;
use crate::shaders::VertexData;

#[derive(Clone, Copy)]
pub enum Geometry {
  Triangle,
  Rectangle,
}

fn triangle_mesh(w: f32, h: f32) -> [VertexData; 3] {
  [
    VertexData::new([0.0, 0.0], [0.5, 1.0]),
    VertexData::new([w * 2.0, -h], [1.0, 0.0]),
    VertexData::new([-w * 2.0, -h], [0.0, 0.0]),
  ]
}

fn rectangle_mesh(w: f32, h: f32) -> [VertexData; 4] {
  [
    VertexData::new([-w, -h], [0.0, 1.0]),
    VertexData::new([w, -h], [1.0, 1.0]),
    VertexData::new([w, h], [1.0, 0.0]),
    VertexData::new([-w, h], [0.0, 0.0]),
  ]
}

fn edit_vertices(w: f32,
                 h: f32,
                 geometry: Geometry,
                 scale: Option<Matrix2<f32>>,
                 rotation: Option<f32>,
                 orientation: Option<Orientation>) -> Vec<VertexData> {
  let mesh = match geometry {
    Geometry::Rectangle => rectangle_mesh(w, h).to_vec(),
    Geometry::Triangle => triangle_mesh(w, h).to_vec(),
  };

  let scale_matrix = scale.unwrap_or_else(|| Matrix2::new(1.0, 0.0, 0.0, 1.0));

  let rot = rotation.unwrap_or(0.0);

  mesh.iter()
    .map(|el| {
      let cos = Angle::cos(Deg(rot));
      let sin = Angle::sin(Deg(rot));

      let x_skew = match orientation {
        Some(Orientation::UpLeft) => Angle::tan(Deg(50.0)),
        Some(Orientation::UpRight) => Angle::tan(Deg(-50.0)),
        _ => 0.0,
      };

      let y_skew = match orientation {
        Some(Orientation::DownRight) => Angle::tan(Deg(-22.0)),
        Some(Orientation::DownLeft) => Angle::tan(Deg(20.0)),
        _ => 0.0,
      };
      let skew_matrix = Matrix2::<f32>::new(1.0, y_skew, x_skew, 1.0);
      let rotation_matrix = Matrix2::<f32>::new(cos, -sin, sin, cos);
      let translate = match orientation {
        Some(Orientation::UpLeft) => Vector2::<f32>::new(0.0, -20.0),
        Some(Orientation::UpRight) => Vector2::<f32>::new(-2.0, -22.0),
        Some(Orientation::DownLeft) => Vector2::<f32>::new(0.0, -14.0),
        Some(Orientation::DownRight) => Vector2::<f32>::new(-4.0, -14.0),
        Some(Orientation::Normal) => Vector2::<f32>::new(-4.0, 4.0),
        Some(Orientation::Left) => Vector2::<f32>::new(-47.0, -36.0),
        Some(Orientation::Right) => Vector2::<f32>::new(58.0, -40.0),
        Some(Orientation::Down) => Vector2::<f32>::new(-1.0, 7.0),
        Some(Orientation::Up) => Vector2::<f32>::new(-2.0, -8.0),
        None => Vector2::<f32>::new(0.0, 0.0),
      };
      let transformation_vec =
        scale_matrix *
          (skew_matrix *
            (rotation_matrix));

      let edited_vertex_data =
        translate + transformation_vec * Vector2::<f32>::new(el.pos[0] as f32, el.pos[1] as f32);

      VertexData { pos: [edited_vertex_data.x, edited_vertex_data.y], uv: el.uv }
    })
    .collect::<Vec<VertexData>>()
}

#[derive(Clone)]
pub struct PlainMesh<R> where R: Resources {
  pub slice: gfx::Slice<R>,
  pub vertex_buffer: gfx::handle::Buffer<R, VertexData>,
}

impl<R> PlainMesh<R> where R: gfx::Resources {
  pub fn new<F>(factory: &mut F, vertices: &[VertexData], indices: &[u16]) -> PlainMesh<R> where F: gfx::Factory<R> {
    let (vertex_buffer, slice) = factory.create_vertex_buffer_with_slice(vertices, indices);
    PlainMesh {
      slice,
      vertex_buffer,
    }
  }

  pub fn new_with_data<F>(factory: &mut F, size: Point2<f32>, scale: Option<Matrix2<f32>>, rotation: Option<f32>, orientation: Option<Orientation>) -> PlainMesh<R> where F: gfx::Factory<R> {
    let w = size.x;
    let h = size.y;

    let vertex_data = edit_vertices(w, h, Geometry::Rectangle, scale, rotation, orientation);

    let indices: &[u16] = &[0, 1, 2, 2, 3, 0];

    let (vertex_buffer, slice) = factory.create_vertex_buffer_with_slice(&vertex_data[..], indices);
    PlainMesh {
      slice,
      vertex_buffer,
    }
  }
}

#[derive(Clone)]
pub struct TexturedMesh<R> where R: Resources {
  pub slice: gfx::Slice<R>,
  pub vertex_buffer: gfx::handle::Buffer<R, VertexData>,
  pub texture: Texture<R>,
}

impl<R> TexturedMesh<R> where R: gfx::Resources {
  pub fn new<F>(factory: &mut F, vertices: &[VertexData], indices: &[u16], texture: Texture<R>) -> TexturedMesh<R> where F: gfx::Factory<R> {
    let mesh = PlainMesh::new(factory, vertices, indices);
    TexturedMesh {
      slice: mesh.slice,
      vertex_buffer: mesh.vertex_buffer,
      texture,
    }
  }
}

#[derive(Clone)]
pub struct RectangularTexturedMesh<R> where R: Resources {
  pub mesh: TexturedMesh<R>,
  pub size: Point2<f32>,
}

impl<R> RectangularTexturedMesh<R> where R: gfx::Resources {
  pub fn new<F>(factory: &mut F,
                texture: Texture<R>,
                geometry: Geometry,
                size: Point2<f32>,
                scale: Option<Matrix2<f32>>,
                rotation: Option<f32>,
                orientation: Option<Orientation>) -> RectangularTexturedMesh<R> where F: gfx::Factory<R> {
    let vertex_data = edit_vertices(size.x, size.y, geometry, scale, rotation, orientation);

    let indices = match geometry {
      Geometry::Rectangle => vec![0, 1, 2, 2, 3, 0],
      Geometry::Triangle => vec![0, 1, 2, 0],
    };

    let mesh = TexturedMesh::new(factory, &vertex_data, &indices.as_slice(), texture);
    RectangularTexturedMesh {
      mesh,
      size,
    }
  }
}
<|endoftext|>