<commit_before>//! xdg-rs is a utility library to make conforming to the [XDG specification](http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html) easier.
//!
//! Some code borrowed from [rust-xdg](https://github.com/o11c/rust-xdg). ```rust-xdg``` is
//! currently a more complete implementation of the specification. The APIs provided by
//! ```rust-xdg``` and ```xdg-rs``` are different.

use std::error::Error;
use std::io;
use std::io::fs::PathExtensions;
use std::iter::IteratorExt;
use std::os;

/// Get the data home directory given a closure that returns the the value of an environment variable.
/// This method allows having a custom environment.
///
/// If ```$XDG_DATA_HOME``` is not set, it returns ```$HOME/.local/share```.
pub fn get_data_home_from_env(getenv: |&str| -> Option<String>) -> Path {
    getenv_path(getenv, "XDG_DATA_HOME").unwrap_or(
        os::homedir().unwrap().join(".local/share")
    )
}

/// Get the data home directory.
///
/// If ```$XDG_DATA_HOME``` is not set, it returns ```$HOME/.local/share```.
pub fn get_data_home() -> Path {
    get_data_home_from_env(os::getenv)
}

/// Get the default data directories given a closure that returns the the value of an environment variable.
/// This method allows having a custom environment.
///
/// If ```$XDG_DATA_DIRS``` is not set, it returns ```[/usr/local/share, /usr/share]```.
pub fn get_data_dirs_from_env(getenv: |&str| -> Option<String>) -> Vec<Path> {
    let default_paths = "/usr/local/share:/usr/share".to_string();
    let paths = match getenv("XDG_DATA_DIRS") {
        Some(paths) => {
            if paths.len() > 0 {
                paths
            } else {
                default_paths
            }
        },
        None => default_paths
    };

    paths.as_slice()
        .split(':')
        .map(Path::new)
        .collect()
}

/// Get the data directories.
///
/// If ```$XDG_DATA_DIRS``` is not set, it returns ```[/usr/local/share, /usr/share]```.
pub fn get_data_dirs() -> Vec<Path> {
    get_data_dirs_from_env(os::getenv)
}

/// Get the config home directory given a closure that returns the the value of an environment variable.
/// This method allows having a custom environment.
///
/// If ```$XDG_CONFIG_HOME``` is not set, it returns ```$HOME/.config```.
pub fn get_config_home_from_env(getenv: |&str| -> Option<String>) -> Path {
    getenv_path(getenv, "XDG_CONFIG_HOME").unwrap_or(
        os::homedir().unwrap().join(".config")
    )
}
/// Get the config home directory.
///
/// If ```$XDG_CONFIG_HOME``` is not set, it returns ```$HOME/.config```.
pub fn get_config_home() -> Path {
    get_config_home_from_env(os::getenv)
}

/// Get the default config directories given a closure that returns the the value of an environment variable.
/// This method allows having a custom environment.
///
/// If ```$XDG_CONFIG_DIRS``` is not set, it returns ```[/etc/xdg]```.
pub fn get_config_dirs_from_env(getenv: |&str| -> Option<String>) -> Vec<Path> {
    let default_paths = "/etc/xdg".to_string();
    let paths = match getenv("XDG_CONFIG_DIRS") {
        Some(paths) => {
            if paths.len() > 0 {
                paths
            } else {
                default_paths
            }
        },
        None => default_paths
    };

    paths.as_slice()
        .split(':')
        .map(Path::new)
        .collect()
}

/// Get the config directories.
///
/// If ```$XDG_CONFIG_DIRS``` is not set, it returns ```[/etc/xdg]```.
pub fn get_config_dirs() -> Vec<Path> {
    get_config_dirs_from_env(os::getenv)
}

/// Get the cache home directory given a closure that returns the the value of an environment variable.
/// This method allows having a custom environment.
///
/// If ```$XDG_CACHE_HOME``` is not set, it returns ```$HOME/.cache```.
pub fn get_cache_home_from_env(getenv: |&str| -> Option<String>) -> Path {
    getenv_path(getenv, "XDG_CACHE_HOME").unwrap_or(
        os::homedir().unwrap().join(".cache")
    )
}

/// Get the cache home directory.
///
/// If ```$XDG_CACHE_HOME``` is not set, it returns ```$HOME/.cache```.
pub fn get_cache_home() -> Path {
    get_cache_home_from_env(os::getenv)
}

/// Get $XDG_RUNTIME_DIR if found in the environment.
///
/// Returns None if ```$XDG_RUNTIME_PATH``` is not set, in which case it is up to the application
/// to fallback to a location that conforms to the specification.
pub fn get_runtime_dir_from_env(getenv: |&str| -> Option<String>) -> Option<Path> {
    getenv_path(getenv, "XDG_RUNTIME_DIR")
}

pub fn get_runtime_dir() -> Option<Path> {
    getenv_path(os::getenv, "XDG_RUNTIME_DIR")
}

/// Check that the value set for ```$XDG_RUNTIME_DIR``` meets the requirements of the specification
///
/// >$XDG_RUNTIME_DIR defines the base directory relative to which user-specific non-essential runtime files and other file objects (such as sockets, named pipes, ...) should be stored. The directory MUST be owned by the user, and he MUST be the only one having read and write access to it. Its Unix access mode MUST be 0700.
/// >
/// >The lifetime of the directory MUST be bound to the user being logged in. It MUST be created when the user first logs in and if the user fully logs out the directory MUST be removed. If the user logs in more than once he should get pointed to the same directory, and it is mandatory that the directory continues to exist from his first login to his last logout on the system, and not removed in between. Files in the directory MUST not survive reboot or a full logout/login cycle.
/// >
/// >The directory MUST be on a local file system and not shared with any other system. The directory MUST by fully-featured by the standards of the operating system. More specifically, on Unix-like operating systems AF_UNIX sockets, symbolic links, hard links, proper permissions, file locking, sparse files, memory mapping, file change notifications, a reliable hard link count must be supported, and no restrictions on the file name character set should be imposed. Files in this directory MAY be subjected to periodic clean-up. To ensure that your files are not removed, they should have their access time timestamp modified at least once every 6 hours of monotonic time or the 'sticky' bit should be set on the file.
pub fn test_runtime_dir(path: &Path) -> Result<(), String> {
    match path.stat() {
        Ok(stat) => {
            if stat.perm.intersects(io::GROUP_RWX | io::OTHER_RWX) {
                Err("Incorrect permissions".to_string())
            } else {
                Ok(())
            }
        },

        Err(error) => Err(error.description().to_string())
    }
}

