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

//! Library for retrieving and interacting with the [crates.io index].
//!
//! [crates.io index]: https://github.com/rust-lang/crates.io-index
//!
//! ## Examples
//!
//! ```rust
//! extern crate crates_index;
//!
//! let index = crates_index::Index::new("/tmp/_index");
//! if !index.exists() {
//!    index.retrieve().expect("Could not fetch crates.io index");
//! }
//! for crate_ in index.crates() {
//!    let latest_version = crate_.latest_version();
//!    println!("crate name: {}", latest_version.name());
//!    println!("crate version: {}", latest_version.version());
//! }
//! ```

use std::collections::HashMap;
use std::fs;
use std::io::{self, BufRead, BufReader};
use std::iter;
use std::path::{Path, PathBuf};

#[macro_use]
extern crate error_chain;
extern crate git2;
extern crate glob;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate serde;
extern crate home;
extern crate smol_str;

use smol_str::SmolStr;

error_chain! {
    foreign_links {
        Git(git2::Error);
    }
}

static INDEX_GIT_URL: &str = "https://github.com/rust-lang/crates.io-index";

/// A single version of a crate published to the index
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Version {
    name: SmolStr,
    vers: SmolStr,
    deps: Vec<Dependency>,
    cksum: Box<str>,
    features: HashMap<String, Vec<String>>,
    yanked: bool,
}

impl Version {
    /// Name of the crate
    pub fn name(&self) -> &str {
        &self.name
    }

    /// Name of this version
    pub fn version(&self) -> &str {
        &self.vers
    }

    /// Dependencies for this version
    pub fn dependencies(&self) -> &[Dependency] {
        &self.deps
    }

    /// Checksum of the package for this version
    pub fn checksum(&self) -> &str {
        &self.cksum
    }

    pub fn features(&self) -> &HashMap<String, Vec<String>> {
        &self.features
    }

    /// Whether this version was [yanked](http://doc.crates.io/crates-io.html#cargo-yank) from the
    /// index
    pub fn is_yanked(&self) -> bool {
        self.yanked
    }
}

/// A single dependency of a specific crate version
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Dependency {
    name: SmolStr,
    req: SmolStr,
    features: Vec<String>,
    optional: bool,
    default_features: bool,
    target: Option<Box<str>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    kind: Option<SmolStr>,
    #[serde(skip_serializing_if = "Option::is_none")]
    package: Option<Box<str>>,
}

impl Dependency {
    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn requirement(&self) -> &str {
        &self.req
    }

    pub fn features(&self) -> &[String] {
        &self.features
    }

    pub fn is_optional(&self) -> bool {
        self.optional
    }

    pub fn has_default_features(&self) -> bool {
        self.default_features
    }

    pub fn target(&self) -> Option<&str> {
        self.target.as_deref()
    }

    pub fn kind(&self) -> Option<&str> {
        self.kind.as_deref()
    }

    pub fn package(&self) -> Option<&str> {
        self.package.as_deref()
    }

    /// Returns the name of the crate providing the dependency.
    /// This is equivalent to `name()` unless `self.package()`
    /// is not `None`, in which case it's equal to `self.package()`.
    ///
    /// Basically, you can define a dependency in your `Cargo.toml`
    /// like this:
    ///
    /// ```toml
    /// serde_lib = {version = "1", package = "serde"}
    /// ```
    ///
    /// ...which means that it uses the crate `serde` but imports
    /// it under the name `serde_lib`.
    pub fn crate_name(&self) -> &str {
        match self.package {
            Some(ref s) => s,
            None => self.name(),
        }
    }
}

/// Constructed from `Index::crates`
///
/// Silently ignores crates that can't be loaded/parsed
pub struct Crates(CrateIndexPaths);

impl Iterator for Crates {
    type Item = Crate;
    fn next(&mut self) -> Option<Self::Item> {
        while let Some(p) = self.0.next() {
            if let Ok(c) = Crate::new_checked(&p) {
                return Some(c)
            }
        }
        None
    }
}

/// Constructed from `Index::crate_index_paths`
pub struct CrateIndexPaths(iter::Chain<glob::Paths, glob::Paths>);

impl CrateIndexPaths {
    fn new<P: AsRef<Path>>(path: P) -> CrateIndexPaths {
        let mut match_options = glob::MatchOptions::new();
        match_options.require_literal_leading_dot = true;
        let path = path.as_ref();

        let glob_pattern = format!("{}/*/*/*", path.to_str().unwrap());
        let index_paths1 = glob::glob_with(&glob_pattern, match_options).unwrap();

        let glob_pattern = format!("{}/[12]/*", path.to_str().unwrap());
        let index_paths2 = glob::glob_with(&glob_pattern, match_options).unwrap();

        CrateIndexPaths(index_paths1.chain(index_paths2))
    }
}

impl Iterator for CrateIndexPaths {
    type Item = PathBuf;
    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|glob_result| glob_result.unwrap())
    }
}

fn fetch_opts<'cb>() -> git2::FetchOptions<'cb> {
    let mut proxy_opts = git2::ProxyOptions::new();
    proxy_opts.auto();
    let mut fetch_opts = git2::FetchOptions::new();
    fetch_opts.proxy_options(proxy_opts);
    fetch_opts
}

/// Wrapper around managing the crates.io-index git repository
#[derive(Debug, Clone, PartialEq)]
pub struct Index {
    path: PathBuf,
}

impl Index {
    /// Construct a new Index supplying a path where the index lives or should live
    pub fn new<P: Into<PathBuf>>(path: P) -> Index {
        Index { path: path.into() }
    }

    /// Use Cargo's own index in `CARGO_HOME` (`~/.cargo/registry/index`)
    pub fn new_cargo_default() -> Index {
        let cargo_home = home::cargo_home().unwrap_or_default();
        Self::new(cargo_home.join("registry").join("index").join("github.com-1ecc6299db9ec823"))
    }

    /// Determines if a crates.io repository exists at `self.path`
    pub fn exists(&self) -> bool {
        git2::Repository::discover(&self.path)
            .map(|repository| {
                repository
                    .find_remote("origin").ok()
                    // Cargo creates a checkout without an origin set,
                    // so default to true in case of missing origin
                    .map_or(true, |remote| remote.url().map_or(true, |url| url == INDEX_GIT_URL))
            })
            .unwrap_or(false)
    }

    /// Downloads the index to the path specified from the constructor
    pub fn retrieve(&self) -> Result<()> {
        git2::build::RepoBuilder::new()
            .fetch_options(fetch_opts())
            .clone(INDEX_GIT_URL, &self.path)?;
        Ok(())
    }

    /// Assumes the index already exists at `self.path`, and updates it
    pub fn update(&self) -> Result<()> {
        debug_assert!(self.exists());
        let repo = git2::Repository::discover(&self.path)?;
        let mut origin_remote = repo.find_remote("origin")
            .or_else(|_| repo.remote_anonymous(INDEX_GIT_URL))?;
        origin_remote.fetch(&["master"], Some(&mut fetch_opts()), None)?;
        let oid = repo.refname_to_id("FETCH_HEAD")?;
        let object = repo.find_object(oid, None).unwrap();
        repo.reset(&object, git2::ResetType::Hard, None)?;
        Ok(())
    }

    /// Downloads the index to the path specified from the constructor
    pub fn retrieve_or_update(&self) -> Result<()> {
        if self.exists() {
            self.update()
        } else {
            self.retrieve()
        }
    }

    /// Retrieve a single crate by name (case insensitive) from the index
    pub fn crate_(&self, crate_name: &str) -> Option<Crate> {
        let name_lower = crate_name.to_ascii_lowercase();
        if !name_lower.is_ascii() {
            return None;
        }
        let path = match name_lower.len() {
            0 => return None,
            1 => self.path.join("1"),
            2 => self.path.join("2"),
            3 => self.path.join("3").join(&name_lower[0..1]),
            _ => self.path.join(&name_lower[0..2]).join(&name_lower[2..4]),
        }.join(name_lower);
        if path.exists() {
            Crate::new_checked(path.as_path()).ok()
        } else {
            None
        }
    }

    /// Retrieve an iterator over all the crates in the index
    pub fn crates(&self) -> Crates {
        Crates(self.crate_index_paths())
    }

    /// Returns all the crate index file paths in the index
    pub fn crate_index_paths(&self) -> CrateIndexPaths {
        CrateIndexPaths::new(self.path.clone()) // TODO: remove this clone
    }

    /// Get the index directory.
    pub fn path(&self) -> &Path {
        &self.path
    }
}

/// A single crate that contains many published versions
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Crate {
    versions: Vec<Version>,
}

impl Crate {
    #[doc(hidden)]
    #[deprecated(note = "this may panic. use new_checked() instead")]
    pub fn new<P: AsRef<Path>>(index_path: P) -> Crate {
        Self::new_checked(index_path).unwrap()
    }

    /// Parse the file with crate versions.
    ///
    /// The file must contain at least one version.
    pub fn new_checked<P: AsRef<Path>>(index_path: P) -> io::Result<Crate> {
        let index_path = index_path.as_ref();
        let mut versions = vec![];
        let file = fs::File::open(&index_path)?;
        for line in BufReader::new(file).lines() {
            let version: Version = serde_json::from_str(&line?).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
            versions.push(version);
        }
        if versions.is_empty() {
            return Err(io::Error::new(io::ErrorKind::Other, "crate must have versions"));
        }
        Ok(Crate { versions })
    }

    /// Published versions of this crate sorted chronologically by date published
    pub fn versions(&self) -> &[Version] {
        &self.versions
    }

    /// Oldest version.
    ///
    /// Warning: may not be the lowest version number.
    pub fn earliest_version(&self) -> &Version {
        &self.versions[0]
    }

    /// Most recently published version. Warning: may not be the highest version.
    pub fn latest_version(&self) -> &Version {
        &self.versions[self.versions.len() - 1]
    }

    pub fn name(&self) -> &str {
        self.latest_version().name()
    }
}

#[cfg(test)]
mod test {
    use super::Index;
    extern crate tempdir;
    use self::tempdir::TempDir;

    #[test]
    fn test_dependencies() {
        let tmp_dir = TempDir::new("test1").unwrap();

        let index = Index::new(tmp_dir.path());
        index.retrieve_or_update().expect("could not fetch crates io index");
        // let crate_ = index.crates().nth(0).expect("could not find a crate in the index");
        let crate_ = index.crate_("sval").expect("Could not find the crate libnotify in the index");
        let _ = format!("supports debug {:?}", crate_);

        let version = crate_.versions().iter().find(|v| v.version() == "0.0.1")
            .expect("Version 0.0.1 of sval does not exist?");
        let dep_with_package_name = version.dependencies().iter().find(|d| d.name() == "serde_lib")
            .expect("sval does not have expected dependency?");
        assert_ne!(dep_with_package_name.name(), dep_with_package_name.package().unwrap());
        assert_eq!(dep_with_package_name.crate_name(), dep_with_package_name.package().unwrap());
    }

    #[test]
    fn test_retrieve_or_update() {
        let tmp_dir = TempDir::new("test2").unwrap();

        let index = Index::new(tmp_dir.path());
        index.retrieve_or_update().expect("could not fetch crates io index");
        assert!(index.exists());
        index.retrieve_or_update().expect("could not fetch crates io index");
        assert!(index.exists());
    }

    #[test]
    fn test_cargo_default_updates() {
        let index = Index::new_cargo_default();
        index.update().map_err(|e| format!("could not fetch cargo's index in {}: {}", index.path().display(), e)).unwrap();
        assert!(index.crate_("crates-index").is_some());
        assert!(index.crate_("toml").is_some());
        assert!(index.crate_("gcc").is_some());
        assert!(index.crate_("cc").is_some());
        assert!(index.crate_("CC").is_some());
        assert!(index.crate_("無").is_none());
    }