/// Get an environment variable's value as a Path.
fn getenv_path(getenv: |&str| -> Option<String>, env_var: &str) -> Option<Path> {
    let path = getenv(env_var);
    match path {
        Some(path) => {
            let path = Path::new(path);
            if path.is_absolute() {
                Some(path)
            } else {
                None
            }
        },

        None => None
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use std::iter::IteratorExt;
    use std::os;

    #[test]
    fn test_env_with_no_xdg_vars() {
        let mut custom_env = HashMap::new();
        custom_env.insert("dummy", "".to_string());

        assert!(super::get_data_home_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == os::homedir().unwrap().join(".local/share"));
        assert!(super::get_data_dirs_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == vec![Path::new("/usr/local/share"), Path::new("/usr/share")]);
        assert!(super::get_config_home_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == os::homedir().unwrap().join(".config"));
        assert!(super::get_config_dirs_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == vec![Path::new("/etc/xdg")]);
        assert!(super::get_cache_home_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == os::homedir().unwrap().join(".cache"));
        assert!(super::get_runtime_dir_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == None);
    }

    #[test]
    fn test_env_with_empty_xdg_vars() {
        let mut custom_env = HashMap::new();
        custom_env.insert("XDG_DATA_HOME", "".to_string());
        custom_env.insert("XDG_DATA_DIRS", "".to_string());
        custom_env.insert("XDG_CONFIG_HOME", "".to_string());
        custom_env.insert("XDG_CONFIG_DIRS", "".to_string());
        custom_env.insert("XDG_CACHE_HOME", "".to_string());

        assert!(super::get_data_home_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == os::homedir().unwrap().join(".local/share"));
        assert!(super::get_data_dirs_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == vec![Path::new("/usr/local/share"), Path::new("/usr/share")]);
        assert!(super::get_config_home_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == os::homedir().unwrap().join(".config"));
        assert!(super::get_config_dirs_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == vec![Path::new("/etc/xdg")]);
        assert!(super::get_cache_home_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == os::homedir().unwrap().join(".cache"));
        assert!(super::get_runtime_dir_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == None);
    }

    #[test]
    fn test_env_with_xdg_vars() {
        let cwd = os::make_absolute(&Path::new(".")).unwrap();
        let mut custom_env = HashMap::new();
        custom_env.insert("XDG_DATA_HOME", format!("{}/user/data", cwd.display()));
        custom_env.insert("XDG_DATA_DIRS", format!("{}/share/data:{}/local/data", cwd.display(), cwd.display()));
        custom_env.insert("XDG_CONFIG_HOME", format!("{}/user/config", cwd.display()));
        custom_env.insert("XDG_CONFIG_DIRS", format!("{}/config:{}/local/config", cwd.display(), cwd.display()));
        custom_env.insert("XDG_CACHE_HOME", format!("{}/user/cache", cwd.display()));

        assert!(super::get_data_home_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == custom_env.get("XDG_DATA_HOME").map(Path::new).unwrap());
        assert!(super::get_data_dirs_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == custom_env["XDG_DATA_DIRS"]
                    .as_slice()
                    .split(':')
                    .map(Path::new)
                    .collect::<Vec<Path>>());
        assert!(super::get_config_home_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == custom_env.get("XDG_CONFIG_HOME").map(Path::new).unwrap());
        assert!(super::get_config_dirs_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == custom_env["XDG_CONFIG_DIRS"]
                    .as_slice()
                    .split(':')
                    .map(Path::new)
                    .collect::<Vec<Path>>());
        assert!(super::get_cache_home_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == custom_env.get("XDG_CACHE_HOME").map(Path::new).unwrap());
    }
}
<commit_msg>use &* slicing syntax<commit_after>//! xdg-rs is a utility library to make conforming to the [XDG specification](http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html) easier.
//!
//! Some code borrowed from [rust-xdg](https://github.com/o11c/rust-xdg). ```rust-xdg``` is
//! currently a more complete implementation of the specification. The APIs provided by
//! ```rust-xdg``` and ```xdg-rs``` are different.

use std::error::Error;
use std::io;
use std::io::fs::PathExtensions;
use std::iter::IteratorExt;
use std::os;

/// Get the data home directory given a closure that returns the the value of an environment variable.
/// This method allows having a custom environment.
///
/// If ```$XDG_DATA_HOME``` is not set, it returns ```$HOME/.local/share```.
pub fn get_data_home_from_env(getenv: |&str| -> Option<String>) -> Path {
    getenv_path(getenv, "XDG_DATA_HOME").unwrap_or(
        os::homedir().unwrap().join(".local/share")
    )
}

/// Get the data home directory.
///
/// If ```$XDG_DATA_HOME``` is not set, it returns ```$HOME/.local/share```.
pub fn get_data_home() -> Path {
    get_data_home_from_env(os::getenv)
}

/// Get the default data directories given a closure that returns the the value of an environment variable.
/// This method allows having a custom environment.
///
/// If ```$XDG_DATA_DIRS``` is not set, it returns ```[/usr/local/share, /usr/share]```.
pub fn get_data_dirs_from_env(getenv: |&str| -> Option<String>) -> Vec<Path> {
    let default_paths = "/usr/local/share:/usr/share".to_string();
    let paths = match getenv("XDG_DATA_DIRS") {
        Some(paths) => {
            if paths.len() > 0 {
                paths
            } else {
                default_paths
            }
        },
        None => default_paths
    };

    (&*paths).split(':')
        .map(Path::new)
        .collect()
}

/// Get the data directories.
///
/// If ```$XDG_DATA_DIRS``` is not set, it returns ```[/usr/local/share, /usr/share]```.
pub fn get_data_dirs() -> Vec<Path> {
    get_data_dirs_from_env(os::getenv)
}

/// Get the config home directory given a closure that returns the the value of an environment variable.
/// This method allows having a custom environment.
///
/// If ```$XDG_CONFIG_HOME``` is not set, it returns ```$HOME/.config```.
pub fn get_config_home_from_env(getenv: |&str| -> Option<String>) -> Path {
    getenv_path(getenv, "XDG_CONFIG_HOME").unwrap_or(
        os::homedir().unwrap().join(".config")
    )
}
/// Get the config home directory.
///
/// If ```$XDG_CONFIG_HOME``` is not set, it returns ```$HOME/.config```.
pub fn get_config_home() -> Path {
    get_config_home_from_env(os::getenv)
}

/// Get the default config directories given a closure that returns the the value of an environment variable.
/// This method allows having a custom environment.
///
/// If ```$XDG_CONFIG_DIRS``` is not set, it returns ```[/etc/xdg]```.
pub fn get_config_dirs_from_env(getenv: |&str| -> Option<String>) -> Vec<Path> {
    let default_paths = "/etc/xdg".to_string();
    let paths = match getenv("XDG_CONFIG_DIRS") {
        Some(paths) => {
            if paths.len() > 0 {
                paths
            } else {
                default_paths
            }
        },
        None => default_paths
    };

    (&*paths).split(':')
        .map(Path::new)
        .collect()
}

/// Get the config directories.
///
/// If ```$XDG_CONFIG_DIRS``` is not set, it returns ```[/etc/xdg]```.
pub fn get_config_dirs() -> Vec<Path> {
    get_config_dirs_from_env(os::getenv)
}

/// Get the cache home directory given a closure that returns the the value of an environment variable.
/// This method allows having a custom environment.
///
/// If ```$XDG_CACHE_HOME``` is not set, it returns ```$HOME/.cache```.
pub fn get_cache_home_from_env(getenv: |&str| -> Option<String>) -> Path {
    getenv_path(getenv, "XDG_CACHE_HOME").unwrap_or(
        os::homedir().unwrap().join(".cache")
    )
}

/// Get the cache home directory.
///
/// If ```$XDG_CACHE_HOME``` is not set, it returns ```$HOME/.cache```.
pub fn get_cache_home() -> Path {
    get_cache_home_from_env(os::getenv)
}

/// Get $XDG_RUNTIME_DIR if found in the environment.
///
/// Returns None if ```$XDG_RUNTIME_PATH``` is not set, in which case it is up to the application
/// to fallback to a location that conforms to the specification.
pub fn get_runtime_dir_from_env(getenv: |&str| -> Option<String>) -> Option<Path> {
    getenv_path(getenv, "XDG_RUNTIME_DIR")
}

pub fn get_runtime_dir() -> Option<Path> {
    getenv_path(os::getenv, "XDG_RUNTIME_DIR")
}

/// Check that the value set for ```$XDG_RUNTIME_DIR``` meets the requirements of the specification
///
/// >$XDG_RUNTIME_DIR defines the base directory relative to which user-specific non-essential runtime files and other file objects (such as sockets, named pipes, ...) should be stored. The directory MUST be owned by the user, and he MUST be the only one having read and write access to it. Its Unix access mode MUST be 0700.
/// >
/// >The lifetime of the directory MUST be bound to the user being logged in. It MUST be created when the user first logs in and if the user fully logs out the directory MUST be removed. If the user logs in more than once he should get pointed to the same directory, and it is mandatory that the directory continues to exist from his first login to his last logout on the system, and not removed in between. Files in the directory MUST not survive reboot or a full logout/login cycle.
/// >
/// >The directory MUST be on a local file system and not shared with any other system. The directory MUST by fully-featured by the standards of the operating system. More specifically, on Unix-like operating systems AF_UNIX sockets, symbolic links, hard links, proper permissions, file locking, sparse files, memory mapping, file change notifications, a reliable hard link count must be supported, and no restrictions on the file name character set should be imposed. Files in this directory MAY be subjected to periodic clean-up. To ensure that your files are not removed, they should have their access time timestamp modified at least once every 6 hours of monotonic time or the 'sticky' bit should be set on the file.
pub fn test_runtime_dir(path: &Path) -> Result<(), String> {
    match path.stat() {
        Ok(stat) => {
            if stat.perm.intersects(io::GROUP_RWX | io::OTHER_RWX) {
                Err("Incorrect permissions".to_string())
            } else {
                Ok(())
            }
        },

        Err(error) => Err(error.description().to_string())
    }
}

/// Get an environment variable's value as a Path.
fn getenv_path(getenv: |&str| -> Option<String>, env_var: &str) -> Option<Path> {
    let path = getenv(env_var);
    match path {
        Some(path) => {
            let path = Path::new(path);
            if path.is_absolute() {
                Some(path)
            } else {
                None
            }
        },

        None => None
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use std::iter::IteratorExt;
    use std::os;

    #[test]
    fn test_env_with_no_xdg_vars() {
        let mut custom_env = HashMap::new();
        custom_env.insert("dummy", "".to_string());

        assert!(super::get_data_home_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == os::homedir().unwrap().join(".local/share"));
        assert!(super::get_data_dirs_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == vec![Path::new("/usr/local/share"), Path::new("/usr/share")]);
        assert!(super::get_config_home_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == os::homedir().unwrap().join(".config"));
        assert!(super::get_config_dirs_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == vec![Path::new("/etc/xdg")]);
        assert!(super::get_cache_home_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == os::homedir().unwrap().join(".cache"));
        assert!(super::get_runtime_dir_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == None);
    }

    #[test]
    fn test_env_with_empty_xdg_vars() {
        let mut custom_env = HashMap::new();
        custom_env.insert("XDG_DATA_HOME", "".to_string());
        custom_env.insert("XDG_DATA_DIRS", "".to_string());
        custom_env.insert("XDG_CONFIG_HOME", "".to_string());
        custom_env.insert("XDG_CONFIG_DIRS", "".to_string());
        custom_env.insert("XDG_CACHE_HOME", "".to_string());

        assert!(super::get_data_home_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == os::homedir().unwrap().join(".local/share"));
        assert!(super::get_data_dirs_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == vec![Path::new("/usr/local/share"), Path::new("/usr/share")]);
        assert!(super::get_config_home_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == os::homedir().unwrap().join(".config"));
        assert!(super::get_config_dirs_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == vec![Path::new("/etc/xdg")]);
        assert!(super::get_cache_home_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == os::homedir().unwrap().join(".cache"));
        assert!(super::get_runtime_dir_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == None);
    }

    #[test]
    fn test_env_with_xdg_vars() {
        let cwd = os::make_absolute(&Path::new(".")).unwrap();
        let mut custom_env = HashMap::new();
        custom_env.insert("XDG_DATA_HOME", format!("{}/user/data", cwd.display()));
        custom_env.insert("XDG_DATA_DIRS", format!("{}/share/data:{}/local/data", cwd.display(), cwd.display()));
        custom_env.insert("XDG_CONFIG_HOME", format!("{}/user/config", cwd.display()));
        custom_env.insert("XDG_CONFIG_DIRS", format!("{}/config:{}/local/config", cwd.display(), cwd.display()));
        custom_env.insert("XDG_CACHE_HOME", format!("{}/user/cache", cwd.display()));

        assert!(super::get_data_home_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == custom_env.get("XDG_DATA_HOME").map(Path::new).unwrap());
        assert!(super::get_data_dirs_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == (&*custom_env["XDG_DATA_DIRS"])
                    .split(':')
                    .map(Path::new)
                    .collect::<Vec<Path>>());
        assert!(super::get_config_home_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == custom_env.get("XDG_CONFIG_HOME").map(Path::new).unwrap());
        assert!(super::get_config_dirs_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == (&*custom_env["XDG_CONFIG_DIRS"])
                    .split(':')
                    .map(Path::new)
                    .collect::<Vec<Path>>());
        assert!(super::get_cache_home_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == custom_env.get("XDG_CACHE_HOME").map(Path::new).unwrap());
    }
}
<|endoftext|>


<commit_before>extern crate rand;

use std::collections::BTreeMap;
use std::cmp;
use innovation::Innovation;
use rand::{Rng, Closed01};

mod innovation;

trait Gene: Clone {
    fn weight_distance(&self, other: &Self) -> f64;
}

enum NodeType {
    Input,
    Output,
    Hidden,
}

struct NodeGene {
    node_type: NodeType,
}

// To avoid node collisions we use Innovation numbers instead of node
// ids.
#[derive(Clone)]
struct LinkGene {
    // This points to the NodeGene of that innovation
    source_node_gene: Innovation,
    // This points to the NodeGene of that innovation
    target_node_gene: Innovation,
    weight: f64,
    active: bool,
}

impl Gene for LinkGene {
    fn weight_distance(&self, other: &LinkGene) -> f64 {
        self.weight - other.weight
    }
}

struct Genome {
    link_genes: BTreeMap<Innovation, LinkGene>,
    node_genes: BTreeMap<Innovation, NodeGene>,
}

enum Correlation<'a, T: 'a> {
    Matching(&'a T, &'a T),
    DisjointLeft(&'a T),
    DisjointRight(&'a T),
    ExcessLeft(&'a T),
    ExcessRight(&'a T),
}

/// Correlate the genes in ```genes_left``` with those in ```genes_right```.
fn correlate<'a, T, F>(genes_left: &'a BTreeMap<Innovation, T>,
                       genes_right: &'a BTreeMap<Innovation, T>,
                       f: &mut F)
    where F: FnMut(Innovation, Correlation<'a, T>)
{
    let range_left = innovation::innovation_range(genes_left);
    let range_right = innovation::innovation_range(genes_right);

    for (innov_left, gene_left) in genes_left.iter() {
        if innov_left.is_within(&range_right) {
            match genes_right.get(innov_left) {
                Some(gene_right) => f(*innov_left, Correlation::Matching(gene_left, gene_right)),
                None => f(*innov_left, Correlation::DisjointLeft(gene_left)),
            }
        } else {
            f(*innov_left, Correlation::ExcessLeft(gene_left))
        }
    }

    for (innov_right, gene_right) in genes_right.iter() {
        if innov_right.is_within(&range_left) {
            if !genes_left.contains_key(innov_right) {
                f(*innov_right, Correlation::DisjointRight(gene_right))
            }
        } else {
            f(*innov_right, Correlation::ExcessRight(gene_right))
        }
    }
}

struct CompatibilityCoefficients {
    excess: f64,
    disjoint: f64,
    weight: f64,
}

/// Calculates the compatibility between two gene lists.
fn compatibility<T: Gene>(genes1: &BTreeMap<Innovation, T>,
                          genes2: &BTreeMap<Innovation, T>,
                          coeff: &CompatibilityCoefficients)
                          -> f64 {
    let max_len = cmp::max(genes1.len(), genes2.len());
    assert!(max_len > 0);

    let mut matching = 0;
    let mut disjoint = 0;
    let mut excess = 0;
    let mut weight_dist = 0.0;

    correlate(genes1,
              genes2,
              &mut |_, correlation| {
                  match correlation {
                      Correlation::Matching(gene_left, gene_right) => {
                          matching += 1;
                          weight_dist += gene_left.weight_distance(gene_right).abs();
                      }
                      Correlation::DisjointLeft(_) | Correlation::DisjointRight(_) => {
                          disjoint += 1;
                      }
                      Correlation::ExcessLeft(_) | Correlation::ExcessRight(_) => {
                          excess += 1;
                      }
                  }
              });

    assert!(2 * matching + disjoint + excess == genes1.len() + genes2.len());

    coeff.excess * (excess as f64) / (max_len as f64) +
    coeff.disjoint * (disjoint as f64) / (max_len as f64) +
    coeff.weight *
    if matching > 0 {
        weight_dist / (matching as f64)
    } else {
        0.0
    }
}

/// These describe the probabilities to take a gene from one of the
/// parents during crossover.
/// XXX: It's probably faster to not use floats here.
struct CrossoverProbabilities {
    /// Probability to take a matching gene from the fitter (first) parent.
    prob_match1: Closed01<f32>,

    /// Probability to take a disjoint gene from the fitter (first) parent.
    prob_disjoint1: Closed01<f32>,

    /// Probability to take an excess gene from the fitter (first) parent.
    prob_excess1: Closed01<f32>,

    /// Probability to take a disjoint gene from the less fit parent.
    prob_disjoint2: Closed01<f32>,

    /// Probability to take an excess gene from the less fit parent.
    prob_excess2: Closed01<f32>,
}

fn is_probable<R: Rng>(prob: &Closed01<f32>, rng: &mut R) -> bool {
    if prob.0 < 1.0 {
        let v: f32 = rng.gen(); // half open [0, 1)
        v < prob.0
    } else {
        true
    }
}

/// We assume ```parent1``` to be the fitter parent. Takes gene
/// either from ```parent1``` or ```parent2``` according to
/// the probabilities specified and the relative fitness of the parents.
fn crossover<T: Clone, R: Rng>(parent1: &BTreeMap<Innovation, T>,
                               parent2: &BTreeMap<Innovation, T>,
                               p: &CrossoverProbabilities,
                               rng: &mut R)
                               -> BTreeMap<Innovation, T> {

    let mut offspring = BTreeMap::new();

    correlate(parent1,
              parent2,
              &mut |innov, correlation| {
                  match correlation {
                      Correlation::Matching(gene_left, gene_right) => {
                          if is_probable(&p.prob_match1, rng) {
                              offspring.insert(innov, gene_left.clone());
                          } else {
                              offspring.insert(innov, gene_right.clone());
                          }
                      }

                      Correlation::DisjointLeft(gene_left) => {
                          if is_probable(&p.prob_disjoint1, rng) {
                              offspring.insert(innov, gene_left.clone());
                          }
                      }

                      Correlation::DisjointRight(gene_right) => {
                          if is_probable(&p.prob_disjoint2, rng) {
                              offspring.insert(innov, gene_right.clone());
                          }
                      }

                      Correlation::ExcessLeft(gene_left) => {
                          if is_probable(&p.prob_excess1, rng) {
                              offspring.insert(innov, gene_left.clone());
                          }
                      }

                      Correlation::ExcessRight(gene_right) => {
                          if is_probable(&p.prob_excess2, rng) {
                              offspring.insert(innov, gene_right.clone());
                          }
                      }
                  }
              });

    offspring
}

type Fitness = f64;

// A niche can never be empty!
struct Niche<'a> {
    genomes: Vec<(Fitness, &'a Genome)>,
    fitness_sum: Fitness,
}

impl<'a> Niche<'a> {
    fn new_with(fitness: Fitness, genome: &'a Genome) -> Niche<'a> {
        Niche {
            genomes: vec![(fitness, genome)],
            fitness_sum: fitness,
        }
    }

    fn mean_fitness(&self) -> Fitness {
        assert!(self.genomes.len() > 0);
        self.fitness_sum / (self.genomes.len() as Fitness)
    }

    fn add(&mut self, fitness: Fitness, genome: &'a Genome) {
        assert!(self.genomes.len() > 0);
        self.genomes.push((fitness, genome));
        self.fitness_sum += fitness;
    }
}

struct Population {
    genomes: Vec<(Fitness, Box<Genome>)>,
}

impl Population {
    // 1. sort whole popluation into niches
    // 2. calculate the number of offspring for each niche.
    // 3. each niche produces offspring.
    //    - sort each niche according to the fitness value.
    //    - determine the elitist size. those are always copied into the new generation.
    //    - r% of the best genomes produce offspring
    //
    fn produce_offspring(&self) {}

    // Sort the whole population into niches
    fn sort_into_niches<'a, R: Rng>(&'a self,
                                    rng: &mut R,
                                    threshold: f64,
                                    coeff: &CompatibilityCoefficients)
                                    -> Vec<Niche<'a>> {
        let mut niches: Vec<Niche> = Vec::new();

        'outer: for &(fitness, ref genome) in self.genomes.iter() {
            for niche in niches.iter_mut() {
                // Is this genome compatible with this niche? Test against a random genome.
                let compatible = match rng.choose(&niche.genomes) {
                    Some(&(_, probe)) => {
                        compatibility(&probe.link_genes, &genome.link_genes, coeff) < threshold
                    }
                    // If a niche is empty, a genome always is compatible
                    None => true,
                };
                if compatible {
                    niche.add(fitness, &*genome);
                    continue 'outer;
                }
            }
            // if no compatible niche was found, insert into a new niche.
            niches.push(Niche::new_with(fitness, &*genome));
        }

        niches
    }
}
<commit_msg>Move Genomes out of the Population instead of storing references<commit_after>extern crate rand;

use std::collections::BTreeMap;
use std::cmp;
use innovation::Innovation;
use rand::{Rng, Closed01};

mod innovation;

trait Gene: Clone {
    fn weight_distance(&self, other: &Self) -> f64;
}

enum NodeType {
    Input,
    Output,
    Hidden,
}

struct NodeGene {
    node_type: NodeType,
}

// To avoid node collisions we use Innovation numbers instead of node
// ids.
#[derive(Clone)]
struct LinkGene {
    // This points to the NodeGene of that innovation
    source_node_gene: Innovation,
    // This points to the NodeGene of that innovation
    target_node_gene: Innovation,
    weight: f64,
    active: bool,
}

impl Gene for LinkGene {
    fn weight_distance(&self, other: &LinkGene) -> f64 {
        self.weight - other.weight
    }
}

struct Genome {
    link_genes: BTreeMap<Innovation, LinkGene>,
    node_genes: BTreeMap<Innovation, NodeGene>,
}

enum Correlation<'a, T: 'a> {
    Matching(&'a T, &'a T),
    DisjointLeft(&'a T),
    DisjointRight(&'a T),
    ExcessLeft(&'a T),
    ExcessRight(&'a T),
}

/// Correlate the genes in ```genes_left``` with those in ```genes_right```.
fn correlate<'a, T, F>(genes_left: &'a BTreeMap<Innovation, T>,
                       genes_right: &'a BTreeMap<Innovation, T>,
                       f: &mut F)
    where F: FnMut(Innovation, Correlation<'a, T>)
{
    let range_left = innovation::innovation_range(genes_left);
    let range_right = innovation::innovation_range(genes_right);

    for (innov_left, gene_left) in genes_left.iter() {
        if innov_left.is_within(&range_right) {
            match genes_right.get(innov_left) {
                Some(gene_right) => f(*innov_left, Correlation::Matching(gene_left, gene_right)),
                None => f(*innov_left, Correlation::DisjointLeft(gene_left)),
            }
        } else {
            f(*innov_left, Correlation::ExcessLeft(gene_left))
        }
    }

    for (innov_right, gene_right) in genes_right.iter() {
        if innov_right.is_within(&range_left) {
            if !genes_left.contains_key(innov_right) {
                f(*innov_right, Correlation::DisjointRight(gene_right))
            }
        } else {
            f(*innov_right, Correlation::ExcessRight(gene_right))
        }
    }
}

struct CompatibilityCoefficients {
    excess: f64,
    disjoint: f64,
    weight: f64,
}

/// Calculates the compatibility between two gene lists.
fn compatibility<T: Gene>(genes1: &BTreeMap<Innovation, T>,
                          genes2: &BTreeMap<Innovation, T>,
                          coeff: &CompatibilityCoefficients)
                          -> f64 {
    let max_len = cmp::max(genes1.len(), genes2.len());
    assert!(max_len > 0);

    let mut matching = 0;
    let mut disjoint = 0;
    let mut excess = 0;
    let mut weight_dist = 0.0;

    correlate(genes1,
              genes2,
              &mut |_, correlation| {
                  match correlation {
                      Correlation::Matching(gene_left, gene_right) => {
                          matching += 1;
                          weight_dist += gene_left.weight_distance(gene_right).abs();
                      }
                      Correlation::DisjointLeft(_) | Correlation::DisjointRight(_) => {
                          disjoint += 1;
                      }
                      Correlation::ExcessLeft(_) | Correlation::ExcessRight(_) => {
                          excess += 1;
                      }
                  }
              });

    assert!(2 * matching + disjoint + excess == genes1.len() + genes2.len());

    coeff.excess * (excess as f64) / (max_len as f64) +
    coeff.disjoint * (disjoint as f64) / (max_len as f64) +
    coeff.weight *
    if matching > 0 {
        weight_dist / (matching as f64)
    } else {
        0.0
    }
}

/// These describe the probabilities to take a gene from one of the
/// parents during crossover.
/// XXX: It's probably faster to not use floats here.
struct CrossoverProbabilities {
    /// Probability to take a matching gene from the fitter (first) parent.
    prob_match1: Closed01<f32>,

    /// Probability to take a disjoint gene from the fitter (first) parent.
    prob_disjoint1: Closed01<f32>,

    /// Probability to take an excess gene from the fitter (first) parent.
    prob_excess1: Closed01<f32>,

    /// Probability to take a disjoint gene from the less fit parent.
    prob_disjoint2: Closed01<f32>,

    /// Probability to take an excess gene from the less fit parent.
    prob_excess2: Closed01<f32>,
}

fn is_probable<R: Rng>(prob: &Closed01<f32>, rng: &mut R) -> bool {
    if prob.0 < 1.0 {
        let v: f32 = rng.gen(); // half open [0, 1)
        v < prob.0
    } else {
        true
    }
}

/// We assume ```parent1``` to be the fitter parent. Takes gene
/// either from ```parent1``` or ```parent2``` according to
/// the probabilities specified and the relative fitness of the parents.
fn crossover<T: Clone, R: Rng>(parent1: &BTreeMap<Innovation, T>,
                               parent2: &BTreeMap<Innovation, T>,
                               p: &CrossoverProbabilities,
                               rng: &mut R)
                               -> BTreeMap<Innovation, T> {

    let mut offspring = BTreeMap::new();

    correlate(parent1,
              parent2,
              &mut |innov, correlation| {
                  match correlation {
                      Correlation::Matching(gene_left, gene_right) => {
                          if is_probable(&p.prob_match1, rng) {
                              offspring.insert(innov, gene_left.clone());
                          } else {
                              offspring.insert(innov, gene_right.clone());
                          }
                      }

                      Correlation::DisjointLeft(gene_left) => {
                          if is_probable(&p.prob_disjoint1, rng) {
                              offspring.insert(innov, gene_left.clone());
                          }
                      }

                      Correlation::DisjointRight(gene_right) => {
                          if is_probable(&p.prob_disjoint2, rng) {
                              offspring.insert(innov, gene_right.clone());
                          }
                      }

                      Correlation::ExcessLeft(gene_left) => {
                          if is_probable(&p.prob_excess1, rng) {
                              offspring.insert(innov, gene_left.clone());
                          }
                      }

                      Correlation::ExcessRight(gene_right) => {
                          if is_probable(&p.prob_excess2, rng) {
                              offspring.insert(innov, gene_right.clone());
                          }
                      }
                  }
              });

    offspring
}

type Fitness = f64;

// A niche can never be empty!
struct Niche {
    genomes: Vec<(Fitness, Box<Genome>)>,
    fitness_sum: Fitness,
}

impl Niche {
    fn new_with(fitness: Fitness, genome: Box<Genome>) -> Niche {
        Niche {
            genomes: vec![(fitness, genome)],
            fitness_sum: fitness,
        }
    }

    fn mean_fitness(&self) -> Fitness {
        assert!(self.genomes.len() > 0);
        self.fitness_sum / (self.genomes.len() as Fitness)
    }

    fn add(&mut self, fitness: Fitness, genome: Box<Genome>) {
        assert!(self.genomes.len() > 0);
        self.genomes.push((fitness, genome));
        self.fitness_sum += fitness;
    }
}

struct Population {
    genomes: Vec<(Fitness, Box<Genome>)>,
}

impl Population {
    // 1. sort whole popluation into niches
    // 2. calculate the number of offspring for each niche.
    // 3. each niche produces offspring.
    //    - sort each niche according to the fitness value.
    //    - determine the elitist size. those are always copied into the new generation.
    //    - r% of the best genomes produce offspring
    //
    fn produce_offspring(self) {}

    // Partitions the whole population into species (niches)
    fn partition<R: Rng>(self,
                         rng: &mut R,
                         threshold: f64,
                         coeff: &CompatibilityCoefficients)
                         -> Vec<Niche> {
        let mut niches: Vec<Niche> = Vec::new();

        'outer: for (fitness, genome) in self.genomes.into_iter() {
            for niche in niches.iter_mut() {
                // Is this genome compatible with this niche? Test against a random genome.
                let compatible = match rng.choose(&niche.genomes) {
                    Some(&(_, ref probe)) => {
                        compatibility(&probe.link_genes, &genome.link_genes, coeff) < threshold
                    }
                    // If a niche is empty, a genome always is compatible
                    None => true,
                };
                if compatible {
                    niche.add(fitness, genome);
                    continue 'outer;
                }
            }
            // if no compatible niche was found, insert into a new niche.
            niches.push(Niche::new_with(fitness, genome));
        }

        niches
    }
}
<|endoftext|>


<commit_before>#![warn(missing_docs)]
#![feature(slice_patterns)]

//! rebind
//! =========
//!
//! A library for binding input keys to actions, and modifying mouse behaviour. Keys can be
//! bound to actions, and then translated during runtime. `Keys` are mapped to `Actions` using
//! a `HashMap`, so lookup time is constant.

extern crate input;
extern crate itertools;
extern crate window;
extern crate rustc_serialize;
extern crate viewport;

mod builder;

#[cfg(test)]
mod test;

use input::{Input, Button, Motion};
use window::Size;
use std::collections::HashMap;
use std::default::Default;
use std::cmp::{PartialEq, Eq};
use std::fmt::{Debug, Formatter, Result};
use std::hash::Hash;
use viewport::Viewport;

pub use builder::RebindBuilder;

/// Represents a logical action to be bound to a particular button press, e.g.
/// jump, attack, or move forward. Needs to be hashable, as it is used as a
/// lookup key when rebinding an action to a different button.
pub trait Action: Copy + PartialEq + Eq + Hash { }

/// A translated action.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Translated<A: Action> {
    /// A keypress event which was bound to an action
    Press(A),

    /// A key release event which was bound to an action
    Release(A),

    /// A translated mouse motion. The logical origin of a translated MouseCursor event
    /// is in the top left corner of the window, and the logical scroll is non-natural.
    /// Relative events are unchanged for now.
    Move(Motion)
}

/// A three-element tuple of Option<Button>. For simplicity, a maximum number of 3
/// buttons can be bound to each action, and this is exposed through the `InputRebind`
/// struct.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ButtonTuple(pub Option<Button>, pub Option<Button>, pub Option<Button>);

impl ButtonTuple {
    /// Creates a new tuple with no buttons in it (equivalent to `Default::default()`).
    pub fn new() -> Self { Default::default() }

    /// Check if the button is in the tuple.
    pub fn contains(&self, button: Button) -> bool {
        let sbtn = Some(button);
        self.0 == sbtn || self.1 == sbtn || self.2 == sbtn
    }

    /// Insert a button into the tuple if there is room, searching from left to right.
    /// If the button is inserted, returns true. Otherwise, if the button is not inserted,
    /// this function returns false.
    pub fn insert_inplace(&mut self, button: Button) -> bool {
        let sbtn = Some(button);
        match self {
            &mut ButtonTuple(a, b, c) if a.is_none() => {*self = ButtonTuple(sbtn, b, c); true},
            &mut ButtonTuple(a, b, c) if b.is_none() => {*self = ButtonTuple(a, sbtn, c); true},
            &mut ButtonTuple(a, b, c) if c.is_none() => {*self = ButtonTuple(a, b, sbtn); true}
            _ => false
        }
    }
}

impl Default for ButtonTuple {
    /// Creates a new tuple with no buttons in it.
    fn default() -> Self { ButtonTuple(None, None, None) }
}

/// An object which translates piston::input::Input events into input_map::Translated<A> events
#[derive(Clone, Debug, PartialEq)]
pub struct InputTranslator<A: Action> {
    keymap: HashMap<Button, A>,
    mouse_translator: MouseTranslator
}

impl<A: Action> InputTranslator<A> {
    /// Creates an empty InputTranslator.
    pub fn new(size: Size) -> Self {
        InputTranslator {
            keymap: HashMap::new(),
            mouse_translator: MouseTranslator::new(size)
        }
    }

    /// Translate an Input into a Translated<A> event. Returns `None` if there is no
    /// action associated with the `Input` variant.
    pub fn translate(&self, input: &Input) -> Option<Translated<A>> {
        macro_rules! translate_button(($but_state:ident, $but_var:ident) => (
            match self.keymap.get(&$but_var).map(|x| *x) {
                Some(act) => Some(Translated::$but_state(act)),
                None => None
            });
        );

        match input {
            &Input::Press(button) => translate_button!(Press, button),
            &Input::Release(button) => translate_button!(Release, button),
            &Input::Move(motion) =>
                Some(Translated::Move(self.mouse_translator.translate(motion))),
            _ => None
        }
    }

    /// Re-set the mouse bounds size used for calculating mouse events
    pub fn set_size(&mut self, size: Size) {
        self.mouse_translator.data.viewport_size = size
    }

    /// Re-set the mouse bounds size from a viewport
    pub fn set_size_from_viewport(&mut self, vp: Viewport) {
        self.set_size(Size::from(vp.draw_size));
    }
}

#[derive(Clone)]
struct MouseTranslationData {
    x_axis_motion_inverted: bool,
    y_axis_motion_inverted: bool,
    x_axis_scroll_inverted: bool,
    y_axis_scroll_inverted: bool,
    viewport_size: Size
}

impl MouseTranslationData {
    fn new(size: Size) -> Self {
        MouseTranslationData {
            x_axis_motion_inverted: false,
            y_axis_motion_inverted: false,
            x_axis_scroll_inverted: false,
            y_axis_scroll_inverted: false,
            viewport_size: size
        }
    }
}

impl Debug for MouseTranslationData {
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "{}, {}, {}, {}, ({}, {})",
               self.x_axis_motion_inverted,
               self.y_axis_motion_inverted,
               self.x_axis_scroll_inverted,
               self.y_axis_scroll_inverted,
               self.viewport_size.width,
               self.viewport_size.height)
    }
}

impl PartialEq for MouseTranslationData {
    fn eq(&self, other: &Self) -> bool {
        self.x_axis_motion_inverted == other.x_axis_motion_inverted &&
        self.y_axis_motion_inverted == other.y_axis_motion_inverted &&
        self.x_axis_scroll_inverted == other.x_axis_scroll_inverted &&
        self.y_axis_scroll_inverted == other.y_axis_scroll_inverted &&
        self.viewport_size.width    == other.viewport_size.width &&
        self.viewport_size.height   == other.viewport_size.height
    }
}

#[derive(Clone, Debug, PartialEq)]
struct MouseTranslator {
    data: MouseTranslationData
}

impl MouseTranslator {
    fn new(size: Size) -> Self {
        MouseTranslator {
            data: MouseTranslationData::new(size)
        }
    }

    fn translate(&self, motion: Motion) -> Motion {
        match motion {
            Motion::MouseCursor(x, y) => {
                let (sw, sh) = {
                    let Size {width, height} = self.data.viewport_size;
                    (width as f64, height as f64)
                };

                let cx = if self.data.x_axis_motion_inverted { sw - x } else { x };
                let cy = if self.data.y_axis_motion_inverted { sh - y } else { y };

                Motion::MouseCursor(cx, cy)
            },
            Motion::MouseScroll(x, y) => {
                let mx = if self.data.x_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                let my = if self.data.y_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                Motion::MouseScroll(x * mx, y * my)
            },
            relative => relative
        }
    }
}

/// An interface for rebinding keys to actions. This is freely convertable to and
/// from an InputTranslator.
#[derive(Clone, Debug, PartialEq)]
pub struct InputRebind<A: Action> {
    keymap: HashMap<A, ButtonTuple>,
    mouse_data: MouseTranslationData
}

impl<A: Action> InputRebind<A> {
    /// Creates a new InputRebind with no stored Action/ButtonTuple pairs.
    pub fn new(size: Size) -> Self {
        InputRebind {
            keymap: HashMap::new(),
            mouse_data: MouseTranslationData::new(size)
        }
    }

    /// Insert an Action into this InputRebind. If the Action is already in the
    /// InputRebind, then its ButtonTuple will be reset to (None, None, None), and
    /// the old ButtonTuple will be returned.
    pub fn insert_action(&mut self, action: A) -> Option<ButtonTuple> {
        self.keymap.insert(action, ButtonTuple::new())
    }

    /// Insert an Action into this InputRebind, and assign it to the ButtonTuple.
    /// If the Action is already in the InputRebind, the old ButtonTuple will be
    /// returned.
    pub fn insert_action_with_buttons(&mut self, action: A, buttons: ButtonTuple) -> Option<ButtonTuple> {
        self.keymap.insert(action, buttons)
    }

    /// Return a reference to the current ButtonTuple stored for an action. If the action
    /// is not stored in this InputRebind, then `None` will be returned.
    pub fn get_bindings(&self, action: &A) -> Option<&ButtonTuple> {
        self.keymap.get(action)
    }

    /// Returns a mutable reference to the current ButtonTuple stored for an action. If the
    /// action is not stored in this InputRebind, then `None` will be returned.
    pub fn get_bindings_mut(&mut self, action: &mut A) -> Option<&mut ButtonTuple> {
        self.keymap.get_mut(action)
    }

    /// Returns a reference to the boolean which represents whether x axis scrolling is inverted.
    pub fn get_x_scroll_inverted(&self) -> &bool {
        &self.mouse_data.x_axis_scroll_inverted
    }

    /// Returns a mutable reference to the boolean which represents whether x axis scrolling is inverted.
    pub fn get_x_scroll_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.x_axis_scroll_inverted
    }

    /// Returns a reference to the boolean which represents whether y axis scrolling is inverted.
    pub fn get_y_scroll_inverted(&self) -> &bool {
        &self.mouse_data.y_axis_scroll_inverted
    }

    /// Returns a mutable reference to the boolean which represents whether y axis scrolling is inverted.
    pub fn get_y_scroll_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.y_axis_scroll_inverted
    }

    /// Returns a reference to the boolean which represents whether mouse movement along the x axis is
    /// inverted.
    pub fn get_x_motion_inverted(&self) -> &bool {
        &self.mouse_data.x_axis_motion_inverted
    }

    /// Returns a mutable reference to the boolean which represents whether mouse movement along the
    /// x axis is inverted.
    pub fn get_x_motion_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.x_axis_motion_inverted
    }

    /// Returns a reference to the boolean which represents whether mouse movement along the y axis is
    /// inverted.
    pub fn get_y_motion_inverted(&self) -> &bool {
        &self.mouse_data.y_axis_motion_inverted
    }

    /// Returns a mutable reference to the boolean which represents whether mouse movement along the
    /// y axis is inverted.
    pub fn get_y_motion_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.y_axis_motion_inverted
    }

    /// Returns a reference to the currently stored viewport size used for calculating the imaginary mouse
    /// position.
    pub fn get_viewport_size(&self) -> &Size {
        &self.mouse_data.viewport_size
    }

    /// Returns a mutable reference to the currently stored viewport size used for calculating the imaginary
    /// mouse position.
    pub fn get_viewport_size_mut(&mut self) -> &mut Size {
        &mut self.mouse_data.viewport_size
    }
}

impl<A: Action> Default for InputRebind<A> {
    /// Creates an `InputRebind` with no pairs. In addition, the viewport size is set to [800, 600].
    fn default() -> Self {
        InputRebind::new((800, 600).into())
    }
}

impl<A: Action> Into<InputTranslator<A>> for InputRebind<A> {
    #[allow(missing_docs)]
    fn into(self) -> InputTranslator<A> {
        let mut input_translator = InputTranslator::new(self.mouse_data.viewport_size);
        input_translator.mouse_translator.data = self.mouse_data;
        input_translator.keymap = self.keymap.values()
                                             .flat_map(|&bt| bt.into_iter())
                                             .filter_map(|x| x)
                                             .zip(self.keymap.keys().map(|x| *x))
                                             .collect();

        input_translator
    }
}

impl<A: Action> Into<InputRebind<A>> for InputTranslator<A> {
    #[allow(missing_docs)]
    fn into(self) -> InputRebind<A> {
        use itertools::Itertools;

        let mut input_rebind = InputRebind::new(self.mouse_translator.data.viewport_size);
        input_rebind.mouse_data = self.mouse_translator.data;
        input_rebind.keymap = self.keymap.keys()
                                         .map(|x| vec![Some(x)])
                                         .coalesce(|b0, b1| if b0 == b1 {
                                                 Ok(b0.into_iter().chain(b1).collect())
                                             } else {
                                                 Err((b0, b1))
                                             })
                                         .map(|s| if let [b0, b1, b2] = &s.iter()
                                                                          .fuse()
                                                                          .take(3)
                                                                          .map(|x| x.cloned())
                                                                          .collect::<Vec<_>>()[..] {
                                                 ButtonTuple(b0, b1, b2)
                                             } else {
                                                 unreachable!();
                                             })
                                         .zip(self.keymap.values().map(|x| *x))
                                         .map(|(k, v)| (v, k))
                                         .collect();

        input_rebind
    }
}