    #[test]
    fn test_exists() {
        let tmp_dir = TempDir::new("test3").unwrap();

        let index = Index::new(tmp_dir.path());
        assert!(!index.exists());
        index.retrieve().unwrap();
        assert!(index.exists());
    }
}
<commit_msg>Reduce reallocations during parsing<commit_after>// Copyright 2015 Corey Farwell
// Copyright 2015 Contributors of github.com/huonw/crates.io-graph
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Library for retrieving and interacting with the [crates.io index].
//!
//! [crates.io index]: https://github.com/rust-lang/crates.io-index
//!
//! ## Examples
//!
//! ```rust
//! extern crate crates_index;
//!
//! let index = crates_index::Index::new("/tmp/_index");
//! if !index.exists() {
//!    index.retrieve().expect("Could not fetch crates.io index");
//! }
//! for crate_ in index.crates() {
//!    let latest_version = crate_.latest_version();
//!    println!("crate name: {}", latest_version.name());
//!    println!("crate version: {}", latest_version.version());
//! }
//! ```

use std::collections::HashMap;

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

#[macro_use]
extern crate error_chain;
extern crate git2;
extern crate glob;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate serde;
extern crate home;
extern crate smol_str;

use smol_str::SmolStr;

error_chain! {
    foreign_links {
        Git(git2::Error);
    }
}

static INDEX_GIT_URL: &str = "https://github.com/rust-lang/crates.io-index";

/// A single version of a crate published to the index
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Version {
    name: SmolStr,
    vers: SmolStr,
    deps: Vec<Dependency>,
    cksum: Box<str>,
    features: HashMap<String, Vec<String>>,
    yanked: bool,
}

impl Version {
    /// Name of the crate
    pub fn name(&self) -> &str {
        &self.name
    }

    /// Name of this version
    pub fn version(&self) -> &str {
        &self.vers
    }

    /// Dependencies for this version
    pub fn dependencies(&self) -> &[Dependency] {
        &self.deps
    }

    /// Checksum of the package for this version
    pub fn checksum(&self) -> &str {
        &self.cksum
    }

    pub fn features(&self) -> &HashMap<String, Vec<String>> {
        &self.features
    }

    /// Whether this version was [yanked](http://doc.crates.io/crates-io.html#cargo-yank) from the
    /// index
    pub fn is_yanked(&self) -> bool {
        self.yanked
    }
}

/// A single dependency of a specific crate version
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Dependency {
    name: SmolStr,
    req: SmolStr,
    features: Vec<String>,
    optional: bool,
    default_features: bool,
    target: Option<Box<str>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    kind: Option<SmolStr>,
    #[serde(skip_serializing_if = "Option::is_none")]
    package: Option<Box<str>>,
}

impl Dependency {
    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn requirement(&self) -> &str {
        &self.req
    }

    pub fn features(&self) -> &[String] {
        &self.features
    }

    pub fn is_optional(&self) -> bool {
        self.optional
    }

    pub fn has_default_features(&self) -> bool {
        self.default_features
    }

    pub fn target(&self) -> Option<&str> {
        self.target.as_deref()
    }

    pub fn kind(&self) -> Option<&str> {
        self.kind.as_deref()
    }

    pub fn package(&self) -> Option<&str> {
        self.package.as_deref()
    }

    /// Returns the name of the crate providing the dependency.
    /// This is equivalent to `name()` unless `self.package()`
    /// is not `None`, in which case it's equal to `self.package()`.
    ///
    /// Basically, you can define a dependency in your `Cargo.toml`
    /// like this:
    ///
    /// ```toml
    /// serde_lib = {version = "1", package = "serde"}
    /// ```
    ///
    /// ...which means that it uses the crate `serde` but imports
    /// it under the name `serde_lib`.
    pub fn crate_name(&self) -> &str {
        match self.package {
            Some(ref s) => s,
            None => self.name(),
        }
    }
}

/// Constructed from `Index::crates`
///
/// Silently ignores crates that can't be loaded/parsed
pub struct Crates(CrateIndexPaths);

impl Iterator for Crates {
    type Item = Crate;
    fn next(&mut self) -> Option<Self::Item> {
        while let Some(p) = self.0.next() {
            if let Ok(c) = Crate::new_checked(&p) {
                return Some(c)
            }
        }
        None
    }
}

/// Constructed from `Index::crate_index_paths`
pub struct CrateIndexPaths(iter::Chain<glob::Paths, glob::Paths>);

impl CrateIndexPaths {
    fn new<P: AsRef<Path>>(path: P) -> CrateIndexPaths {
        let mut match_options = glob::MatchOptions::new();
        match_options.require_literal_leading_dot = true;
        let path = path.as_ref();

        let glob_pattern = format!("{}/*/*/*", path.to_str().unwrap());
        let index_paths1 = glob::glob_with(&glob_pattern, match_options).unwrap();

        let glob_pattern = format!("{}/[12]/*", path.to_str().unwrap());
        let index_paths2 = glob::glob_with(&glob_pattern, match_options).unwrap();

        CrateIndexPaths(index_paths1.chain(index_paths2))
    }
}

impl Iterator for CrateIndexPaths {
    type Item = PathBuf;
    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|glob_result| glob_result.unwrap())
    }
}

fn fetch_opts<'cb>() -> git2::FetchOptions<'cb> {
    let mut proxy_opts = git2::ProxyOptions::new();
    proxy_opts.auto();
    let mut fetch_opts = git2::FetchOptions::new();
    fetch_opts.proxy_options(proxy_opts);
    fetch_opts
}

/// Wrapper around managing the crates.io-index git repository
#[derive(Debug, Clone, PartialEq)]
pub struct Index {
    path: PathBuf,
}

impl Index {
    /// Construct a new Index supplying a path where the index lives or should live
    pub fn new<P: Into<PathBuf>>(path: P) -> Index {
        Index { path: path.into() }
    }

    /// Use Cargo's own index in `CARGO_HOME` (`~/.cargo/registry/index`)
    pub fn new_cargo_default() -> Index {
        let cargo_home = home::cargo_home().unwrap_or_default();
        Self::new(cargo_home.join("registry").join("index").join("github.com-1ecc6299db9ec823"))
    }

    /// Determines if a crates.io repository exists at `self.path`
    pub fn exists(&self) -> bool {
        git2::Repository::discover(&self.path)
            .map(|repository| {
                repository
                    .find_remote("origin").ok()
                    // Cargo creates a checkout without an origin set,
                    // so default to true in case of missing origin
                    .map_or(true, |remote| remote.url().map_or(true, |url| url == INDEX_GIT_URL))
            })
            .unwrap_or(false)
    }

    /// Downloads the index to the path specified from the constructor
    pub fn retrieve(&self) -> Result<()> {
        git2::build::RepoBuilder::new()
            .fetch_options(fetch_opts())
            .clone(INDEX_GIT_URL, &self.path)?;
        Ok(())
    }

    /// Assumes the index already exists at `self.path`, and updates it
    pub fn update(&self) -> Result<()> {
        debug_assert!(self.exists());
        let repo = git2::Repository::discover(&self.path)?;
        let mut origin_remote = repo.find_remote("origin")
            .or_else(|_| repo.remote_anonymous(INDEX_GIT_URL))?;
        origin_remote.fetch(&["master"], Some(&mut fetch_opts()), None)?;
        let oid = repo.refname_to_id("FETCH_HEAD")?;
        let object = repo.find_object(oid, None).unwrap();
        repo.reset(&object, git2::ResetType::Hard, None)?;
        Ok(())
    }

    /// Downloads the index to the path specified from the constructor
    pub fn retrieve_or_update(&self) -> Result<()> {
        if self.exists() {
            self.update()
        } else {
            self.retrieve()
        }
    }

    /// Retrieve a single crate by name (case insensitive) from the index
    pub fn crate_(&self, crate_name: &str) -> Option<Crate> {
        let name_lower = crate_name.to_ascii_lowercase();
        if !name_lower.is_ascii() {
            return None;
        }
        let path = match name_lower.len() {
            0 => return None,
            1 => self.path.join("1"),
            2 => self.path.join("2"),
            3 => self.path.join("3").join(&name_lower[0..1]),
            _ => self.path.join(&name_lower[0..2]).join(&name_lower[2..4]),
        }.join(name_lower);
        if path.exists() {
            Crate::new_checked(path.as_path()).ok()
        } else {
            None
        }
    }

    /// Retrieve an iterator over all the crates in the index
    pub fn crates(&self) -> Crates {
        Crates(self.crate_index_paths())
    }

    /// Returns all the crate index file paths in the index
    pub fn crate_index_paths(&self) -> CrateIndexPaths {
        CrateIndexPaths::new(self.path.clone()) // TODO: remove this clone
    }

    /// Get the index directory.
    pub fn path(&self) -> &Path {
        &self.path
    }
}

/// A single crate that contains many published versions
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Crate {
    versions: Vec<Version>,
}

impl Crate {
    #[doc(hidden)]
    #[deprecated(note = "this may panic. use new_checked() instead")]
    pub fn new<P: AsRef<Path>>(index_path: P) -> Crate {
        Self::new_checked(index_path).unwrap()
    }

    /// Parse the file with crate versions.
    ///
    /// The file must contain at least one version.
    pub fn new_checked<P: AsRef<Path>>(index_path: P) -> io::Result<Crate> {
        let lines = std::fs::read(index_path)?;
        // Trim last newline
        let mut lines = &lines[..];
        while lines.get(lines.len()-1) == Some(&b'\n') {
            lines = &lines[..lines.len()-1];
        }

        #[inline(always)]
        fn is_newline(&c: &u8) -> bool { c == b'\n' }
        let mut versions = Vec::with_capacity(lines.split(is_newline).count());
        for line in lines.split(is_newline) {
            let version: Version = serde_json::from_slice(line).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
            versions.push(version);
        }
        if versions.is_empty() {
            return Err(io::Error::new(io::ErrorKind::Other, "crate must have versions"));
        }
        Ok(Crate { versions })
    }

    /// Published versions of this crate sorted chronologically by date published
    pub fn versions(&self) -> &[Version] {
        &self.versions
    }

    /// Oldest version.
    ///
    /// Warning: may not be the lowest version number.
    pub fn earliest_version(&self) -> &Version {
        &self.versions[0]
    }

    /// Most recently published version. Warning: may not be the highest version.
    pub fn latest_version(&self) -> &Version {
        &self.versions[self.versions.len() - 1]
    }

    pub fn name(&self) -> &str {
        self.latest_version().name()
    }
}

#[cfg(test)]
mod test {
    use super::Index;
    extern crate tempdir;
    use self::tempdir::TempDir;

    #[test]
    fn test_dependencies() {
        let tmp_dir = TempDir::new("test1").unwrap();

        let index = Index::new(tmp_dir.path());
        index.retrieve_or_update().expect("could not fetch crates io index");
        // let crate_ = index.crates().nth(0).expect("could not find a crate in the index");
        let crate_ = index.crate_("sval").expect("Could not find the crate libnotify in the index");
        let _ = format!("supports debug {:?}", crate_);

        let version = crate_.versions().iter().find(|v| v.version() == "0.0.1")
            .expect("Version 0.0.1 of sval does not exist?");
        let dep_with_package_name = version.dependencies().iter().find(|d| d.name() == "serde_lib")
            .expect("sval does not have expected dependency?");
        assert_ne!(dep_with_package_name.name(), dep_with_package_name.package().unwrap());
        assert_eq!(dep_with_package_name.crate_name(), dep_with_package_name.package().unwrap());
    }

    #[test]
    fn test_retrieve_or_update() {
        let tmp_dir = TempDir::new("test2").unwrap();

        let index = Index::new(tmp_dir.path());
        index.retrieve_or_update().expect("could not fetch crates io index");
        assert!(index.exists());
        index.retrieve_or_update().expect("could not fetch crates io index");
        assert!(index.exists());
    }

    #[test]
    fn test_cargo_default_updates() {
        let index = Index::new_cargo_default();
        index.update().map_err(|e| format!("could not fetch cargo's index in {}: {}", index.path().display(), e)).unwrap();
        assert!(index.crate_("crates-index").is_some());
        assert!(index.crate_("toml").is_some());
        assert!(index.crate_("gcc").is_some());
        assert!(index.crate_("cc").is_some());
        assert!(index.crate_("CC").is_some());
        assert!(index.crate_("無").is_none());
    }

    #[test]
    fn test_exists() {
        let tmp_dir = TempDir::new("test3").unwrap();

        let index = Index::new(tmp_dir.path());
        assert!(!index.exists());
        index.retrieve().unwrap();
        assert!(index.exists());
    }
}
<|endoftext|>


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

extern crate ansi_term;
extern crate base64;
#[cfg(target_os = "linux")]
extern crate caps;
extern crate crypto as rust_crypto;
#[cfg(windows)]
extern crate ctrlc;

#[macro_use]
extern crate log;

#[macro_use]
extern crate serde_derive;

#[cfg(not(windows))]
extern crate users as linux_users;

#[cfg(windows)]
extern crate habitat_win_users;
#[cfg(windows)]
extern crate widestring;
#[cfg(windows)]
extern crate winapi;
#[cfg(windows)]
extern crate windows_acl;

pub use self::error::{Error, Result};

pub mod binlink;
pub mod channel;
pub mod config;
pub mod crypto;
pub mod env;
pub mod error;
pub mod event;
pub mod fs;
pub mod os;
pub mod output;
pub mod package;
pub mod service;
pub mod url;
pub mod util;

use std::path::PathBuf;

pub use crate::os::filesystem;
pub use crate::os::users;

pub const AUTH_TOKEN_ENVVAR: &str = "HAB_AUTH_TOKEN";

lazy_static::lazy_static! {
    pub static ref PROGRAM_NAME: String = {
        let arg0 = std::env::args().next().map(PathBuf::from);
        arg0.as_ref()
            .and_then(|p| p.file_stem())
            .and_then(|p| p.to_str())
            .unwrap()
            .to_string()
    };
}
<commit_msg>Replace Strings and &strs with type-safe habitat_core::ChannelIdent type<commit_after>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate ansi_term;
extern crate base64;
#[cfg(target_os = "linux")]
extern crate caps;
extern crate crypto as rust_crypto;
#[cfg(windows)]
extern crate ctrlc;

#[macro_use]
extern crate log;

#[macro_use]
extern crate serde_derive;

#[cfg(not(windows))]
extern crate users as linux_users;

#[cfg(windows)]
extern crate habitat_win_users;
#[cfg(windows)]
extern crate widestring;
#[cfg(windows)]
extern crate winapi;
#[cfg(windows)]
extern crate windows_acl;

pub use self::error::{Error, Result};

pub mod binlink;
pub mod channel;
pub mod config;
pub mod crypto;
pub mod env;
pub mod error;
pub mod event;
pub mod fs;
pub mod os;
pub mod output;
pub mod package;
pub mod service;
pub mod url;
pub mod util;

use std::env::VarError;
use std::ffi::OsStr;
use std::fmt;
use std::path::PathBuf;

pub use crate::os::filesystem;
pub use crate::os::users;

pub const AUTH_TOKEN_ENVVAR: &str = "HAB_AUTH_TOKEN";

lazy_static::lazy_static! {
    pub static ref PROGRAM_NAME: String = {
        let arg0 = std::env::args().next().map(PathBuf::from);
        arg0.as_ref()
            .and_then(|p| p.file_stem())
            .and_then(|p| p.to_str())
            .unwrap()
            .to_string()
    };
}

/// A Builder channel
#[derive(Clone, Debug, PartialEq)]
pub struct ChannelIdent(String);

impl ChannelIdent {
    const LEGACY_ENVVAR: &'static str = "HAB_DEPOT_CHANNEL";
    pub const BLDR_ENVVAR: &'static str = "HAB_BLDR_CHANNEL";
    const UNSTABLE: &'static str = "unstable";
    const STABLE: &'static str = "stable";

    pub fn from_env_var(key: impl AsRef<OsStr>) -> std::result::Result<Self, VarError> {
        crate::env::var(key).map(ChannelIdent)
    }

    pub fn from(s: &str) -> Self {
        ChannelIdent(s.to_string())
    }

    pub fn as_str(&self) -> &str {
        self.0.as_str()
    }

    pub fn stable() -> Self {
        Self::from(Self::STABLE)
    }

    pub fn unstable() -> Self {
        Self::from(Self::UNSTABLE)
    }

    fn legacy_default() -> Self {
        ChannelIdent(
            env::var(Self::LEGACY_ENVVAR)
                .ok()
                .and_then(|c| Some(c.to_string()))
                .unwrap_or(Self::STABLE.to_string()),
        )
    }

    /// Helper function for Builder dynamic channels
    pub fn bldr_name(id: u64) -> String {
        format!("bldr-{}", id)
    }
}

impl fmt::Display for ChannelIdent {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl Default for ChannelIdent {
    fn default() -> Self {
        match env::var(ChannelIdent::BLDR_ENVVAR) {
            Ok(value) => ChannelIdent(value.to_string()),
            Err(_) => ChannelIdent::legacy_default(),
        }
    }
}
<|endoftext|>


<commit_before>//! Setup and control loop devices.
//!
//! Provides rust interface with similar functionality to the Linux utility `losetup`.
//!
//! # Examples
//!
//! ```rust
//! use loopdev::LoopControl;
//! let lc = LoopControl::open().unwrap();
//! let ld = lc.next_free().unwrap();
//!
//! println!("{}", ld.path().unwrap().display());
//!
//! ld.attach_file("test.img").unwrap();
//! // ...
//! ld.detach().unwrap();
//! ```

extern crate libc;

use std::fs::OpenOptions;
use std::fs::File;

use std::os::unix::prelude::*;
use std::io;
use std::path::{Path, PathBuf};
use libc::{c_int, ioctl, uint8_t, uint32_t, uint64_t};
use std::default::Default;

// TODO support missing operations
const LOOP_SET_FD: u16 = 0x4C00;
const LOOP_CLR_FD: u16 = 0x4C01;
const LOOP_SET_STATUS64: u16 = 0x4C04;
//const LOOP_GET_STATUS64: u16 = 0x4C05;
const LOOP_SET_CAPACITY: u16 = 0x4C07;
//const LOOP_SET_DIRECT_IO: u16 = 0x4C08;
//const LOOP_SET_BLOCK_SIZE: u16 = 0x4C09;

//const LOOP_CTL_ADD: u16 = 0x4C80;
//const LOOP_CTL_REMOVE: u16 = 0x4C81;
const LOOP_CTL_GET_FREE: u16 = 0x4C82;

const LOOP_CONTROL: &str = "/dev/loop-control";
const LOOP_PREFIX: &str = "/dev/loop";

/// Interface to the loop control device: `/dev/loop-control`.
#[derive(Debug)]
pub struct LoopControl {
    dev_file: File,
}

impl LoopControl {
    /// Opens the loop control device.
    pub fn open() -> io::Result<LoopControl> {
        Ok(LoopControl {
            dev_file: try!(OpenOptions::new().read(true).write(true).open(LOOP_CONTROL)),
        })
    }

    /// Finds and opens the next available loop device.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use loopdev::LoopControl;
    /// let lc = LoopControl::open().unwrap();
    /// let ld = lc.next_free().unwrap();
    /// println!("{}", ld.path().unwrap().display());
    /// ```
    pub fn next_free(&self) -> io::Result<LoopDevice> {
        let result;
        unsafe {
            result = ioctl(self.dev_file.as_raw_fd() as c_int, LOOP_CTL_GET_FREE.into());
        }
        if result < 0 {
            Err(io::Error::last_os_error())
        } else {
            Ok(try!(
                LoopDevice::open(&format!("{}{}", LOOP_PREFIX, result))
            ))
        }
    }
}

/// Interface to a loop device ie `/dev/loop0`.
#[derive(Debug)]
pub struct LoopDevice {
    device: File,
}

impl AsRawFd for LoopDevice {
    fn as_raw_fd(&self) -> RawFd {
        self.device.as_raw_fd()
    }
}

impl LoopDevice {
    /// Opens a loop device.
    pub fn open<P: AsRef<Path>>(dev: P) -> io::Result<LoopDevice> {
        // TODO create dev if it does not exist and begins with LOOP_PREFIX
        let f = try!(OpenOptions::new().read(true).write(true).open(dev));
        Ok(LoopDevice { device: f })
    }

    /// Attach the loop device to a file starting at offset into the file.
    #[deprecated(since = "0.2.0", note = "use `attach_file` or `attach_with_offset` instead")]
    pub fn attach<P: AsRef<Path>>(&self, backing_file: P, offset: u64) -> io::Result<()> {
        self.attach_with_sizelimit(backing_file, offset, 0)
    }

    /// Attach the loop device to a file that maps to the whole file.
    ///
    /// # Examples
    ///
    /// Attach the device to a file.
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop4").unwrap();
    /// ld.attach_file("test.img").unwrap();
    /// # ld.detach().unwrap();
    /// ```
    pub fn attach_file<P: AsRef<Path>>(&self, backing_file: P) -> io::Result<()> {
        self.attach_with_sizelimit(backing_file, 0, 0)
    }

    /// Attach the loop device to a file starting at offset into the file.
    ///
    /// # Examples
    ///
    /// Attach the device to the start of a file.
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop5").unwrap();
    /// ld.attach_with_offset("test.img", 0).unwrap();
    /// # ld.detach().unwrap();
    /// ```
    pub fn attach_with_offset<P: AsRef<Path>>(
        &self,
        backing_file: P,
        offset: u64,
    ) -> io::Result<()> {
        self.attach_with_sizelimit(backing_file, offset, 0)
    }

    /// Attach the loop device to a file starting at offset into the file and a the given sizelimit.
    ///
    /// # Examples
    ///
    /// Attach the device to the start of a file with a maximum size of 1024 bytes.
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop6").unwrap();
    /// ld.attach_with_sizelimit("test.img", 0, 1024).unwrap();
    /// # ld.detach().unwrap();
    /// ```
    pub fn attach_with_sizelimit<P: AsRef<Path>>(
        &self,
        backing_file: P,
        offset: u64,
        sizelimit: u64,
    ) -> io::Result<()> {
        let bf = try!(OpenOptions::new().read(true).write(true).open(backing_file));

        // Attach the file
        unsafe {
            if ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_SET_FD.into(),
                bf.as_raw_fd() as c_int,
            ) < 0
            {
                return Err(io::Error::last_os_error());
            }
        }