impl ButtonTuple {
    fn into_iter(self) -> ButtonTupleIterator {
        ButtonTupleIterator {
            button_tuple: self,
            i: 0
        }
    }
}

struct ButtonTupleIterator {
    button_tuple: ButtonTuple,
    i: usize
}

impl Iterator for ButtonTupleIterator {
    type Item = Option<Button>;

    fn next(&mut self) -> Option<Self::Item> {
        let i = self.i;
        self.i += 1;
        match i {
            0 => Some(self.button_tuple.0),
            1 => Some(self.button_tuple.1),
            2 => Some(self.button_tuple.2),
            _ => None
        }
    }
}
<commit_msg>Use cloned() iter method instead of map deref<commit_after>#![warn(missing_docs)]
#![feature(slice_patterns)]

//! rebind
//! =========
//!
//! A library for binding input keys to actions, and modifying mouse behaviour. Keys can be
//! bound to actions, and then translated during runtime. `Keys` are mapped to `Actions` using
//! a `HashMap`, so lookup time is constant.

extern crate input;
extern crate itertools;
extern crate window;
extern crate rustc_serialize;
extern crate viewport;

mod builder;

#[cfg(test)]
mod test;

use input::{Input, Button, Motion};
use window::Size;
use std::collections::HashMap;
use std::default::Default;
use std::cmp::{PartialEq, Eq};
use std::fmt::{Debug, Formatter, Result};
use std::hash::Hash;
use viewport::Viewport;