        // Set offset for backing_file
        let mut info: loop_info64 = Default::default();
        info.lo_offset = offset;
        info.lo_sizelimit = sizelimit;
        unsafe {
            if ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_SET_STATUS64.into(),
                &mut info,
            ) < 0
            {
                try!(self.detach());
                return Err(io::Error::last_os_error());
            }
        }
        Ok(())
    }

    /// Get the path of the loop device.
    #[deprecated(since = "0.2.0", note = "use `path` instead")]
    pub fn get_path(&self) -> Option<PathBuf> {
        self.path()
    }

    /// Get the path of the loop device.
    pub fn path(&self) -> Option<PathBuf> {
        let mut p = PathBuf::from("/proc/self/fd");
        p.push(self.device.as_raw_fd().to_string());
        std::fs::read_link(&p).ok()
    }

    /// Detach a loop device from its backing file.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop7").unwrap();
    /// # ld.attach_file("test.img").unwrap();
    /// ld.detach().unwrap();
    /// ```
    pub fn detach(&self) -> io::Result<()> {
        unsafe {
            if ioctl(self.device.as_raw_fd() as c_int, LOOP_CLR_FD.into(), 0) < 0 {
                Err(io::Error::last_os_error())
            } else {
                Ok(())
            }
        }
    }

    /// Resize a live loop device. If the size of the backing file changes this can be called to
    /// inform the loop driver about the new size.
    pub fn set_capacity(&self) -> io::Result<()> {
        println!("running set_capacity");
        unsafe {
            if ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_SET_CAPACITY.into(),
                0,
            ) < 0
            {
                Err(io::Error::last_os_error())
            } else {
                println!("ok");
                Ok(())
            }
        }
    }
}

#[repr(C)]
struct loop_info64 {
    pub lo_device: uint64_t,
    pub lo_inode: uint64_t,
    pub lo_rdevice: uint64_t,
    pub lo_offset: uint64_t,
    pub lo_sizelimit: uint64_t,
    pub lo_number: uint32_t,
    pub lo_encrypt_type: uint32_t,
    pub lo_encrypt_key_size: uint32_t,
    pub lo_flags: uint32_t,
    pub lo_file_name: [uint8_t; 64],
    pub lo_crypt_name: [uint8_t; 64],
    pub lo_encrypt_key: [uint8_t; 32],
    pub lo_init: [uint64_t; 2],
}

impl Default for loop_info64 {
    fn default() -> loop_info64 {
        loop_info64 {
            lo_device: 0,
            lo_inode: 0,
            lo_rdevice: 0,
            lo_offset: 0,
            lo_sizelimit: 0,
            lo_number: 0,
            lo_encrypt_type: 0,
            lo_encrypt_key_size: 0,
            lo_flags: 0,
            lo_file_name: [0; 64],
            lo_crypt_name: [0; 64],
            lo_encrypt_key: [0; 32],
            lo_init: [0; 2],
        }
    }
}
<commit_msg>Fixes lints and updates the format to latest rust fmt<commit_after>//! Setup and control loop devices.
//!
//! Provides rust interface with similar functionality to the Linux utility `losetup`.
//!
//! # Examples
//!
//! ```rust
//! use loopdev::LoopControl;
//! let lc = LoopControl::open().unwrap();
//! let ld = lc.next_free().unwrap();
//!
//! println!("{}", ld.path().unwrap().display());
//!
//! ld.attach_file("test.img").unwrap();
//! // ...
//! ld.detach().unwrap();
//! ```

extern crate libc;

use std::fs::File;
use std::fs::OpenOptions;

use libc::{c_int, ioctl};
use std::default::Default;
use std::io;
use std::os::unix::prelude::*;
use std::path::{Path, PathBuf};

// TODO support missing operations
const LOOP_SET_FD: u16 = 0x4C00;
const LOOP_CLR_FD: u16 = 0x4C01;
const LOOP_SET_STATUS64: u16 = 0x4C04;
//const LOOP_GET_STATUS64: u16 = 0x4C05;
const LOOP_SET_CAPACITY: u16 = 0x4C07;
//const LOOP_SET_DIRECT_IO: u16 = 0x4C08;
//const LOOP_SET_BLOCK_SIZE: u16 = 0x4C09;

//const LOOP_CTL_ADD: u16 = 0x4C80;
//const LOOP_CTL_REMOVE: u16 = 0x4C81;
const LOOP_CTL_GET_FREE: u16 = 0x4C82;

const LOOP_CONTROL: &str = "/dev/loop-control";
const LOOP_PREFIX: &str = "/dev/loop";

/// Interface to the loop control device: `/dev/loop-control`.
#[derive(Debug)]
pub struct LoopControl {
    dev_file: File,
}

impl LoopControl {
    /// Opens the loop control device.
    pub fn open() -> io::Result<Self> {
        Ok(Self {
            dev_file: try!(OpenOptions::new().read(true).write(true).open(LOOP_CONTROL)),
        })
    }

    /// Finds and opens the next available loop device.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use loopdev::LoopControl;
    /// let lc = LoopControl::open().unwrap();
    /// let ld = lc.next_free().unwrap();
    /// println!("{}", ld.path().unwrap().display());
    /// ```
    pub fn next_free(&self) -> io::Result<LoopDevice> {
        let result;
        unsafe {
            result = ioctl(self.dev_file.as_raw_fd() as c_int, LOOP_CTL_GET_FREE.into());
        }
        if result < 0 {
            Err(io::Error::last_os_error())
        } else {
            Ok(try!(LoopDevice::open(&format!(
                "{}{}",
                LOOP_PREFIX, result
            ))))
        }
    }
}

/// Interface to a loop device ie `/dev/loop0`.
#[derive(Debug)]
pub struct LoopDevice {
    device: File,
}

impl AsRawFd for LoopDevice {
    fn as_raw_fd(&self) -> RawFd {
        self.device.as_raw_fd()
    }
}

impl LoopDevice {
    /// Opens a loop device.
    pub fn open<P: AsRef<Path>>(dev: P) -> io::Result<Self> {
        // TODO create dev if it does not exist and begins with LOOP_PREFIX
        let f = try!(OpenOptions::new().read(true).write(true).open(dev));
        Ok(Self { device: f })
    }

    /// Attach the loop device to a file starting at offset into the file.
    #[deprecated(
        since = "0.2.0",
        note = "use `attach_file` or `attach_with_offset` instead"
    )]
    pub fn attach<P: AsRef<Path>>(&self, backing_file: P, offset: u64) -> io::Result<()> {
        self.attach_with_sizelimit(backing_file, offset, 0)
    }

    /// Attach the loop device to a file that maps to the whole file.
    ///
    /// # Examples
    ///
    /// Attach the device to a file.
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop4").unwrap();
    /// ld.attach_file("test.img").unwrap();
    /// # ld.detach().unwrap();
    /// ```
    pub fn attach_file<P: AsRef<Path>>(&self, backing_file: P) -> io::Result<()> {
        self.attach_with_sizelimit(backing_file, 0, 0)
    }

    /// Attach the loop device to a file starting at offset into the file.
    ///
    /// # Examples
    ///
    /// Attach the device to the start of a file.
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop5").unwrap();
    /// ld.attach_with_offset("test.img", 0).unwrap();
    /// # ld.detach().unwrap();
    /// ```
    pub fn attach_with_offset<P: AsRef<Path>>(
        &self,
        backing_file: P,
        offset: u64,
    ) -> io::Result<()> {
        self.attach_with_sizelimit(backing_file, offset, 0)
    }

    /// Attach the loop device to a file starting at offset into the file and a the given sizelimit.
    ///
    /// # Examples
    ///
    /// Attach the device to the start of a file with a maximum size of 1024 bytes.
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop6").unwrap();
    /// ld.attach_with_sizelimit("test.img", 0, 1024).unwrap();
    /// # ld.detach().unwrap();
    /// ```
    pub fn attach_with_sizelimit<P: AsRef<Path>>(
        &self,
        backing_file: P,
        offset: u64,
        sizelimit: u64,
    ) -> io::Result<()> {
        let bf = try!(OpenOptions::new().read(true).write(true).open(backing_file));

        // Attach the file
        unsafe {
            if ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_SET_FD.into(),
                bf.as_raw_fd() as c_int,
            ) < 0
            {
                return Err(io::Error::last_os_error());
            }
        }

        // Set offset for backing_file
        let mut info = loop_info64::default();
        info.lo_offset = offset;
        info.lo_sizelimit = sizelimit;
        unsafe {
            if ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_SET_STATUS64.into(),
                &mut info,
            ) < 0
            {
                try!(self.detach());
                return Err(io::Error::last_os_error());
            }
        }
        Ok(())
    }

    /// Get the path of the loop device.
    #[deprecated(since = "0.2.0", note = "use `path` instead")]
    pub fn get_path(&self) -> Option<PathBuf> {
        self.path()
    }

    /// Get the path of the loop device.
    pub fn path(&self) -> Option<PathBuf> {
        let mut p = PathBuf::from("/proc/self/fd");
        p.push(self.device.as_raw_fd().to_string());
        std::fs::read_link(&p).ok()
    }

    /// Detach a loop device from its backing file.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop7").unwrap();
    /// # ld.attach_file("test.img").unwrap();
    /// ld.detach().unwrap();
    /// ```
    pub fn detach(&self) -> io::Result<()> {
        unsafe {
            if ioctl(self.device.as_raw_fd() as c_int, LOOP_CLR_FD.into(), 0) < 0 {
                Err(io::Error::last_os_error())
            } else {
                Ok(())
            }
        }
    }

    /// Resize a live loop device. If the size of the backing file changes this can be called to
    /// inform the loop driver about the new size.
    pub fn set_capacity(&self) -> io::Result<()> {
        println!("running set_capacity");
        unsafe {
            if ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_SET_CAPACITY.into(),
                0,
            ) < 0
            {
                Err(io::Error::last_os_error())
            } else {
                println!("ok");
                Ok(())
            }
        }
    }
}

#[repr(C)]
struct loop_info64 {
    pub lo_device: u64,
    pub lo_inode: u64,
    pub lo_rdevice: u64,
    pub lo_offset: u64,
    pub lo_sizelimit: u64,
    pub lo_number: u32,
    pub lo_encrypt_type: u32,
    pub lo_encrypt_key_size: u32,
    pub lo_flags: u32,
    pub lo_file_name: [u8; 64],
    pub lo_crypt_name: [u8; 64],
    pub lo_encrypt_key: [u8; 32],
    pub lo_init: [u64; 2],
}

impl Default for loop_info64 {
    fn default() -> Self {
        Self {
            lo_device: 0,
            lo_inode: 0,
            lo_rdevice: 0,
            lo_offset: 0,
            lo_sizelimit: 0,
            lo_number: 0,
            lo_encrypt_type: 0,
            lo_encrypt_key_size: 0,
            lo_flags: 0,
            lo_file_name: [0; 64],
            lo_crypt_name: [0; 64],
            lo_encrypt_key: [0; 32],
            lo_init: [0; 2],
        }
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::Read;
use std::ops::Index;

#[derive(Copy, Clone)]
pub enum MemSection {
    Vram,
    RomBank0,
}

pub struct AddressSpace {
    data: [u8; 0x10000],
}

pub const IOREG_P1:     u16 = 0xFF00;
pub const IOREG_SB:     u16 = 0xFF01;
pub const IOREG_DIV:    u16 = 0xFF04;
pub const IOREG_TIMA:   u16 = 0xFF05;
pub const IOREG_TMA:    u16 = 0xFF06;
pub const IOREG_TAC:    u16 = 0xFF07;
pub const IOREG_IF:     u16 = 0xFF0F;
pub const IOREG_LCDC:   u16 = 0xFF40;
pub const IOREG_STAT:   u16 = 0xFF41;
pub const IOREG_SCY:    u16 = 0xFF42;
pub const IOREG_SCX:    u16 = 0xFF43;
pub const IOREG_LY:     u16 = 0xFF44;
pub const IOREG_LYC:    u16 = 0xFF45;
pub const IOREG_BGP:    u16 = 0xFF47;
pub const IOREG_OBP0:   u16 = 0xFF48;
pub const IOREG_OBP1:   u16 = 0xFF49;
pub const IOREG_WY:     u16 = 0xFF4A;
pub const IOREG_WX:     u16 = 0xFF4B;
pub const IOREG_IE:     u16 = 0xFFFF;

impl AddressSpace {

    pub fn new() -> AddressSpace {
        AddressSpace { data: [0; 0x10000] }
    }

    pub fn read(&self, addr: u16) -> u8 {
        self.data[addr as usize]
    }

    pub fn read_u16(&self, addr: u16) -> u16 {
        let lo = self.read(addr) as u16;
        let hi = (self.read(addr + 1) as u16) << 8;
        lo | hi
    }

    pub fn read_slice(&self, addr: u16, bytes: u16) -> &[u8] {
        &self.data[addr as usize .. (addr + bytes) as usize]
    }

    pub fn write(&mut self, addr: u16, data: u8) {
        match addr {
            // ROM Banks, read only
            0x0000...0x7FFF => (),
            // Switchable RAM bank
            // TODO: Make RAM switchable
            0xA000...0xBFFF => {
                self.data[addr as usize] = data;
            },
            // Internal RAM echo
            0xE000...0xFDFF => {
                let adj_addr = addr - 0x2000;
                self.data[adj_addr as usize] = data;
            },
            // TODO: I/O ports
            // No special write rules
            _ => {
                self.data[addr as usize] = data;
            },
        }
    }

    pub fn write_u16(&mut self, addr: u16, data: u16) {
        let lo = (data & 0xFF) as u8;
        let hi = ((data & 0xFF00) >> 8) as u8;
        self.write(addr, lo);
        self.write(addr + 1, hi);
    }

    pub fn load_rom(&mut self, rom: &mut File) -> ::std::io::Result<()> {
        // Read in header first
        try!(rom.read(&mut self.data[0x000..0x150]));
        // Then read in remaining cart data
        try!(rom.read(&mut self.data[0x0150..0x8000]));
        Ok(())
    }

}

impl Index<u16> for AddressSpace {
    type Output = u8;

    fn index(&self, idx: u16) -> &u8 {
        &self.data[idx as usize]
    }
}

#[derive(Copy, Clone)]
pub enum RegFlag {
    Zero,
    Subtract,
    HalfCarry,
    Carry,
}

#[derive(Copy, Clone)]
pub enum Register {
    A,
    B,
    C,
    D,
    E,
    F,
    H,
    L,
    AF,
    BC,
    DE,
    HL,
    SP,
    PC,
    Flag,
}

pub struct RegData {
    a: u8,
    b: u8,
    c: u8,
    d: u8,
    e: u8,
    f: u8,
    h: u8,
    l: u8,
    sp: u16,
    pc: u16,
    flag: u8,
}

impl RegData {

    pub fn new() -> RegData {
        RegData {
            a: 0,
            b: 0,
            c: 0,
            d: 0,
            e: 0,
            f: 0,
            h: 0,
            l: 0,
            sp: 0xFFFE,
            pc: 0x100,
            flag: 0,
        }
    }

    pub fn read(&self, reg: Register) -> u8 {
        match reg {
            Register::A => self.a,
            Register::B => self.b,
            Register::C => self.c,
            Register::D => self.d,
            Register::E => self.e,
            Register::F => self.f,
            Register::H => self.h,
            Register::L => self.l,
            Register::Flag => self.flag,
            _ => panic!("Register not available for 8-bit read"),
        }
    }

    pub fn read_u16(&self, reg: Register) -> u16 {
        match reg {
            Register::AF => (self.a as u16) << 8 | self.f as u16,
            Register::BC => (self.b as u16) << 8 | self.c as u16,
            Register::DE => (self.d as u16) << 8 | self.e as u16,
            Register::HL => (self.h as u16) << 8 | self.l as u16,
            Register::SP => self.sp,
            Register::PC => self.pc,
            _ => panic!("Register not available for 16-bit read"),
        }
    }

    pub fn write(&mut self, reg: Register, data: u8) {
        match reg {
            Register::A => self.a = data,
            Register::B => self.b = data,
            Register::C => self.c = data,
            Register::D => self.d = data,
            Register::E => self.e = data,
            Register::F => self.f = data,
            Register::H => self.h = data,
            Register::L => self.l = data,
            _ => panic!("Register not available for 8-bit write"),
        }
    }

    pub fn write_u16(&mut self, reg: Register, data: u16) {
        let (hi, lo) = ((data & 0xFF00 >> 8) as u8, (data & 0xFF) as u8);
        match reg {
            Register::AF => {
                self.a = hi;
                self.f = lo;
            },
            Register::BC => {
                self.b = hi;
                self.c = lo;
            },
            Register::DE => {
                self.d = hi;
                self.c = lo;
            },
            Register::HL => {
                self.h = hi;
                self.l = lo;
            },
            Register::SP => self.sp = data,
            Register::PC => self.pc = data,
            _ => panic!("Register not available for 16-bit write"),
        }
    }

    pub fn copy(&mut self, dst: Register, src: Register) {
        let data = self.read(src);
        self.write(dst, data);
    }

    pub fn copy_u16(&mut self, dst: Register, src: Register) {
        let data = self.read_u16(src);
        self.write_u16(dst, data);
    }

    pub fn set_flag(&mut self, flag: RegFlag, on: bool) {
        let bit = match flag {
            RegFlag::Zero => 0x80,
            RegFlag::Subtract => 0x40,
            RegFlag::HalfCarry => 0x20,
            RegFlag::Carry => 0x10,
        };
        if (on) {
            self.flag |= bit;
        } else {
            self.flag &= bit ^ 0xFF;
        }
    }

    pub fn get_flag(&self, flag: RegFlag) -> bool {
        let bit = match flag {
            RegFlag::Zero => 0x80,
            RegFlag::Subtract => 0x40,
            RegFlag::HalfCarry => 0x20,
            RegFlag::Carry => 0x10,
        };
        self.flag & bit != 0
    }

    pub fn advance_pc(&mut self) -> u16 {
        let pc = self.pc;
        self.pc += 1;
        pc
    }

    pub fn set_pc(&mut self, addr: u16) -> u16 {
        let pc = self.pc;
        self.pc = addr;
        pc
    }

    pub fn add_pc(&mut self, n: i8) -> u16 {
        let pc = self.pc;
        self.pc = ((self.pc as i32) + (n as i32)) as u16;
        pc
    }

}
<commit_msg>Add support for I/O registers in write function<commit_after>use std::fs::File;
use std::io::Read;
use std::ops::Index;

#[derive(Copy, Clone)]
pub enum MemSection {
    Vram,
    RomBank0,
}

pub struct AddressSpace {
    data: [u8; 0x10000],
}

pub const IOREG_P1:     u16 = 0xFF00;
pub const IOREG_SB:     u16 = 0xFF01;
pub const IOREG_DIV:    u16 = 0xFF04;
pub const IOREG_TIMA:   u16 = 0xFF05;
pub const IOREG_TMA:    u16 = 0xFF06;
pub const IOREG_TAC:    u16 = 0xFF07;
pub const IOREG_IF:     u16 = 0xFF0F;
pub const IOREG_LCDC:   u16 = 0xFF40;
pub const IOREG_STAT:   u16 = 0xFF41;
pub const IOREG_SCY:    u16 = 0xFF42;
pub const IOREG_SCX:    u16 = 0xFF43;
pub const IOREG_LY:     u16 = 0xFF44;
pub const IOREG_LYC:    u16 = 0xFF45;
pub const IOREG_BGP:    u16 = 0xFF47;
pub const IOREG_OBP0:   u16 = 0xFF48;
pub const IOREG_OBP1:   u16 = 0xFF49;
pub const IOREG_WY:     u16 = 0xFF4A;
pub const IOREG_WX:     u16 = 0xFF4B;
pub const IOREG_IE:     u16 = 0xFFFF;

impl AddressSpace {

    pub fn new() -> AddressSpace {
        AddressSpace { data: [0; 0x10000] }
    }

    pub fn read(&self, addr: u16) -> u8 {
        self.data[addr as usize]
    }

    pub fn read_u16(&self, addr: u16) -> u16 {
        let lo = self.read(addr) as u16;
        let hi = (self.read(addr + 1) as u16) << 8;
        lo | hi
    }

    pub fn read_slice(&self, addr: u16, bytes: u16) -> &[u8] {
        &self.data[addr as usize .. (addr + bytes) as usize]
    }

    pub fn write(&mut self, addr: u16, data: u8) {
        let mut addr = addr;
        let mut data = data;
        let rw = match addr {
            // ROM Banks, read only
            0x0000...0x7FFF => false,
            // Switchable RAM bank
            // TODO: Make RAM switchable
            0xA000...0xBFFF => true,
            // Internal RAM echo
            0xE000...0xFDFF => {
                addr -= 0x2000;
                true
            },
            // I/O registers
            IOREG_DIV => {
                data = 0;
                true
            },
            IOREG_LY => {
                data = 0;
                true
            },
            // No special write rules
            _ => true,
        };
        if rw {
            self.data[addr as usize] = data;
        }
    }

    pub fn write_u16(&mut self, addr: u16, data: u16) {
        let lo = (data & 0xFF) as u8;
        let hi = ((data & 0xFF00) >> 8) as u8;
        self.write(addr, lo);
        self.write(addr + 1, hi);
    }

    pub fn load_rom(&mut self, rom: &mut File) -> ::std::io::Result<()> {
        // Read in header first
        try!(rom.read(&mut self.data[0x000..0x150]));
        // Then read in remaining cart data
        try!(rom.read(&mut self.data[0x0150..0x8000]));
        Ok(())
    }

}

impl Index<u16> for AddressSpace {
    type Output = u8;

    fn index(&self, idx: u16) -> &u8 {
        &self.data[idx as usize]
    }
}

#[derive(Copy, Clone)]
pub enum RegFlag {
    Zero,
    Subtract,
    HalfCarry,
    Carry,
}

#[derive(Copy, Clone)]
pub enum Register {
    A,
    B,
    C,
    D,
    E,
    F,
    H,
    L,
    AF,
    BC,
    DE,
    HL,
    SP,
    PC,
    Flag,
}

pub struct RegData {
    a: u8,
    b: u8,
    c: u8,
    d: u8,
    e: u8,
    f: u8,
    h: u8,
    l: u8,
    sp: u16,
    pc: u16,
    flag: u8,
}

impl RegData {

    pub fn new() -> RegData {
        RegData {
            a: 0,
            b: 0,
            c: 0,
            d: 0,
            e: 0,
            f: 0,
            h: 0,
            l: 0,
            sp: 0xFFFE,
            pc: 0x100,
            flag: 0,
        }
    }

    pub fn read(&self, reg: Register) -> u8 {
        match reg {
            Register::A => self.a,
            Register::B => self.b,
            Register::C => self.c,
            Register::D => self.d,
            Register::E => self.e,
            Register::F => self.f,
            Register::H => self.h,
            Register::L => self.l,
            Register::Flag => self.flag,
            _ => panic!("Register not available for 8-bit read"),
        }
    }

    pub fn read_u16(&self, reg: Register) -> u16 {
        match reg {
            Register::AF => (self.a as u16) << 8 | self.f as u16,
            Register::BC => (self.b as u16) << 8 | self.c as u16,
            Register::DE => (self.d as u16) << 8 | self.e as u16,
            Register::HL => (self.h as u16) << 8 | self.l as u16,
            Register::SP => self.sp,
            Register::PC => self.pc,
            _ => panic!("Register not available for 16-bit read"),
        }
    }

    pub fn write(&mut self, reg: Register, data: u8) {
        match reg {
            Register::A => self.a = data,
            Register::B => self.b = data,
            Register::C => self.c = data,
            Register::D => self.d = data,
            Register::E => self.e = data,
            Register::F => self.f = data,
            Register::H => self.h = data,
            Register::L => self.l = data,
            _ => panic!("Register not available for 8-bit write"),
        }
    }

    pub fn write_u16(&mut self, reg: Register, data: u16) {
        let (hi, lo) = ((data & 0xFF00 >> 8) as u8, (data & 0xFF) as u8);
        match reg {
            Register::AF => {
                self.a = hi;
                self.f = lo;
            },
            Register::BC => {
                self.b = hi;
                self.c = lo;
            },
            Register::DE => {
                self.d = hi;
                self.c = lo;
            },
            Register::HL => {
                self.h = hi;
                self.l = lo;
            },
            Register::SP => self.sp = data,
            Register::PC => self.pc = data,
            _ => panic!("Register not available for 16-bit write"),
        }
    }

    pub fn copy(&mut self, dst: Register, src: Register) {
        let data = self.read(src);
        self.write(dst, data);
    }

    pub fn copy_u16(&mut self, dst: Register, src: Register) {
        let data = self.read_u16(src);
        self.write_u16(dst, data);
    }

    pub fn set_flag(&mut self, flag: RegFlag, on: bool) {
        let bit = match flag {
            RegFlag::Zero => 0x80,
            RegFlag::Subtract => 0x40,
            RegFlag::HalfCarry => 0x20,
            RegFlag::Carry => 0x10,
        };
        if (on) {
            self.flag |= bit;
        } else {
            self.flag &= bit ^ 0xFF;
        }
    }

    pub fn get_flag(&self, flag: RegFlag) -> bool {
        let bit = match flag {
            RegFlag::Zero => 0x80,
            RegFlag::Subtract => 0x40,
            RegFlag::HalfCarry => 0x20,
            RegFlag::Carry => 0x10,
        };
        self.flag & bit != 0
    }

    pub fn advance_pc(&mut self) -> u16 {
        let pc = self.pc;
        self.pc += 1;
        pc
    }

    pub fn set_pc(&mut self, addr: u16) -> u16 {
        let pc = self.pc;
        self.pc = addr;
        pc
    }

    pub fn add_pc(&mut self, n: i8) -> u16 {
        let pc = self.pc;
        self.pc = ((self.pc as i32) + (n as i32)) as u16;
        pc
    }

}
<|endoftext|>


<commit_before>use low_level as ll;
use error::Error;
use event::{Event, EventStatus, EventLike};

use std::sync::Arc;
use std::cell::RefCell;

struct MemEvents {
    last_write: RefCell<Option<Event>>,
    last_read: RefCell<Vec<Event>>,
}

pub struct Mem {
    pub id: ll::Mem,
    events: Arc<MemEvents>,
}

impl Mem {
    pub fn new(id: ll::Mem) -> Mem {
        let events = MemEvents{
            last_write: RefCell::new(None),
            last_read: RefCell::new(Vec::new()),
        };
        Mem{
            id: id,
            events: Arc::new(events),
        }
    }

    pub fn write_events(self: &Self) -> Vec<ll::Event> {
        let mut tr: Vec<ll::Event> = Vec::with_capacity(2);
        if let Some(ref evt) = *self.events.last_write.borrow() {
            tr.push(evt.id);
        }
        tr.extend(self.events.last_read.borrow().iter().map(|e| e.id));
        tr
    }

    pub fn read_events(self: &Self) -> Vec<ll::Event> {
        if let Some(ref evt) = *self.events.last_write.borrow() {
            vec!(evt.id)
        } else {
            vec!()
        }
    }

    pub fn register_write(self: &mut Self, evt: Event) -> () {
        *self.events.last_write.borrow_mut() = Some(evt);
    }

    pub fn register_read(self: &Self, evt: Event) -> () {
        let mut r = self.events.last_read.borrow_mut();
        if r.len() > 10 {
            r.retain(|e|
                     match e.status().ok().expect("error getting event status") {
                         EventStatus::Complete => false,
                         _ => true,
            });
        }
        r.push(evt);
    }
}

impl Drop for Mem {
    fn drop(self: &mut Self) -> () {
        unsafe {
            Error::check(ll::clReleaseMemObject(self.id))
                .ok().expect("error releasing mem object");
        }
    }
}

impl Clone for Mem {
    fn clone(self: &Self) -> Self {
        unsafe {
            Error::check(ll::clRetainMemObject(self.id))
                .ok().expect("error retaining mem object");
        }
        Mem{ id: self.id, events: self.events.clone() }
    }
}

<commit_msg>increases check to 20<commit_after>use low_level as ll;
use error::Error;
use event::{Event, EventStatus, EventLike};

use std::sync::Arc;
use std::cell::RefCell;

struct MemEvents {
    last_write: RefCell<Option<Event>>,
    last_read: RefCell<Vec<Event>>,
}

pub struct Mem {
    pub id: ll::Mem,
    events: Arc<MemEvents>,
}

impl Mem {
    pub fn new(id: ll::Mem) -> Mem {
        let events = MemEvents{
            last_write: RefCell::new(None),
            last_read: RefCell::new(Vec::new()),
        };
        Mem{
            id: id,
            events: Arc::new(events),
        }
    }

    pub fn write_events(self: &Self) -> Vec<ll::Event> {
        let mut tr: Vec<ll::Event> = Vec::with_capacity(2);
        if let Some(ref evt) = *self.events.last_write.borrow() {
            tr.push(evt.id);
        }
        tr.extend(self.events.last_read.borrow().iter().map(|e| e.id));
        tr
    }

    pub fn read_events(self: &Self) -> Vec<ll::Event> {
        if let Some(ref evt) = *self.events.last_write.borrow() {
            vec!(evt.id)
        } else {
            vec!()
        }
    }

    pub fn register_write(self: &mut Self, evt: Event) -> () {
        *self.events.last_write.borrow_mut() = Some(evt);
    }

    pub fn register_read(self: &Self, evt: Event) -> () {
        let mut r = self.events.last_read.borrow_mut();
        if r.len() > 20 {
            r.retain(|e|
                     match e.status().ok().expect("error getting event status") {
                         EventStatus::Complete => false,
                         _ => true,
            });
        }
        r.push(evt);
    }
}

impl Drop for Mem {
    fn drop(self: &mut Self) -> () {
        unsafe {
            Error::check(ll::clReleaseMemObject(self.id))
                .ok().expect("error releasing mem object");
        }
    }
}

impl Clone for Mem {
    fn clone(self: &Self) -> Self {
        unsafe {
            Error::check(ll::clRetainMemObject(self.id))
                .ok().expect("error retaining mem object");
        }
        Mem{ id: self.id, events: self.events.clone() }
    }
}

<|endoftext|>


<commit_before>extern crate num;
use std::collections::BTreeSet;
use std::cmp;
use rand::Rng;
use std::ops::Range;
use std::iter::Rev;
use super::{Genetic, Stateless};
use std::marker::PhantomData;
use std::fmt::{self, Debug};

/// Defines an opcode for the Mep. Every opcode contains an instruction and two parameter indices. These specify which
/// previous opcodes produced the result required as inputs to this opcode. These parameters can also come from the inputs
/// to the program, which sequentially preceed the internal instructions.
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
struct Opcode<Ins> {
    instruction: Ins,
    first: usize,
    second: usize,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SerialMep<Ins> {
    program: Vec<Opcode<Ins>>,
    unit_mutate_size: usize,
    crossover_points: usize,
    inputs: usize,
    outputs: usize,
}

impl<'a, Ins, Param, F> From<&'a Mep<Ins, Param, F>> for SerialMep<Ins>
    where Ins: Clone
{
    fn from(mep: &'a Mep<Ins, Param, F>) -> Self {
        SerialMep {
            program: mep.program.clone(),
            unit_mutate_size: mep.unit_mutate_size,
            crossover_points: mep.crossover_points,
            inputs: mep.inputs,
            outputs: mep.outputs,
        }
    }
}

/// A multi-expression program represented using a series of operations that can reuse results of previous operations.
pub struct Mep<Ins, Param, F> {
    program: Vec<Opcode<Ins>>,
    unit_mutate_size: usize,
    crossover_points: usize,
    inputs: usize,
    outputs: usize,
    processor: F,
    _phantom: PhantomData<Param>,
}

impl<Ins, Param, F> Debug for Mep<Ins, Param, F>
    where Ins: Debug
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // write!(f, "Mep{{ program: {}, unit_mutate_size: {}, crossover_points: {}, inputs: {}, outputs: {} }}", )
        try!(write!(f, "Mep{{ program: ["));
        if self.program.len() != 0 {
            for op in &self.program[..self.program.len() - 1] {
                try!(write!(f, "{:?}, ", op));
            }
            try!(write!(f, "{:?}", self.program.last().unwrap()));
        }
        write!(f,
               "], unit_mutate_size: {}, crossover_points: {}, inputs: {}, outputs: {} }}",
               self.unit_mutate_size,
               self.crossover_points,
               self.inputs,
               self.outputs)
    }
}

impl<Ins, Param, F> Clone for Mep<Ins, Param, F>
    where Ins: Clone,
          F: Copy
{
    fn clone(&self) -> Self {
        Mep {
            program: self.program.clone(),
            unit_mutate_size: self.unit_mutate_size,
            crossover_points: self.crossover_points,
            inputs: self.inputs,
            outputs: self.outputs,
            processor: self.processor,
            _phantom: PhantomData,
        }
    }
}

impl<Ins, Param, F> Mep<Ins, Param, F> {
    /// Generates a new Mep with a particular size and takes a closure to generate random instructions.
    /// Takes an RNG as well to generate random internal data for each instruction. This Rng is different from the Mep's
    /// Rng, thus it is parameterized separately here.
    pub fn new<I, Rg>(inputs: usize,
                      outputs: usize,
                      unit_mutate_size: usize,
                      crossover_points: usize,
                      rng: &mut Rg,
                      instruction_iter: I,
                      processor: F)
                      -> Self
        where I: ExactSizeIterator<Item = Ins>,
              Rg: Rng,
              F: Fn(&Ins, Param, Param) -> Param
    {
        let outputs_beginning = instruction_iter.len() - outputs;
        Mep {
            program: instruction_iter.enumerate()
                .map(|(index, ins)|
                    // For normal instructions previous outputs may be used.
                    if index < outputs_beginning {
                        Opcode{
                            instruction: ins,
                            first: rng.gen_range(0, index + inputs),
                            second: rng.gen_range(0, index + inputs),
                        }
                    // An output should not be used as an input to another output.
                    } else {
                        Opcode{
                            instruction: ins,
                            first: rng.gen_range(0, outputs_beginning + inputs),
                            second: rng.gen_range(0, outputs_beginning + inputs),
                        }
                    })
                .collect(),
            unit_mutate_size: unit_mutate_size,
            crossover_points: crossover_points,
            inputs: inputs,
            outputs: outputs,
            processor: processor,
            _phantom: PhantomData,
        }
    }