pub use builder::RebindBuilder;

/// Represents a logical action to be bound to a particular button press, e.g.
/// jump, attack, or move forward. Needs to be hashable, as it is used as a
/// lookup key when rebinding an action to a different button.
pub trait Action: Copy + PartialEq + Eq + Hash { }

/// A translated action.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Translated<A: Action> {
    /// A keypress event which was bound to an action
    Press(A),

    /// A key release event which was bound to an action
    Release(A),

    /// A translated mouse motion. The logical origin of a translated MouseCursor event
    /// is in the top left corner of the window, and the logical scroll is non-natural.
    /// Relative events are unchanged for now.
    Move(Motion)
}

/// A three-element tuple of Option<Button>. For simplicity, a maximum number of 3
/// buttons can be bound to each action, and this is exposed through the `InputRebind`
/// struct.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ButtonTuple(pub Option<Button>, pub Option<Button>, pub Option<Button>);

impl ButtonTuple {
    /// Creates a new tuple with no buttons in it (equivalent to `Default::default()`).
    pub fn new() -> Self { Default::default() }

    /// Check if the button is in the tuple.
    pub fn contains(&self, button: Button) -> bool {
        let sbtn = Some(button);
        self.0 == sbtn || self.1 == sbtn || self.2 == sbtn
    }

    /// Insert a button into the tuple if there is room, searching from left to right.
    /// If the button is inserted, returns true. Otherwise, if the button is not inserted,
    /// this function returns false.
    pub fn insert_inplace(&mut self, button: Button) -> bool {
        let sbtn = Some(button);
        match self {
            &mut ButtonTuple(a, b, c) if a.is_none() => {*self = ButtonTuple(sbtn, b, c); true},
            &mut ButtonTuple(a, b, c) if b.is_none() => {*self = ButtonTuple(a, sbtn, c); true},
            &mut ButtonTuple(a, b, c) if c.is_none() => {*self = ButtonTuple(a, b, sbtn); true}
            _ => false
        }
    }
}

impl Default for ButtonTuple {
    /// Creates a new tuple with no buttons in it.
    fn default() -> Self { ButtonTuple(None, None, None) }
}

/// An object which translates piston::input::Input events into input_map::Translated<A> events
#[derive(Clone, Debug, PartialEq)]
pub struct InputTranslator<A: Action> {
    keymap: HashMap<Button, A>,
    mouse_translator: MouseTranslator
}

impl<A: Action> InputTranslator<A> {
    /// Creates an empty InputTranslator.
    pub fn new(size: Size) -> Self {
        InputTranslator {
            keymap: HashMap::new(),
            mouse_translator: MouseTranslator::new(size)
        }
    }

    /// Translate an Input into a Translated<A> event. Returns `None` if there is no
    /// action associated with the `Input` variant.
    pub fn translate(&self, input: &Input) -> Option<Translated<A>> {
        macro_rules! translate_button(($but_state:ident, $but_var:ident) => (
            match self.keymap.get(&$but_var).map(|x| *x) {
                Some(act) => Some(Translated::$but_state(act)),
                None => None
            });
        );

        match input {
            &Input::Press(button) => translate_button!(Press, button),
            &Input::Release(button) => translate_button!(Release, button),
            &Input::Move(motion) =>
                Some(Translated::Move(self.mouse_translator.translate(motion))),
            _ => None
        }
    }

    /// Re-set the mouse bounds size used for calculating mouse events
    pub fn set_size(&mut self, size: Size) {
        self.mouse_translator.data.viewport_size = size
    }

    /// Re-set the mouse bounds size from a viewport
    pub fn set_size_from_viewport(&mut self, vp: Viewport) {
        self.set_size(Size::from(vp.draw_size));
    }
}

#[derive(Clone)]
struct MouseTranslationData {
    x_axis_motion_inverted: bool,
    y_axis_motion_inverted: bool,
    x_axis_scroll_inverted: bool,
    y_axis_scroll_inverted: bool,
    viewport_size: Size
}

impl MouseTranslationData {
    fn new(size: Size) -> Self {
        MouseTranslationData {
            x_axis_motion_inverted: false,
            y_axis_motion_inverted: false,
            x_axis_scroll_inverted: false,
            y_axis_scroll_inverted: false,
            viewport_size: size
        }
    }
}

impl Debug for MouseTranslationData {
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "{}, {}, {}, {}, ({}, {})",
               self.x_axis_motion_inverted,
               self.y_axis_motion_inverted,
               self.x_axis_scroll_inverted,
               self.y_axis_scroll_inverted,
               self.viewport_size.width,
               self.viewport_size.height)
    }
}

impl PartialEq for MouseTranslationData {
    fn eq(&self, other: &Self) -> bool {
        self.x_axis_motion_inverted == other.x_axis_motion_inverted &&
        self.y_axis_motion_inverted == other.y_axis_motion_inverted &&
        self.x_axis_scroll_inverted == other.x_axis_scroll_inverted &&
        self.y_axis_scroll_inverted == other.y_axis_scroll_inverted &&
        self.viewport_size.width    == other.viewport_size.width &&
        self.viewport_size.height   == other.viewport_size.height
    }
}

#[derive(Clone, Debug, PartialEq)]
struct MouseTranslator {
    data: MouseTranslationData
}

impl MouseTranslator {
    fn new(size: Size) -> Self {
        MouseTranslator {
            data: MouseTranslationData::new(size)
        }
    }

    fn translate(&self, motion: Motion) -> Motion {
        match motion {
            Motion::MouseCursor(x, y) => {
                let (sw, sh) = {
                    let Size {width, height} = self.data.viewport_size;
                    (width as f64, height as f64)
                };

                let cx = if self.data.x_axis_motion_inverted { sw - x } else { x };
                let cy = if self.data.y_axis_motion_inverted { sh - y } else { y };

                Motion::MouseCursor(cx, cy)
            },
            Motion::MouseScroll(x, y) => {
                let mx = if self.data.x_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                let my = if self.data.y_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                Motion::MouseScroll(x * mx, y * my)
            },
            relative => relative
        }
    }
}

/// An interface for rebinding keys to actions. This is freely convertable to and
/// from an InputTranslator.
#[derive(Clone, Debug, PartialEq)]
pub struct InputRebind<A: Action> {
    keymap: HashMap<A, ButtonTuple>,
    mouse_data: MouseTranslationData
}

impl<A: Action> InputRebind<A> {
    /// Creates a new InputRebind with no stored Action/ButtonTuple pairs.
    pub fn new(size: Size) -> Self {
        InputRebind {
            keymap: HashMap::new(),
            mouse_data: MouseTranslationData::new(size)
        }
    }

    /// Insert an Action into this InputRebind. If the Action is already in the
    /// InputRebind, then its ButtonTuple will be reset to (None, None, None), and
    /// the old ButtonTuple will be returned.
    pub fn insert_action(&mut self, action: A) -> Option<ButtonTuple> {
        self.keymap.insert(action, ButtonTuple::new())
    }

    /// Insert an Action into this InputRebind, and assign it to the ButtonTuple.
    /// If the Action is already in the InputRebind, the old ButtonTuple will be
    /// returned.
    pub fn insert_action_with_buttons(&mut self, action: A, buttons: ButtonTuple) -> Option<ButtonTuple> {
        self.keymap.insert(action, buttons)
    }

    /// Return a reference to the current ButtonTuple stored for an action. If the action
    /// is not stored in this InputRebind, then `None` will be returned.
    pub fn get_bindings(&self, action: &A) -> Option<&ButtonTuple> {
        self.keymap.get(action)
    }

    /// Returns a mutable reference to the current ButtonTuple stored for an action. If the
    /// action is not stored in this InputRebind, then `None` will be returned.
    pub fn get_bindings_mut(&mut self, action: &mut A) -> Option<&mut ButtonTuple> {
        self.keymap.get_mut(action)
    }

    /// Returns a reference to the boolean which represents whether x axis scrolling is inverted.
    pub fn get_x_scroll_inverted(&self) -> &bool {
        &self.mouse_data.x_axis_scroll_inverted
    }

    /// Returns a mutable reference to the boolean which represents whether x axis scrolling is inverted.
    pub fn get_x_scroll_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.x_axis_scroll_inverted
    }

    /// Returns a reference to the boolean which represents whether y axis scrolling is inverted.
    pub fn get_y_scroll_inverted(&self) -> &bool {
        &self.mouse_data.y_axis_scroll_inverted
    }

    /// Returns a mutable reference to the boolean which represents whether y axis scrolling is inverted.
    pub fn get_y_scroll_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.y_axis_scroll_inverted
    }

    /// Returns a reference to the boolean which represents whether mouse movement along the x axis is
    /// inverted.
    pub fn get_x_motion_inverted(&self) -> &bool {
        &self.mouse_data.x_axis_motion_inverted
    }

    /// Returns a mutable reference to the boolean which represents whether mouse movement along the
    /// x axis is inverted.
    pub fn get_x_motion_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.x_axis_motion_inverted
    }

    /// Returns a reference to the boolean which represents whether mouse movement along the y axis is
    /// inverted.
    pub fn get_y_motion_inverted(&self) -> &bool {
        &self.mouse_data.y_axis_motion_inverted
    }

    /// Returns a mutable reference to the boolean which represents whether mouse movement along the
    /// y axis is inverted.
    pub fn get_y_motion_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.y_axis_motion_inverted
    }

    /// Returns a reference to the currently stored viewport size used for calculating the imaginary mouse
    /// position.
    pub fn get_viewport_size(&self) -> &Size {
        &self.mouse_data.viewport_size
    }

    /// Returns a mutable reference to the currently stored viewport size used for calculating the imaginary
    /// mouse position.
    pub fn get_viewport_size_mut(&mut self) -> &mut Size {
        &mut self.mouse_data.viewport_size
    }
}

impl<A: Action> Default for InputRebind<A> {
    /// Creates an `InputRebind` with no pairs. In addition, the viewport size is set to [800, 600].
    fn default() -> Self {
        InputRebind::new((800, 600).into())
    }
}

impl<A: Action> Into<InputTranslator<A>> for InputRebind<A> {
    #[allow(missing_docs)]
    fn into(self) -> InputTranslator<A> {
        let mut input_translator = InputTranslator::new(self.mouse_data.viewport_size);
        input_translator.mouse_translator.data = self.mouse_data;
        input_translator.keymap = self.keymap.values()
                                             .flat_map(|&bt| bt.into_iter())
                                             .filter_map(|x| x)
                                             .zip(self.keymap.keys().cloned())
                                             .collect();

        input_translator
    }
}

impl<A: Action> Into<InputRebind<A>> for InputTranslator<A> {
    #[allow(missing_docs)]
    fn into(self) -> InputRebind<A> {
        use itertools::Itertools;

        let mut input_rebind = InputRebind::new(self.mouse_translator.data.viewport_size);
        input_rebind.mouse_data = self.mouse_translator.data;
        input_rebind.keymap = self.keymap.keys()
                                         .map(|x| vec![Some(x)])
                                         .coalesce(|b0, b1| if b0 == b1 {
                                                 Ok(b0.into_iter().chain(b1).collect())
                                             } else {
                                                 Err((b0, b1))
                                             })
                                         .map(|s| if let [b0, b1, b2] = &s.iter()
                                                                          .fuse()
                                                                          .take(3)
                                                                          .map(|x| x.cloned())
                                                                          .collect::<Vec<_>>()[..] {
                                                 ButtonTuple(b0, b1, b2)
                                             } else {
                                                 unreachable!();
                                             })
                                         .zip(self.keymap.values().cloned())
                                         .map(|(k, v)| (v, k))
                                         .collect();

        input_rebind
    }
}

impl ButtonTuple {
    fn into_iter(self) -> ButtonTupleIterator {
        ButtonTupleIterator {
            button_tuple: self,
            i: 0
        }
    }
}

struct ButtonTupleIterator {
    button_tuple: ButtonTuple,
    i: usize
}

impl Iterator for ButtonTupleIterator {
    type Item = Option<Button>;

    fn next(&mut self) -> Option<Self::Item> {
        let i = self.i;
        self.i += 1;
        match i {
            0 => Some(self.button_tuple.0),
            1 => Some(self.button_tuple.1),
            2 => Some(self.button_tuple.2),
            _ => None
        }
    }
}
<|endoftext|>


<commit_before>#![doc(test(attr(deny(warnings), allow(deprecated))))]

//! Fraction is designed to be a precise lossless drop-in replacement for floating types (f32, f64).
//!
//! It comes with a number of predefined type aliases covering the most common use cases such as
//! [Fraction], [Decimal], [BigFraction], [DynaDecimal] and so on (see [prelude] module for more examples).
//!
//! The public API provides you with the generic types that you may use straightforwardly to build your
//! own types, suiting your needs best (see [prelude] module for the examples).
//!
//! # Library features
//!
//! - Drop in replacement for floats with the exception for NaN == NaN so that it's hashable
//! - It's hashable, so may be used as values in Sets and keys in dictionaries and hash maps
//! - [Display](fraction::display) implementation for fractions and decimals
//! - [Fraction](GenericFraction) type, representing fractions
//! - [Decimal](GenericDecimal) type, based on [Fraction](GenericFraction) type represents floats as lossless decimals
//! - [DynaInt](dynaint) implements dinamically growing integer type that perfarms checked math and avoids stack overflows
//! - PostgreSQL binary protocol integration for both fractions and decimals
//! - Juniper support for both fractions and decimals
//! - [Generic integer conversions](generic), such as `i8 -> u8`, `usize -> u8` and so on
//! - [Lossless division](division) with no allocations and infinite precision
//!
//! # Disclaimer
//! Even though we do our best to keep it well covered with tests, there may be bugs out there.
//! The library API is still in flux. When it gets stable we will release the version 1.0.0.
//! You may find more info about Semantic Versioning on [https://semver.org/](https://semver.org/).
//! Bug reports and contributions are appreciated.
//!
//! # Crate features
//! - `with-bigint` (default) integration with [num::BigInt] and [num::BigUint] data types
//! - `with-decimal` (default) [Decimal] type implemented upon [GenericFraction]
//! - `with-dynaint` (default) dynamically growing integer avoiding stack overflows
//! - `with-juniper-support` [Juniper](https://crates.io/crates/juniper) integration
//! - `with-postgres-support` [PostgreSQL](https://crates.io/crates/postgres) integration; Numeric/Decimal type
//! - `with-serde-support` [Serde](https://crates.io/crates/serde) traits implementation
//!
//! # Implementation
//! Basic math implemented upon the [num] crate (in particular the [num::rational] module).
//! The utilised traits from the [num] crate are re-exported, so you don't have to explicitly depend on that crate however,
//! you may import them from either of crates if necessary.
//!
//! # Usage
//! To start using types see the [Prelude](self::prelude) module.
//!
//! # Examples
//!
//! ## Simple use:
//!
//! ```
//! type F = fraction::Fraction; // choose the type accordingly to your needs (see prelude module docs)
//!
//! let two = F::from(0) + F::from(2);   // 0 + 2 = 2
//! let two_third = two / F::from(3);    // 2/3 = 0.666666[...]
//!
//! assert_eq!(F::from(2), two);
//! assert_eq!(F::new(2u64, 3u64), two_third);
//!
//! assert_eq!("2/3", format!("{}", two_third));  // print as Fraction (by default)
//! assert_eq!("0.6666", format!("{:.4}", two_third));  // format as decimal and print up to 4 digits after floating point
//! ```
//!
//! Decimal is implemented as a representation layer on top of Fraction.
//! Thus, it is also lossless and may require explicit control over "precision"
//! for comparison and formatting operations.
//! ```
//! type D = fraction::Decimal;
//!
//! let result = D::from(0.5) / D::from(0.3);
//!
//! assert_eq!(format!("{}", result), "1.6"); // calculation result uses precision of the operands
//! assert_eq!(format!("{:.4}", result), "1.6666");  // explicitly passing precision to format
//!
//! assert_eq!("1.6666", format!("{}", result.set_precision(4))); // the other way to set precision explicitly on Decimal
//! ```
//!
//! ## Construct:
//!
//! Fraction:
//! ```
//! use fraction::{Fraction, Sign};  // choose the type accordingly with your needs (see prelude module docs)
//!
//! fn main() {
//!     // There are several ways to construct a fraction, depending on your use case
//!
//!     let f = Fraction::new(1u8, 2u8);  // constructs with numerator/denominator and normalizes the fraction (finds least common denominator)
//!     assert_eq!(f, Fraction::new_generic(Sign::Plus, 1i32, 2u8).unwrap());  // with numerator/denominator of different integer types
//!     assert_eq!(f, Fraction::from(0.5));  // convert from float (f32, f64)
//!     assert_eq!(f, Fraction::from_decimal_str("0.5").unwrap());  // parse a string
//!
//!     // Raw construct with no extra calculations.
//!     // Most performant, but does not look for common denominator and may lead to unexpected results
//!     // in following calculations. Only use if you are sure numerator/denominator are already normalized.
//!     assert_eq!(f, Fraction::new_raw(1u64, 2u64));
//! }
//! ```
//!
//! Decimal:
//! ```
//! use fraction::{Decimal, Fraction};  // choose the type accordingly with your needs (see prelude module docs)
//!
//! fn main() {
//!     // There are similar ways to construct Decimal. Underneath it is always represented as Fraction.
//!     // When constructed, Decimal preserves its precision (number of digits after floating point).
//!     // When two decimals are calculated, the result takes the biggest precision of both.
//!     // The precision is used for visual representation (formatting and printing) and for comparison of two decimals.
//!     // Precision is NOT used in any calculations. All calculations are lossless and implemented through Fraction.
//!     // To override the precision use Decimal::set_precision.
//!
//!     let d = Decimal::from(1);  // from integer, precision = 0
//!     assert_eq!(d, Decimal::from_fraction(Fraction::from(1))); // from fraction, precision is calculated from fraction
//!
//!     let d = Decimal::from(1.3);  // from float (f32, f64)
//!     assert_eq!(d, Decimal::from_decimal_str("1.3").unwrap());
//! }
//! ```
//!
//! ## Format (convert to string)
//! Formatting works similar for both Decimal and Fraction (Decimal uses Fraction internally).
//! The format implementation closely follows the rust Format trait documentation.
//!
//! ```
//! type F = fraction::Fraction;
//!
//! let result = F::from(0.7) / F::from(0.4);
//! assert_eq!(format!("{}", result), "7/4");  // Printed as fraction by default
//! assert_eq!(format!("{:.2}", result), "1.75"); // if precision is defined, printed as decimal
//! assert_eq!(format!("{:#.3}", result), "1.750"); // to print leading zeroes, pass hash to the format
//! ```
//!
//! ### Generic integer conversion
//! ```
//! use fraction::{Sign, GenericFraction};
//!
//! type F = GenericFraction<u32>;
//!
//! let fra = F::new_generic(Sign::Plus, 1i8, 42usize).unwrap();
//! assert_eq!(fra, F::new(1u32, 42u32));
//! ```
//!
//! ### Postgres usage
//! Postgres uses i16 for its binary protocol, so you'll have to use at least u16
//! as the base type for fractions/decimals.
//! Otherwise you may workaround with DynaInt<u8, _something_more_than_u8_>.
//! The safest way to go with would be DynaInt based types
//! such as DynaFraction or DynaDecimal as they would prevent
//! stack overflows for high values.
//!
//! Beware bad numbers such as 1/3, 1/7.
//! Fraction keeps the highest achievable precision (up to 16383 digits after floating point).
//! Decimal uses its own precision.
//! So, if you may end up with bad numbers, it may be preferable to go with Decimals over Fractions.
//!
//! Both types (fractions and decimals) should work transparently
//! in accordance with Postgres crate documentation