    pub fn new_from_serial_mep(smep: SerialMep<Ins>, processor: F) -> Self {
        Mep {
            program: smep.program,
            unit_mutate_size: smep.unit_mutate_size,
            crossover_points: smep.crossover_points,
            inputs: smep.inputs,
            outputs: smep.outputs,
            processor: processor,
            _phantom: PhantomData,
        }
    }
}

impl<Ins, Param, F, R, M> Genetic<R, M> for Mep<Ins, Param, F>
    where R: Rng,
          Ins: Clone,
          Param: Clone,
          F: Copy,
          M: Fn(&mut Ins, &mut R)
{
    fn mate(&self, rhs: &Self, rng: &mut R) -> Self {
        // Each Mep must have the same amount of inputs
        // TODO: Once Rust implements generic values, this can be made explicit and is not needed
        assert!(self.inputs == rhs.inputs);
        assert!(self.outputs == rhs.outputs);
        // Get the smallest of the two lengths
        let total_instructions = cmp::min(self.program.len(), rhs.program.len());
        let crossover_choice = rng.gen_range(0, 2);
        Mep{program:
            //Generate a randomly sized sequence between 1 and crossover_points
            (0..rng.gen_range(1, cmp::min(total_instructions / 2, {
                if crossover_choice == 0 {self}
                else {rhs}}.crossover_points + 1)))
            //Map these to random crossover points
            .map(|_| rng.gen_range(0, total_instructions))
            //Add total_instructions at the end so we can generate a range with it
            .chain(Some(total_instructions))
            //Sort them by value into BTree, which removes duplicates and orders them
            .fold(BTreeSet::new(), |mut set, i| {set.insert(i); set})
            //Iterate over the sorted values
            .iter()
            //Turn every copy of two, prepending a 0, into a range
            .scan(0, |prev, x| {let out = Some(*prev..*x); *prev = *x; out})
            //Enumerate by index to differentiate odd and even values
            .enumerate()
            //Map even pairs to ranges in parent 0 and odd ones to ranges in parent 1 and expand the ranges
            .flat_map(|(index, range)| {
                {if index % 2 == 0 {self} else {rhs}}.program[range].iter().cloned()
            })
            //Collect all the instruction ranges from each parent
            .collect(),

            unit_mutate_size: if self.unit_mutate_size < rhs.unit_mutate_size {
                rng.gen_range(self.unit_mutate_size, rhs.unit_mutate_size + 1)
            } else {
                rng.gen_range(rhs.unit_mutate_size, self.unit_mutate_size + 1)
            },

            crossover_points: if self.crossover_points < rhs.crossover_points {
                rng.gen_range(self.crossover_points, rhs.crossover_points + 1)
            } else {
                rng.gen_range(rhs.crossover_points, self.crossover_points + 1)
            },

            inputs: self.inputs,
            outputs: self.outputs,
            processor: {if rng.gen_range(0, 2) == 0 {self} else {rhs}}.processor,
            _phantom: PhantomData,
        }
    }

    /// The Mep mutate function operates using the unit_mutate_size. This variable specifies the amount of instructions
    /// for which a single mutation is expect to occour every time mutate is called. This variable can be mutated inside
    /// of mutate, in which case it may never go below 1, but may tend towards infinity in increments of 1. This variable
    /// is implemented as a u64 to permit it to expand unbounded to mutation levels that are so low that mutations
    /// virtually never happen. Allowing this to mutate allows species to find the equilibrium between genomic
    /// adaptability and stability. If a species develops information gathering, then it can adapt intellegently, making
    /// it possibly more beneficial to operate at lower mutation rates. Setting the default mutation rate for species
    /// properly, or allowing it to adapt as the simulation continues, permits species to survive more frequently that
    /// are randomly generated.
    fn mutate(&mut self, mutator: M, rng: &mut R) {
        // Mutate unit_mutate_size
        if rng.gen_range(0, self.unit_mutate_size) == 0 {
            // Make it possibly go up or down by 1
            match rng.gen_range(0, 2) {
                0 => self.unit_mutate_size += 1,
                1 => {
                    if self.unit_mutate_size > 1 {
                        self.unit_mutate_size -= 1
                    }
                }
                _ => unreachable!(),
            }
        }
        // Mutate crossover_points
        if rng.gen_range(0, self.unit_mutate_size) == 0 {
            // Make it possibly go up or down by 1
            match rng.gen_range(0, 2) {
                0 => self.crossover_points += 1,
                1 => {
                    if self.crossover_points > 1 {
                        self.crossover_points -= 1
                    }
                }
                _ => unreachable!(),
            }
        }

        // Mutate the instructions using the mutator
        loop {
            // Choose a random location in the instructions and then add a random value up to the unit_mutate_size
            let choice = rng.gen_range(0, self.program.len() + self.unit_mutate_size);
            // Whenever we choose a location outside the vector reject the choice and end mutation
            if choice >= self.program.len() {
                break;
            }
            let op = &mut self.program[choice];
            // Randomly mutate only one of the things contained here
            match rng.gen_range(0, 3) {
                0 => mutator(&mut op.instruction, rng),
                1 => op.first = rng.gen_range(0, choice + self.inputs),
                2 => op.second = rng.gen_range(0, choice + self.inputs),
                _ => unreachable!(),
            }
        }
    }
}

impl<'a, Ins: 'a, Param: 'a, F: 'a> Stateless<'a, &'a [Param], ResultIterator<'a, Ins, Param, F>> for Mep<Ins, Param, F>
    where F: Fn(&Ins, Param, Param) -> Param,
          Param: Clone
{
    fn process(&'a self, inputs: &'a [Param]) -> ResultIterator<'a, Ins, Param, F> {
// Ensure we have enough opcodes to produce the desired amount of outputs, otherwise the programmer has failed
        assert!(self.outputs <= self.program.len());
        ResultIterator {
            mep: self,
            buff: vec![None; self.program.len()],
            solve_iter: ((self.program.len() + self.inputs - self.outputs)..(self.program.len() +
                                                                             self.inputs))
                .rev(),
            inputs: inputs,
        }
    }
}

pub struct ResultIterator<'a, Ins: 'a, Param: 'a, F: 'a> {
    mep: &'a Mep<Ins, Param, F>,
    buff: Vec<Option<Param>>,
    solve_iter: Rev<Range<usize>>,
    inputs: &'a [Param],
}

impl<'a, Ins, Param, F> ResultIterator<'a, Ins, Param, F>
    where F: Fn(&Ins, Param, Param) -> Param,
          Param: Clone
{
    fn op_solved(&mut self, i: usize) -> Param {
        // If this is an input, it is already solved, so return the result immediately
        if i < self.mep.inputs {
            return unsafe { self.inputs.get_unchecked(i) }.clone();
        }
        // Check if this has been evaluated or not
        let possible = unsafe { self.buff.get_unchecked(i - self.mep.inputs) }.clone();
        match possible {
            // If it has, return the value
            Some(x) => x,
            // If it hasnt been solved
            None => {
                // Get a reference to the opcode
                let op = unsafe { self.mep.program.get_unchecked(i - self.mep.inputs) };
                // Compute the result of the operation, ensuring the inputs are solved beforehand
                let result = (self.mep.processor)(&op.instruction,
                                                  self.op_solved(op.first),
                                                  self.op_solved(op.second));
                // Properly store the Some result to the buffer
                unsafe { *self.buff.get_unchecked_mut(i - self.mep.inputs) = Some(result.clone()) };
                // Return the result
                result
            }
        }
    }
}

impl<'a, Ins, Param, F> Iterator for ResultIterator<'a, Ins, Param, F>
    where F: Fn(&Ins, Param, Param) -> Param,
          Param: Clone
{
    type Item = Param;
    fn next(&mut self) -> Option<Param> {
        match self.solve_iter.next() {
            None => None,
            Some(i) => Some(self.op_solved(i)),
        }
    }
}

#[cfg(test)]
mod tests {
    use rand::{Isaac64Rng, SeedableRng, Rng};
    use super::*;
    use super::super::{Genetic, Stateless};

    fn mutator(_: &mut i32, _: &mut Isaac64Rng) {}
    fn processor(_: &i32, _: i32, _: i32) -> i32 {
        0
    }

    #[test]
    fn new() {
        let a = Mep::new(3,
                         1,
                         10,
                         10,
                         &mut Isaac64Rng::from_seed(&[1, 2, 3, 4]),
                         0..30,
                         processor);

        assert_eq!(a.program.iter().map(|i| i.instruction).collect::<Vec<_>>(),
                   (0..30).collect::<Vec<_>>());
    }

    #[test]
    fn crossover() {
        let mut rng = Isaac64Rng::from_seed(&[1, 2, 3, 4]);
        let (a, b) = {
            let mut clos = || Mep::new(3, 1, 10, 10, &mut rng, 0..30, processor);
            (clos(), clos())
        };
        let old_rngs: Vec<_> = rng.clone().gen_iter::<i32>().take(5).collect();
        let _: Mep<i32, i32, fn(&i32, i32, i32) -> i32> = a.mate(&b, &mut rng);
        // Ensure that rng was used.
        assert!(rng.clone().gen_iter::<i32>().take(5).collect::<Vec<_>>() != old_rngs);
    }

    #[test]
    fn compute() {
        let mut rng = Isaac64Rng::from_seed(&[1, 2, 3, 4]);
        let a = Mep::new(3, 1, 10, 10, &mut rng, 0..30, processor);

        let inputs = [2, 3, 4];
        assert_eq!(a.process(&inputs[..]).collect::<Vec<_>>(), [0]);
    }
}
<commit_msg>wow, tests okay but not pretty<commit_after>extern crate num;
use std::collections::BTreeSet;
use std::cmp;
use rand::Rng;
use std::ops::Range;
use std::iter::Rev;
use super::{Genetic, Stateless};
use std::marker::PhantomData;
use std::fmt::{self, Debug};

/// Defines an opcode for the Mep. Every opcode contains an instruction and two parameter indices. These specify which
/// previous opcodes produced the result required as inputs to this opcode. These parameters can also come from the inputs
/// to the program, which sequentially preceed the internal instructions.
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
struct Opcode<Ins> {
    instruction: Ins,
    first: usize,
    second: usize,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SerialMep<Ins> {
    program: Vec<Opcode<Ins>>,
    unit_mutate_size: usize,
    crossover_points: usize,
    inputs: usize,
    outputs: usize,
}

impl<'a, Ins, Param, F> From<&'a Mep<Ins, Param, F>> for SerialMep<Ins>
    where Ins: Clone
{
    fn from(mep: &'a Mep<Ins, Param, F>) -> Self {
        SerialMep {
            program: mep.program.clone(),
            unit_mutate_size: mep.unit_mutate_size,
            crossover_points: mep.crossover_points,
            inputs: mep.inputs,
            outputs: mep.outputs,
        }
    }
}

/// A multi-expression program represented using a series of operations that can reuse results of previous operations.
pub struct Mep<Ins, Param, F> {
    program: Vec<Opcode<Ins>>,
    unit_mutate_size: usize,
    crossover_points: usize,
    inputs: usize,
    outputs: usize,
    processor: F,
    _phantom: PhantomData<Param>,
}

impl<Ins, Param, F> Debug for Mep<Ins, Param, F>
    where Ins: Debug
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // write!(f, "Mep{{ program: {}, unit_mutate_size: {}, crossover_points: {}, inputs: {}, outputs: {} }}", )
        try!(write!(f, "Mep{{ program: ["));
        if self.program.len() != 0 {
            for op in &self.program[..self.program.len() - 1] {
                try!(write!(f, "{:?}, ", op));
            }
            try!(write!(f, "{:?}", self.program.last().unwrap()));
        }
        write!(f,
               "], unit_mutate_size: {}, crossover_points: {}, inputs: {}, outputs: {} }}",
               self.unit_mutate_size,
               self.crossover_points,
               self.inputs,
               self.outputs)
    }
}

impl<Ins, Param, F> Clone for Mep<Ins, Param, F>
    where Ins: Clone,
          F: Copy
{
    fn clone(&self) -> Self {
        Mep {
            program: self.program.clone(),
            unit_mutate_size: self.unit_mutate_size,
            crossover_points: self.crossover_points,
            inputs: self.inputs,
            outputs: self.outputs,
            processor: self.processor,
            _phantom: PhantomData,
        }
    }
}