extern crate num;

#[cfg(feature = "with-bigint")]
#[macro_use]
extern crate lazy_static;

#[cfg(feature = "with-bigint")]
pub use num::bigint::{BigInt, BigUint};

pub use num::rational::{ParseRatioError, Ratio};

pub use num::{
    Bounded, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, FromPrimitive, Integer, Num, One,
    Signed, ToPrimitive, Zero,
};

#[cfg(test)]
#[macro_use]
mod tests;

pub mod convert;

pub mod division;

pub mod error;

mod fraction;
pub use fraction::*;

pub mod generic;

pub mod prelude;
pub use self::prelude::*;

// ====================================== FEATURES ======================================

#[cfg(feature = "with-juniper-support")]
extern crate juniper;
#[cfg(feature = "with-postgres-support")]
#[macro_use]
extern crate postgres_types;

#[cfg(feature = "with-serde-support")]
#[macro_use]
extern crate serde_derive;
#[cfg(feature = "with-serde-support")]
extern crate serde;

#[cfg(feature = "with-decimal")]
mod decimal;
#[cfg(feature = "with-dynaint")]
pub mod dynaint;
<commit_msg>Fix lint warnings<commit_after>#![doc(test(attr(deny(warnings), allow(deprecated))))]

//! Fraction is designed to be a precise lossless drop-in replacement for floating types (f32, f64).
//!
//! It comes with a number of predefined type aliases covering the most common use cases such as
//! [Fraction], [Decimal], [BigFraction], [DynaDecimal] and so on (see [prelude] module for more examples).
//!
//! The public API provides you with the generic types that you may use straightforwardly to build your
//! own types, suiting your needs best (see [prelude] module for the examples).
//!
//! # Library features
//!
//! - Drop in replacement for floats with the exception for NaN == NaN so that it's hashable
//! - It's hashable, so may be used as values in Sets and keys in dictionaries and hash maps
//! - [Display](fraction::display) implementation for fractions and decimals
//! - [Fraction](GenericFraction) type, representing fractions
//! - [Decimal](GenericDecimal) type, based on [Fraction](GenericFraction) type represents floats as lossless decimals
//! - [DynaInt](dynaint) implements dinamically growing integer type that perfarms checked math and avoids stack overflows
//! - PostgreSQL binary protocol integration for both fractions and decimals
//! - Juniper support for both fractions and decimals
//! - [Generic integer conversions](generic), such as `i8 -> u8`, `usize -> u8` and so on
//! - [Lossless division](division) with no allocations and infinite precision
//!
//! # Disclaimer
//! Even though we do our best to keep it well covered with tests, there may be bugs out there.
//! The library API is still in flux. When it gets stable we will release the version 1.0.0.
//! You may find more info about Semantic Versioning on [https://semver.org/](https://semver.org/).
//! Bug reports and contributions are appreciated.
//!
//! # Crate features
//! - `with-bigint` (default) integration with [num::BigInt] and [num::BigUint] data types
//! - `with-decimal` (default) [Decimal] type implemented upon [GenericFraction]
//! - `with-dynaint` (default) dynamically growing integer avoiding stack overflows
//! - `with-juniper-support` [Juniper](https://crates.io/crates/juniper) integration
//! - `with-postgres-support` [PostgreSQL](https://crates.io/crates/postgres) integration; Numeric/Decimal type
//! - `with-serde-support` [Serde](https://crates.io/crates/serde) traits implementation
//!
//! # Implementation
//! Basic math implemented upon the [num] crate (in particular the [num::rational] module).
//! The utilised traits from the [num] crate are re-exported, so you don't have to explicitly depend on that crate however,
//! you may import them from either of crates if necessary.
//!
//! # Usage
//! To start using types see the [Prelude](self::prelude) module.
//!
//! # Examples
//!
//! ## Simple use:
//!
//! ```
//! type F = fraction::Fraction; // choose the type accordingly to your needs (see prelude module docs)
//!
//! let two = F::from(0) + F::from(2);   // 0 + 2 = 2
//! let two_third = two / F::from(3);    // 2/3 = 0.666666[...]
//!
//! assert_eq!(F::from(2), two);
//! assert_eq!(F::new(2u64, 3u64), two_third);
//!
//! assert_eq!("2/3", format!("{}", two_third));  // print as Fraction (by default)
//! assert_eq!("0.6666", format!("{:.4}", two_third));  // format as decimal and print up to 4 digits after floating point
//! ```
//!
//! Decimal is implemented as a representation layer on top of Fraction.
//! Thus, it is also lossless and may require explicit control over "precision"
//! for comparison and formatting operations.
//! ```
//! type D = fraction::Decimal;
//!
//! let result = D::from(0.5) / D::from(0.3);
//!
//! assert_eq!(format!("{}", result), "1.6"); // calculation result uses precision of the operands
//! assert_eq!(format!("{:.4}", result), "1.6666");  // explicitly passing precision to format
//!
//! assert_eq!("1.6666", format!("{}", result.set_precision(4))); // the other way to set precision explicitly on Decimal
//! ```
//!
//! ## Construct:
//!
//! Fraction:
//! ```
//! use fraction::{Fraction, Sign};  // choose the type accordingly with your needs (see prelude module docs)
//!
//! fn main() {
//!     // There are several ways to construct a fraction, depending on your use case
//!
//!     let f = Fraction::new(1u8, 2u8);  // constructs with numerator/denominator and normalizes the fraction (finds least common denominator)
//!     assert_eq!(f, Fraction::new_generic(Sign::Plus, 1i32, 2u8).unwrap());  // with numerator/denominator of different integer types
//!     assert_eq!(f, Fraction::from(0.5));  // convert from float (f32, f64)
//!     assert_eq!(f, Fraction::from_decimal_str("0.5").unwrap());  // parse a string
//!
//!     // Raw construct with no extra calculations.
//!     // Most performant, but does not look for common denominator and may lead to unexpected results
//!     // in following calculations. Only use if you are sure numerator/denominator are already normalized.
//!     assert_eq!(f, Fraction::new_raw(1u64, 2u64));
//! }
//! ```
//!
//! Decimal:
//! ```
//! use fraction::{Decimal, Fraction};  // choose the type accordingly with your needs (see prelude module docs)
//!
//! fn main() {
//!     // There are similar ways to construct Decimal. Underneath it is always represented as Fraction.
//!     // When constructed, Decimal preserves its precision (number of digits after floating point).
//!     // When two decimals are calculated, the result takes the biggest precision of both.
//!     // The precision is used for visual representation (formatting and printing) and for comparison of two decimals.
//!     // Precision is NOT used in any calculations. All calculations are lossless and implemented through Fraction.
//!     // To override the precision use Decimal::set_precision.
//!
//!     let d = Decimal::from(1);  // from integer, precision = 0
//!     assert_eq!(d, Decimal::from_fraction(Fraction::from(1))); // from fraction, precision is calculated from fraction
//!
//!     let d = Decimal::from(1.3);  // from float (f32, f64)
//!     assert_eq!(d, Decimal::from_decimal_str("1.3").unwrap());
//! }
//! ```
//!
//! ## Format (convert to string)
//! Formatting works similar for both Decimal and Fraction (Decimal uses Fraction internally).
//! The format implementation closely follows the rust Format trait documentation.
//!
//! ```
//! type F = fraction::Fraction;
//!
//! let result = F::from(0.7) / F::from(0.4);
//! assert_eq!(format!("{}", result), "7/4");  // Printed as fraction by default
//! assert_eq!(format!("{:.2}", result), "1.75"); // if precision is defined, printed as decimal
//! assert_eq!(format!("{:#.3}", result), "1.750"); // to print leading zeroes, pass hash to the format
//! ```
//!
//! ### Generic integer conversion
//! ```
//! use fraction::{Sign, GenericFraction};
//!
//! type F = GenericFraction<u32>;
//!
//! let fra = F::new_generic(Sign::Plus, 1i8, 42usize).unwrap();
//! assert_eq!(fra, F::new(1u32, 42u32));
//! ```
//!
//! ### Postgres usage
//! Postgres uses i16 for its binary protocol, so you'll have to use at least u16
//! as the base type for fractions/decimals.
//! Otherwise you may workaround with DynaInt<u8, _something_more_than_u8_>.
//! The safest way to go with would be DynaInt based types
//! such as DynaFraction or DynaDecimal as they would prevent
//! stack overflows for high values.
//!
//! Beware bad numbers such as 1/3, 1/7.
//! Fraction keeps the highest achievable precision (up to 16383 digits after floating point).
//! Decimal uses its own precision.
//! So, if you may end up with bad numbers, it may be preferable to go with Decimals over Fractions.
//!
//! Both types (fractions and decimals) should work transparently
//! in accordance with Postgres crate documentation