impl<Ins, Param, F> Mep<Ins, Param, F> {
    /// Generates a new Mep with a particular size and takes a closure to generate random instructions.
    /// Takes an RNG as well to generate random internal data for each instruction. This Rng is different from the Mep's
    /// Rng, thus it is parameterized separately here.
    pub fn new<I, Rg>(inputs: usize,
                      outputs: usize,
                      unit_mutate_size: usize,
                      crossover_points: usize,
                      rng: &mut Rg,
                      instruction_iter: I,
                      processor: F)
                      -> Self
        where I: ExactSizeIterator<Item = Ins>,
              Rg: Rng,
              F: Fn(&Ins, Param, Param) -> Param
    {
        let outputs_beginning = instruction_iter.len() - outputs;
        Mep {
            program: instruction_iter.enumerate()
                .map(|(index, ins)|
                    // For normal instructions previous outputs may be used.
                    if index < outputs_beginning {
                        Opcode{
                            instruction: ins,
                            first: rng.gen_range(0, index + inputs),
                            second: rng.gen_range(0, index + inputs),
                        }
                    // An output should not be used as an input to another output.
                    } else {
                        Opcode{
                            instruction: ins,
                            first: rng.gen_range(0, outputs_beginning + inputs),
                            second: rng.gen_range(0, outputs_beginning + inputs),
                        }
                    })
                .collect(),
            unit_mutate_size: unit_mutate_size,
            crossover_points: crossover_points,
            inputs: inputs,
            outputs: outputs,
            processor: processor,
            _phantom: PhantomData,
        }
    }

    pub fn new_from_serial_mep(smep: SerialMep<Ins>, processor: F) -> Self {
        Mep {
            program: smep.program,
            unit_mutate_size: smep.unit_mutate_size,
            crossover_points: smep.crossover_points,
            inputs: smep.inputs,
            outputs: smep.outputs,
            processor: processor,
            _phantom: PhantomData,
        }
    }
}

impl<Ins, Param, F, R, M> Genetic<R, M> for Mep<Ins, Param, F>
    where R: Rng,
          Ins: Clone,
          Param: Clone,
          F: Copy,
          M: Fn(&mut Ins, &mut R)
{
    fn mate(&self, rhs: &Self, rng: &mut R) -> Self {
        // Each Mep must have the same amount of inputs
        // TODO: Once Rust implements generic values, this can be made explicit and is not needed
        assert!(self.inputs == rhs.inputs);
        assert!(self.outputs == rhs.outputs);
        // Get the smallest of the two lengths
        let total_instructions = cmp::min(self.program.len(), rhs.program.len());
        let crossover_choice = rng.gen_range(0, 2);
        Mep{program:
            //Generate a randomly sized sequence between 1 and crossover_points
            (0..rng.gen_range(1, cmp::min(total_instructions / 2, {
                if crossover_choice == 0 {self}
                else {rhs}}.crossover_points + 1)))
            //Map these to random crossover points
            .map(|_| rng.gen_range(0, total_instructions))
            //Add total_instructions at the end so we can generate a range with it
            .chain(Some(total_instructions))
            //Sort them by value into BTree, which removes duplicates and orders them
            .fold(BTreeSet::new(), |mut set, i| {set.insert(i); set})
            //Iterate over the sorted values
            .iter()
            //Turn every copy of two, prepending a 0, into a range
            .scan(0, |prev, x| {let out = Some(*prev..*x); *prev = *x; out})
            //Enumerate by index to differentiate odd and even values
            .enumerate()
            //Map even pairs to ranges in parent 0 and odd ones to ranges in parent 1 and expand the ranges
            .flat_map(|(index, range)| {
                {if index % 2 == 0 {self} else {rhs}}.program[range].iter().cloned()
            })
            //Collect all the instruction ranges from each parent
            .collect(),

            unit_mutate_size: if self.unit_mutate_size < rhs.unit_mutate_size {
                rng.gen_range(self.unit_mutate_size, rhs.unit_mutate_size + 1)
            } else {
                rng.gen_range(rhs.unit_mutate_size, self.unit_mutate_size + 1)
            },

            crossover_points: if self.crossover_points < rhs.crossover_points {
                rng.gen_range(self.crossover_points, rhs.crossover_points + 1)
            } else {
                rng.gen_range(rhs.crossover_points, self.crossover_points + 1)
            },

            inputs: self.inputs,
            outputs: self.outputs,
            processor: {if rng.gen_range(0, 2) == 0 {self} else {rhs}}.processor,
            _phantom: PhantomData,
        }
    }

    /// The Mep mutate function operates using the unit_mutate_size. This variable specifies the amount of instructions
    /// for which a single mutation is expect to occour every time mutate is called. This variable can be mutated inside
    /// of mutate, in which case it may never go below 1, but may tend towards infinity in increments of 1. This variable
    /// is implemented as a u64 to permit it to expand unbounded to mutation levels that are so low that mutations
    /// virtually never happen. Allowing this to mutate allows species to find the equilibrium between genomic
    /// adaptability and stability. If a species develops information gathering, then it can adapt intellegently, making
    /// it possibly more beneficial to operate at lower mutation rates. Setting the default mutation rate for species
    /// properly, or allowing it to adapt as the simulation continues, permits species to survive more frequently that
    /// are randomly generated.
    fn mutate(&mut self, mutator: M, rng: &mut R) {
        // Mutate unit_mutate_size
        if rng.gen_range(0, self.unit_mutate_size) == 0 {
            // Make it possibly go up or down by 1
            match rng.gen_range(0, 2) {
                0 => self.unit_mutate_size += 1,
                1 => {
                    if self.unit_mutate_size > 1 {
                        self.unit_mutate_size -= 1
                    }
                }
                _ => unreachable!(),
            }
        }
        // Mutate crossover_points
        if rng.gen_range(0, self.unit_mutate_size) == 0 {
            // Make it possibly go up or down by 1
            match rng.gen_range(0, 2) {
                0 => self.crossover_points += 1,
                1 => {
                    if self.crossover_points > 1 {
                        self.crossover_points -= 1
                    }
                }
                _ => unreachable!(),
            }
        }

        // Mutate the instructions using the mutator
        loop {
            // Choose a random location in the instructions and then add a random value up to the unit_mutate_size
            let choice = rng.gen_range(0, self.program.len() + self.unit_mutate_size);
            // Whenever we choose a location outside the vector reject the choice and end mutation
            if choice >= self.program.len() {
                break;
            }
            let op = &mut self.program[choice];
            // Randomly mutate only one of the things contained here
            match rng.gen_range(0, 3) {
                0 => mutator(&mut op.instruction, rng),
                1 => op.first = rng.gen_range(0, choice + self.inputs),
                2 => op.second = rng.gen_range(0, choice + self.inputs),
                _ => unreachable!(),
            }
        }
    }
}

impl<'a, Ins: 'a, Param: 'a, F: 'a> Stateless<'a, &'a [Param], ResultIterator<'a, Ins, Param, F>> for Mep<Ins, Param, F>
    where F: Fn(&Ins, Param, Param) -> Param,
          Param: Clone
{
    fn process(&'a self, inputs: &'a [Param]) -> ResultIterator<'a, Ins, Param, F> {
// Ensure we have enough opcodes to produce the desired amount of outputs, otherwise the programmer has failed
        assert!(self.outputs <= self.program.len());
        ResultIterator {
            mep: self,
            buff: vec![None; self.program.len()],
            solve_iter: ((self.program.len() + self.inputs - self.outputs)..(self.program.len() +
                                                                             self.inputs))
                .rev(),
            inputs: inputs,
        }
    }
}

pub struct ResultIterator<'a, Ins: 'a, Param: 'a, F: 'a> {
    mep: &'a Mep<Ins, Param, F>,
    buff: Vec<Option<Param>>,
    solve_iter: Rev<Range<usize>>,
    inputs: &'a [Param],
}

impl<'a, Ins, Param, F> ResultIterator<'a, Ins, Param, F>
    where F: Fn(&Ins, Param, Param) -> Param,
          Param: Clone
{
    fn op_solved(&mut self, i: usize) -> Param {
        // If this is an input, it is already solved, so return the result immediately
        if i < self.mep.inputs {
            return unsafe { self.inputs.get_unchecked(i) }.clone();
        }
        // Check if this has been evaluated or not
        let possible = unsafe { self.buff.get_unchecked(i - self.mep.inputs) }.clone();
        match possible {
            // If it has, return the value
            Some(x) => x,
            // If it hasnt been solved
            None => {
                // Get a reference to the opcode
                let op = unsafe { self.mep.program.get_unchecked(i - self.mep.inputs) };
                // Compute the result of the operation, ensuring the inputs are solved beforehand
                let result = (self.mep.processor)(&op.instruction,
                                                  self.op_solved(op.first),
                                                  self.op_solved(op.second));
                // Properly store the Some result to the buffer
                unsafe { *self.buff.get_unchecked_mut(i - self.mep.inputs) = Some(result.clone()) };
                // Return the result
                result
            }
        }
    }
}

impl<'a, Ins, Param, F> Iterator for ResultIterator<'a, Ins, Param, F>
    where F: Fn(&Ins, Param, Param) -> Param,
          Param: Clone
{
    type Item = Param;
    fn next(&mut self) -> Option<Param> {
        match self.solve_iter.next() {
            None => None,
            Some(i) => Some(self.op_solved(i)),
        }
    }
}

#[cfg(test)]
mod tests {
    use rand::{Isaac64Rng, SeedableRng, Rng};
    use super::*;
    use super::super::{Genetic, Stateless};

    fn mutator(_: &mut i32, _: &mut Isaac64Rng) {}
    fn processor(_: &i32, _: i32, _: i32) -> i32 {
        0
    }

    #[test]
    fn new() {
        let a = Mep::new(3,
                         1,
                         10,
                         10,
                         &mut Isaac64Rng::from_seed(&[1, 2, 3, 4]),
                         0..30,
                         processor);

        assert_eq!(a.program.iter().map(|i| i.instruction).collect::<Vec<_>>(),
                   (0..30).collect::<Vec<_>>());
    }

    #[test]
    fn crossover() {
        let mut rng = Isaac64Rng::from_seed(&[1, 2, 3, 4]);
        let (mut a, b) = {
            let mut clos = || {
                Mep::new(3,
                         1,
                         10,
                         10,
                         &mut rng,
                         0..30,
                         processor as fn(&i32, i32, i32) -> i32)
            };
            (clos(), clos())
        };
        let old_rngs: Vec<_> = rng.clone().gen_iter::<i32>().take(5).collect();
        a.mutate(mutator as fn(&mut i32, &mut Isaac64Rng), &mut rng);
        let _: Mep<i32, i32, fn(&i32, i32, i32) -> i32> =
            <Mep<i32, i32, fn(&i32, i32, i32) -> i32> as Genetic<Isaac64Rng, fn(&mut i32, &mut Isaac64Rng)>>::mate(&a, &b, &mut rng);
        // Ensure that rng was used.
        assert!(rng.clone().gen_iter::<i32>().take(5).collect::<Vec<_>>() != old_rngs);
    }

    #[test]
    fn compute() {
        let mut rng = Isaac64Rng::from_seed(&[1, 2, 3, 4]);
        let a = Mep::new(3, 1, 10, 10, &mut rng, 0..30, processor);

        let inputs = [2, 3, 4];
        assert_eq!(a.process(&inputs[..]).collect::<Vec<_>>(), [0]);
    }
}
<|endoftext|>