extern crate num;

#[cfg(feature = "with-bigint")]
#[macro_use]
extern crate lazy_static;

#[cfg(feature = "with-bigint")]
pub use num::bigint::{BigInt, BigUint};

pub use num::rational::{ParseRatioError, Ratio};

pub use num::{
    Bounded, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, FromPrimitive, Integer, Num, One,
    Signed, ToPrimitive, Zero,
};

#[cfg(test)]
#[macro_use]
mod tests;

pub mod convert;

pub mod division;

pub mod error;

mod fraction;
pub use fraction::*;

pub mod generic;

pub mod prelude;
pub use self::prelude::*;

// ====================================== FEATURES ======================================

#[cfg(feature = "with-juniper-support")]
extern crate juniper;
#[cfg(feature = "with-postgres-support")]
#[macro_use]
extern crate postgres_types;

#[cfg(feature = "with-serde-support")]
#[macro_use]
extern crate serde_derive;
#[cfg(feature = "with-serde-support")]
extern crate serde;

#[cfg(feature = "with-decimal")]
mod decimal;
#[cfg(feature = "with-dynaint")]
pub mod dynaint;
<|endoftext|>


<commit_before>#[macro_use(bson, doc)]
extern crate bson;
extern crate mongodb;
extern crate chrono;

use std::result;
use mongodb::{Client, ThreadedClient};
use mongodb::cursor::Cursor;
use mongodb::db::ThreadedDatabase;
use mongodb::coll::options::{FindOptions, CursorType};
use chrono::{DateTime, UTC, TimeZone};

#[derive(Debug)]
pub enum OplogError {
    MissingField(bson::ValueAccessError),
    Database(mongodb::Error),
    UnknownOperation(String),
}

type Result<T> = result::Result<T, OplogError>;

pub struct Oplog {
    cursor: Cursor,
}

#[derive(PartialEq, Debug)]
pub enum Operation<'a> {
    Insert { id: i64, timestamp: DateTime<UTC>, namespace: &'a str, document: &'a bson::Document },
    Update { id: i64, namespace: &'a str },
    Delete { id: i64, namespace: &'a str },
    Command { id: i64, namespace: &'a str },
    Database { id: i64, namespace: &'a str },
    Noop { id: i64, timestamp: DateTime<UTC>, document: &'a bson::Document },
    Unknown
}

impl<'a> Operation<'a> {
    pub fn new(document: &'a bson::Document) -> Result<Operation<'a>> {
        let op = try!(document.get_str("op").map_err(OplogError::MissingField));

        match op {
            "n" => document_to_noop(document),
            "i" => document_to_insert(document),
            _ => Err(OplogError::UnknownOperation(op.to_owned())),
        }
    }
}

fn document_to_noop(document: &bson::Document) -> Result<Operation> {
    let h = try!(document.get_i64("h").map_err(OplogError::MissingField));
    let ts = try!(document.get_time_stamp("ts").map_err(OplogError::MissingField));
    let o = try!(document.get_document("o").map_err(OplogError::MissingField));

    Ok(Operation::Noop { id: h, timestamp: timestamp_to_datetime(ts), document: o })
}

fn document_to_insert(document: &bson::Document) -> Result<Operation> {
    let h = try!(document.get_i64("h").map_err(OplogError::MissingField));
    let ts = try!(document.get_time_stamp("ts").map_err(OplogError::MissingField));
    let o = try!(document.get_document("o").map_err(OplogError::MissingField));
    let ns = try!(document.get_str("ns").map_err(OplogError::MissingField));

    Ok(Operation::Insert { id: h, timestamp: timestamp_to_datetime(ts), document: o, namespace: ns })
}

fn timestamp_to_datetime(timestamp: i64) -> DateTime<UTC> {
    let seconds = timestamp >> 32;
    let nanoseconds = ((timestamp & 0xFFFFFFFF) * 1000000) as u32;

    UTC.timestamp(seconds, nanoseconds)
}

impl Iterator for Oplog {
    type Item = bson::Document;

    fn next(&mut self) -> Option<bson::Document> {
        loop {
            if let Some(Ok(op)) = self.cursor.next() {
                return Some(op);
            }
        }
    }
}

impl Oplog {
    pub fn new(client: Client) -> Result<Oplog> {
        let coll = client.db("local").collection("oplog.rs");

        let mut opts = FindOptions::new();
        opts.cursor_type = CursorType::TailableAwait;
        opts.no_cursor_timeout = true;

        coll.find(None, Some(opts)).map(|cursor| Oplog { cursor: cursor }).map_err(OplogError::Database)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use bson::Bson;
    use bson::oid::ObjectId;
    use chrono::{UTC, TimeZone};

    #[test]
    fn operation_converts_noops() {
        let doc = doc! {
            "ts" => (Bson::TimeStamp(1479419535 << 32)),
            "h" => (-2135725856567446411i64),
            "v" => 2,
            "op" => "n",
            "ns" => "",
            "o" => {
                "msg" => "initiating set"
            }
        };
        let operation = Operation::new(&doc).unwrap();

        match operation {
            Operation::Noop { id, timestamp, document } => {
                assert_eq!(-2135725856567446411i64, id);
                assert_eq!(UTC.timestamp(1479419535, 0), timestamp);
                assert_eq!("initiating set", document.get_str("msg").unwrap());
            },
            _ => panic!("Unexpected type of operation"),
        }
    }

    #[test]
    fn operation_converts_inserts() {
        let oid = ObjectId::with_string("583050b26813716e505a5bf2").unwrap();
        let doc = doc! {
            "ts" => (Bson::TimeStamp(1479561394 << 32)),
            "h" => (-1742072865587022793i64),
            "v" => 2,
            "op" => "i",
            "ns" => "foo.bar",
            "o" => {
                "_id" => (Bson::ObjectId(oid)),
                "foo" => "bar"
            }
        };
        let operation = Operation::new(&doc).unwrap();

        match operation {
            Operation::Insert { id, timestamp, namespace, document } => {
                assert_eq!(-1742072865587022793i64, id);
                assert_eq!(UTC.timestamp(1479561394, 0), timestamp);
                assert_eq!("foo.bar", namespace);
                assert_eq!("bar", document.get_str("foo").unwrap());
            },
            _ => panic!("Unexpected type of operation"),
        }
    }
}
<commit_msg>Implement From for custom error types<commit_after>#[macro_use(bson, doc)]
extern crate bson;
extern crate mongodb;
extern crate chrono;

use std::result;
use mongodb::{Client, ThreadedClient};
use mongodb::cursor::Cursor;
use mongodb::db::ThreadedDatabase;
use mongodb::coll::options::{FindOptions, CursorType};
use chrono::{DateTime, UTC, TimeZone};

#[derive(Debug)]
pub enum OplogError {
    MissingField(bson::ValueAccessError),
    Database(mongodb::Error),
    UnknownOperation(String),
}

impl From<bson::ValueAccessError> for OplogError {
    fn from(original: bson::ValueAccessError) -> OplogError {
        OplogError::MissingField(original)
    }
}

impl From<mongodb::Error> for OplogError {
    fn from(original: mongodb::Error) -> OplogError {
        OplogError::Database(original)
    }
}

type Result<T> = result::Result<T, OplogError>;

pub struct Oplog {
    cursor: Cursor,
}

#[derive(PartialEq, Debug)]
pub enum Operation<'a> {
    Insert { id: i64, timestamp: DateTime<UTC>, namespace: &'a str, document: &'a bson::Document },
    Update { id: i64, namespace: &'a str },
    Delete { id: i64, namespace: &'a str },
    Command { id: i64, namespace: &'a str },
    Database { id: i64, namespace: &'a str },
    Noop { id: i64, timestamp: DateTime<UTC>, document: &'a bson::Document },
}

impl<'a> Operation<'a> {
    pub fn new(document: &'a bson::Document) -> Result<Operation<'a>> {
        let op = try!(document.get_str("op"));

        match op {
            "n" => document_to_noop(document),
            "i" => document_to_insert(document),
            _ => Err(OplogError::UnknownOperation(op.to_owned())),
        }
    }
}

fn document_to_noop(document: &bson::Document) -> Result<Operation> {
    let h = try!(document.get_i64("h"));
    let ts = try!(document.get_time_stamp("ts"));
    let o = try!(document.get_document("o"));

    Ok(Operation::Noop { id: h, timestamp: timestamp_to_datetime(ts), document: o })
}

fn document_to_insert(document: &bson::Document) -> Result<Operation> {
    let h = try!(document.get_i64("h"));
    let ts = try!(document.get_time_stamp("ts"));
    let o = try!(document.get_document("o"));
    let ns = try!(document.get_str("ns"));

    Ok(Operation::Insert { id: h, timestamp: timestamp_to_datetime(ts), document: o, namespace: ns })
}

fn timestamp_to_datetime(timestamp: i64) -> DateTime<UTC> {
    let seconds = timestamp >> 32;
    let nanoseconds = ((timestamp & 0xFFFFFFFF) * 1000000) as u32;

    UTC.timestamp(seconds, nanoseconds)
}

impl Iterator for Oplog {
    type Item = bson::Document;

    fn next(&mut self) -> Option<bson::Document> {
        loop {
            if let Some(Ok(op)) = self.cursor.next() {
                return Some(op);
            }
        }
    }
}

impl Oplog {
    pub fn new(client: Client) -> Result<Oplog> {
        let coll = client.db("local").collection("oplog.rs");

        let mut opts = FindOptions::new();
        opts.cursor_type = CursorType::TailableAwait;
        opts.no_cursor_timeout = true;

        Ok(Oplog { cursor: try!(coll.find(None, Some(opts))) })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use bson::Bson;
    use bson::oid::ObjectId;
    use chrono::{UTC, TimeZone};

    #[test]
    fn operation_converts_noops() {
        let ref doc = doc! {
            "ts" => (Bson::TimeStamp(1479419535 << 32)),
            "h" => (-2135725856567446411i64),
            "v" => 2,
            "op" => "n",
            "ns" => "",
            "o" => {
                "msg" => "initiating set"
            }
        };
        let operation = Operation::new(doc).unwrap();

        match operation {
            Operation::Noop { id, timestamp, document } => {
                assert_eq!(-2135725856567446411i64, id);
                assert_eq!(UTC.timestamp(1479419535, 0), timestamp);
                assert_eq!("initiating set", document.get_str("msg").unwrap());
            },
            _ => panic!("Unexpected type of operation"),
        }
    }

    #[test]
    fn operation_converts_inserts() {
        let oid = ObjectId::with_string("583050b26813716e505a5bf2").unwrap();
        let ref doc = doc! {
            "ts" => (Bson::TimeStamp(1479561394 << 32)),
            "h" => (-1742072865587022793i64),
            "v" => 2,
            "op" => "i",
            "ns" => "foo.bar",
            "o" => {
                "_id" => (Bson::ObjectId(oid)),
                "foo" => "bar"
            }
        };
        let operation = Operation::new(doc).unwrap();

        match operation {
            Operation::Insert { id, timestamp, namespace, document } => {
                assert_eq!(-1742072865587022793i64, id);
                assert_eq!(UTC.timestamp(1479561394, 0), timestamp);
                assert_eq!("foo.bar", namespace);
                assert_eq!("bar", document.get_str("foo").unwrap());
            },
            _ => panic!("Unexpected type of operation"),
        }
    }
}
<|endoftext|>