<commit_before>/* Cymbalum, Molecular Simulation in Rust - Copyright (C) 2015 Guillaume Fraux
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/
 */

//! This module allow to convert from and to the internal unit system, using the
//! following units:
//!
//!  - Angstrom (A) for distances;
//!  - femtosecond (fs) for time;
//!  - Unified atomic mass unit (u or Da) for mass;
//!  - Kelvin (K) for temperature;
//!  - Number of particles for quantity of matter;
//!  - radian (rad) for angles;
//!
//!  Using this system, the internal unit for energy is 1e-4 kJ/mol.

use std::collections::HashMap;
use std::f64::consts::PI;
use std::num;
use std::fmt;
use std::error::Error;

use ::constants::{BOHR_RADIUS, NA};

// Atomic mass unit in kg
const U_IN_KG : f64 = 1.660538782e-27;

/// Get the conversion factors from a string unit to the internal units.
fn conversion_factors() -> HashMap<&'static str, f64> {
    let mut map = HashMap::new();
    // Distances units.
    map.insert("A", 1.0);
    map.insert("Å", 1.0);
    map.insert("nm", 10.0);
    map.insert("pm", 1e-2);
    map.insert("fm", 1e-5);
    map.insert("m", 1e10);
    map.insert("bohr", BOHR_RADIUS);

    // Time units.
    map.insert("fs", 1.0);
    map.insert("ps", 1e3);
    map.insert("ns", 1e6);

    // Mass units.
    map.insert("u", 1.0);
    map.insert("Da", 1.0);
    map.insert("kDa", 1.0);
    map.insert("g", 1e-3 / U_IN_KG);
    map.insert("kg", 1.0 / U_IN_KG);

    // Temperature units.
    map.insert("K", 1.0);
    // Quantity of matter units.
    map.insert("mol", NA);

    // Angle units.
    map.insert("rad", 1.0);
    map.insert("deg", PI / 180.0);

    // Energy units.
    map.insert("J", 1e-10 / U_IN_KG);
    map.insert("kJ", 1e-7 / U_IN_KG);
    map.insert("kcal", 4.184 * 1e-7 / U_IN_KG);
    map.insert("eV", 1.60217653e-19 * 1e-10 / U_IN_KG);
    map.insert("H", 4.35974417e-18 * 1e-10 / U_IN_KG);
    map.insert("Ry", 4.35974417e-18 / 2.0 * 1e-10 / U_IN_KG);

    // Force unit.
    map.insert("N", 1e-20 / U_IN_KG);

    // Pressure units.
    map.insert("Pa", 1e-40 / U_IN_KG);
    map.insert("kPa", 1e-37 / U_IN_KG);
    map.insert("MPa", 1e-34 / U_IN_KG);
    map.insert("bar", 1e-35 / U_IN_KG);
    map.insert("atm", 101325.0 * 1e-40 / U_IN_KG);

    return map;
}

/// Possible error causes when parsing an unit string.
#[derive(Debug)]
pub enum UnitParsingError {
    /// Error while parsing a power in `x^y` expressions
    PowerParsingError(num::ParseIntError),
    /// Parentheses are not balanced in this unit
    UnbalancedParentheses{
        /// The full unit that created this error
        unit:String
    },
    /// Unknown binary operator
    BadBinary{
        /// The operator that created this error
        op: char
    },
    /// This unit was not found
    NotFound{
        /// The full unit that created this error
        unit:String
    },
}

impl From<num::ParseIntError> for UnitParsingError {
    fn from(err: num::ParseIntError) -> UnitParsingError {
        UnitParsingError::PowerParsingError(err)
    }
}

impl fmt::Display for UnitParsingError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            UnitParsingError::PowerParsingError(ref err) => err.fmt(f),
            UnitParsingError::UnbalancedParentheses{ref unit} => write!(f, "Parentheses are not equilibrated in unit: {}.", unit),
            UnitParsingError::BadBinary{ref op} => write!(f, "Bad binary operator {}.", op),
            UnitParsingError::NotFound{ref unit} => write!(f, "Unit '{}' not found.", unit),
        }
    }
}

impl Error for UnitParsingError {
    fn description(&self) -> &str {
        match *self {
            UnitParsingError::PowerParsingError(ref err) => err.description(),
            UnitParsingError::UnbalancedParentheses{unit: _} => "Parentheses are not equilibrated.",
            UnitParsingError::BadBinary{op: _} => "Bad binary operator.",
            UnitParsingError::NotFound{unit: _} => "Unit not found.",
        }
    }
}

/// Recursive unit string parsing function. This return the conversion factor
/// for a given unit.
fn conversion<'a>(unit: &'a str) -> Result<f64, UnitParsingError> {
    let unit = unit.trim();
    // First check if we do already have a known unit
    let factors = conversion_factors();
    match factors.get(unit) {
        Some(val) => return Ok(*val),
        None => {} // Do nothing and try to parse the unit string.
    }

    let chars: Vec<char> = unit.chars().collect();
    let strlen = chars.len();

    if strlen == 0 {
        return Ok(1.0);
    }

    // First, check parentheses equilibration and any of '/' or '.' or '*' in the string
    let mut depth = 0;  // parentheses counter
    let mut i = strlen - 1;
    for (j, c) in unit.chars().rev().enumerate() {
        match c {
            '.' | '*' | '/' => {i = j;},
            '(' => {depth += 1;},
            ')' => {depth -= 1;},
            _ => {}
        }
    }
    let i = (strlen - 1) - i; // index of the first operator

    if depth != 0 {
        return Err(UnitParsingError::UnbalancedParentheses{unit: String::from(unit)});
    }

    // Are we enclosed by parentheses?
    if chars[0] == '(' {
        assert!(chars[strlen-1] == ')');
        return conversion(&unit[1..strlen-1])
    }

    // If a product character was found, recurse
    if i > 0 {
        let lhs = try!(conversion(&unit[..i]));
        let rhs = try!(conversion(&unit[i+1..]));

        return match chars[i] {
            '/' => Ok(lhs / rhs),
            '*' | '.' => Ok(lhs * rhs),
            _ => Err(UnitParsingError::BadBinary{op: chars[i]}),
        };
    }

    // Do we have an exponentiation?
    let mut i = strlen - 1;
    while chars[i].is_numeric() || chars[i] == '-' {
        i -= 1;
    }
    if chars[i] == '^' {
        let power = try!(unit[i+1..].parse::<i32>());
        let val = try!(conversion(&unit[0..i]));
        return Ok(val.powi(power));
    }

    return Err(UnitParsingError::NotFound{unit: String::from(unit)});
}

/// Convert the numeric value `val` from the unit `unit` to the internal unit.
///
/// ```
/// let internal = from(10.0, "A");
/// assert!(internal == 10.0);
///
/// let internal = from(1.0, "kJ/mol");
/// assert!(internal == 1000.0);
/// ```
pub fn from<'a>(val: f64, unit: &'a str) -> Result<f64, UnitParsingError> {
    let factor = match conversion(unit) {
        Ok(f) => f,
        Err(err) => {
            return Err(err);
        }
    };
    return Ok(factor * val);
}

/// Convert the numeric value `val` (in internal units) to the unit `unit`.
///
/// ```
/// let real = to(10.0, "A");
/// assert!(real == 10.0);
///
/// let real = to(1e-4, "kJ/mol");
/// assert!(internal == 1.0);
/// ```
pub fn to<'a>(val: f64, unit: &'a str) -> Result<f64, UnitParsingError> {
    let factor = match conversion(unit) {
        Ok(f) => f,
        Err(err) => {
            return Err(err);
        }
    };
    return Ok(val / factor);
}

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

    #[test]
    fn conversions() {
        // Get the factors rights
        assert_eq!(from(10.0, "A").ok(), Some(10.0));
        assert_eq!(from(10.0, "Å").ok(), Some(10.0));
        assert_eq!(from(10.0, "pm").ok(), Some(0.1));
        assert_eq!(from(10.0, "nm").ok(), Some(100.0));

        // Parse stuff
        assert_eq!(from(10.0, "bohr/fs").ok(), Some(10.0*0.52917720859));
        assert_eq!(from(10.0, "kJ/mol/A^2").ok(), Some(0.0010000000007002099));
        assert_eq!(from(10.0, "(Ry / rad^-3   )").ok(), Some(1.3127498789124938));
        assert_eq!(from(10.0, "bar/(m * fs^2)").ok(), Some(6.0221417942167636e-18));

        // Test the 'to' function too
        assert_eq!(to(25.0, "m").ok(), Some(2.5e-9));
        assert_eq!(to(25.0, "bar").ok(), Some(4.1513469550000005e9));
        assert_eq!(to(25.0, "kJ/mol").ok(), Some(249999.99982494753));
    }

    #[test]
    fn errors() {
        assert!(from(10.0, "(bar/m").is_err());
        assert!(from(10.0, "m^4-8").is_err());
        assert!(from(10.0, "m/K)").is_err());
        assert!(from(10.0, "HJK").is_err());
    }
}
<commit_msg>Add a units::from_str function to parse a string<commit_after>/* Cymbalum, Molecular Simulation in Rust - Copyright (C) 2015 Guillaume Fraux
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/
 */

//! This module allow to convert from and to the internal unit system, using the
//! following units:
//!
//!  - Angstrom (A) for distances;
//!  - femtosecond (fs) for time;
//!  - Unified atomic mass unit (u or Da) for mass;
//!  - Kelvin (K) for temperature;
//!  - Number of particles for quantity of matter;
//!  - radian (rad) for angles;
//!
//!  Using this system, the internal unit for energy is 1e-4 kJ/mol.

use std::collections::HashMap;
use std::f64::consts::PI;
use std::num;
use std::fmt;
use std::error::Error;

use ::constants::{BOHR_RADIUS, NA};

// Atomic mass unit in kg
const U_IN_KG : f64 = 1.660538782e-27;

/// Get the conversion factors from a string unit to the internal units.
fn conversion_factors() -> HashMap<&'static str, f64> {
    let mut map = HashMap::new();
    // Distances units.
    map.insert("A", 1.0);
    map.insert("Å", 1.0);
    map.insert("nm", 10.0);
    map.insert("pm", 1e-2);
    map.insert("fm", 1e-5);
    map.insert("m", 1e10);
    map.insert("bohr", BOHR_RADIUS);

    // Time units.
    map.insert("fs", 1.0);
    map.insert("ps", 1e3);
    map.insert("ns", 1e6);

    // Mass units.
    map.insert("u", 1.0);
    map.insert("Da", 1.0);
    map.insert("kDa", 1.0);
    map.insert("g", 1e-3 / U_IN_KG);
    map.insert("kg", 1.0 / U_IN_KG);

    // Temperature units.
    map.insert("K", 1.0);
    // Quantity of matter units.
    map.insert("mol", NA);

    // Angle units.
    map.insert("rad", 1.0);
    map.insert("deg", PI / 180.0);

    // Energy units.
    map.insert("J", 1e-10 / U_IN_KG);
    map.insert("kJ", 1e-7 / U_IN_KG);
    map.insert("kcal", 4.184 * 1e-7 / U_IN_KG);
    map.insert("eV", 1.60217653e-19 * 1e-10 / U_IN_KG);
    map.insert("H", 4.35974417e-18 * 1e-10 / U_IN_KG);
    map.insert("Ry", 4.35974417e-18 / 2.0 * 1e-10 / U_IN_KG);

    // Force unit.
    map.insert("N", 1e-20 / U_IN_KG);

    // Pressure units.
    map.insert("Pa", 1e-40 / U_IN_KG);
    map.insert("kPa", 1e-37 / U_IN_KG);
    map.insert("MPa", 1e-34 / U_IN_KG);
    map.insert("bar", 1e-35 / U_IN_KG);
    map.insert("atm", 101325.0 * 1e-40 / U_IN_KG);

    return map;
}

/// Possible error causes when parsing an unit string.
#[derive(Debug)]
pub enum UnitParsingError {
    /// Error while parsing a power in `x^y` expressions
    PowerParsingError(num::ParseIntError),
    /// Error while parsing the value part of an unit string
    ValueParsingError(num::ParseFloatError),
    /// Parentheses are not balanced in this unit
    UnbalancedParentheses{
        /// The full unit that created this error
        unit:String
    },
    /// Unknown binary operator
    BadBinary{
        /// The operator that created this error
        op: char
    },
    /// This unit was not found
    NotFound{
        /// The full unit that created this error
        unit:String
    },
}

impl From<num::ParseIntError> for UnitParsingError {
    fn from(err: num::ParseIntError) -> UnitParsingError {
        UnitParsingError::PowerParsingError(err)
    }
}

impl From<num::ParseFloatError> for UnitParsingError {
    fn from(err: num::ParseFloatError) -> UnitParsingError {
        UnitParsingError::ValueParsingError(err)
    }
}

impl fmt::Display for UnitParsingError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            UnitParsingError::PowerParsingError(ref err) => err.fmt(f),
            UnitParsingError::ValueParsingError(ref err) => err.fmt(f),
            UnitParsingError::UnbalancedParentheses{ref unit} => write!(f, "Parentheses are not equilibrated in unit: {}.", unit),
            UnitParsingError::BadBinary{ref op} => write!(f, "Bad binary operator {}.", op),
            UnitParsingError::NotFound{ref unit} => write!(f, "Unit '{}' not found.", unit),
        }
    }
}

impl Error for UnitParsingError {
    fn description(&self) -> &str {
        match *self {
            UnitParsingError::PowerParsingError(ref err) => err.description(),
            UnitParsingError::ValueParsingError(ref err) => err.description(),
            UnitParsingError::UnbalancedParentheses{unit: _} => "Parentheses are not equilibrated.",
            UnitParsingError::BadBinary{op: _} => "Bad binary operator.",
            UnitParsingError::NotFound{unit: _} => "Unit not found.",
        }
    }
}

/// Recursive unit string parsing function. This return the conversion factor
/// for a given unit.
fn conversion<'a>(unit: &'a str) -> Result<f64, UnitParsingError> {
    let unit = unit.trim();
    // First check if we do already have a known unit
    let factors = conversion_factors();
    match factors.get(unit) {
        Some(val) => return Ok(*val),
        None => {} // Do nothing and try to parse the unit string.
    }

    let chars: Vec<char> = unit.chars().collect();
    let strlen = chars.len();

    if strlen == 0 {
        return Ok(1.0);
    }

    // First, check parentheses equilibration and any of '/' or '.' or '*' in the string
    let mut depth = 0;  // parentheses counter
    let mut i = strlen - 1;
    for (j, c) in unit.chars().rev().enumerate() {
        match c {
            '.' | '*' | '/' => {i = j;},
            '(' => {depth += 1;},
            ')' => {depth -= 1;},
            _ => {}
        }
    }
    let i = (strlen - 1) - i; // index of the first operator

    if depth != 0 {
        return Err(UnitParsingError::UnbalancedParentheses{unit: String::from(unit)});
    }

    // Are we enclosed by parentheses?
    if chars[0] == '(' {
        assert!(chars[strlen-1] == ')');
        return conversion(&unit[1..strlen-1])
    }

    // If a product character was found, recurse
    if i > 0 {
        let lhs = try!(conversion(&unit[..i]));
        let rhs = try!(conversion(&unit[i+1..]));

        return match chars[i] {
            '/' => Ok(lhs / rhs),
            '*' | '.' => Ok(lhs * rhs),
            _ => Err(UnitParsingError::BadBinary{op: chars[i]}),
        };
    }

    // Do we have an exponentiation?
    let mut i = strlen - 1;
    while chars[i].is_numeric() || chars[i] == '-' {
        i -= 1;
    }
    if chars[i] == '^' {
        let power = try!(unit[i+1..].parse::<i32>());
        let val = try!(conversion(&unit[0..i]));
        return Ok(val.powi(power));
    }

    return Err(UnitParsingError::NotFound{unit: String::from(unit)});
}

/// Convert the numeric value `val` from the unit `unit` to the internal unit.
///
/// ```
/// let internal = from(10.0, "A");
/// assert!(internal == 10.0);
///
/// let internal = from(1.0, "kJ/mol");
/// assert!(internal == 1000.0);
/// ```
pub fn from(val: f64, unit: &str) -> Result<f64, UnitParsingError> {
    let factor = try!(conversion(unit));
    return Ok(factor * val);
}

/// Parse the string `val` and convert it to the corresponding internal unit
///
/// ```
/// let internal = from_str("10 A");
/// assert!(internal == 10.0);
///
/// let internal = from("1 kJ/mol");
/// assert!(internal == 1000.0);
/// ```
pub fn from_str(val: &str) -> Result<f64, UnitParsingError> {
    let unit = val.split_whitespace().skip(1).collect::<Vec<&str>>().join(" ");
    let factor = try!(conversion(&unit));
    let val: &str = val.split_whitespace().take(1).collect::<Vec<&str>>()[0];
    let val: f64 = try!(val.parse());
    return Ok(factor * val);
}

/// Convert the numeric value `val` (in internal units) to the unit `unit`.
///
/// ```
/// let real = to(10.0, "A");
/// assert!(real == 10.0);
///
/// let real = to(1e-4, "kJ/mol");
/// assert!(internal == 1.0);
/// ```
pub fn to(val: f64, unit: &str) -> Result<f64, UnitParsingError> {
    let factor = try!(conversion(unit));
    return Ok(val / factor);
}

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

    #[test]
    fn conversions() {
        // Get the factors rights
        assert_eq!(from(10.0, "A").ok(), Some(10.0));
        assert_eq!(from(10.0, "Å").ok(), Some(10.0));
        assert_eq!(from(10.0, "pm").ok(), Some(0.1));
        assert_eq!(from(10.0, "nm").ok(), Some(100.0));

        assert_eq!(from_str("10.0 A").ok(), Some(10.0));
        assert_eq!(from_str("10 A").ok(), Some(10.0));
        assert_eq!(from_str("1e1 A").ok(), Some(10.0));
        assert_eq!(from_str("10").ok(), Some(10.0));

        // Parse stuff
        assert_eq!(from(10.0, "bohr/fs").ok(), Some(10.0*0.52917720859));
        assert_eq!(from(10.0, "kJ/mol/A^2").ok(), Some(0.0010000000007002099));
        assert_eq!(from(10.0, "(Ry / rad^-3   )").ok(), Some(1.3127498789124938));
        assert_eq!(from(10.0, "bar/(m * fs^2)").ok(), Some(6.0221417942167636e-18));

        assert_eq!(from_str("10 bar/(m * fs^2)").ok(), Some(6.0221417942167636e-18));

        // Test the 'to' function too
        assert_eq!(to(25.0, "m").ok(), Some(2.5e-9));
        assert_eq!(to(25.0, "bar").ok(), Some(4.1513469550000005e9));
        assert_eq!(to(25.0, "kJ/mol").ok(), Some(249999.99982494753));
    }

    #[test]
    fn errors() {
        assert!(from(10.0, "(bar/m").is_err());
        assert!(from(10.0, "m^4-8").is_err());
        assert!(from(10.0, "m^z4").is_err());
        assert!(from(10.0, "m/K)").is_err());
        assert!(from(10.0, "HJK").is_err());

        assert!(from_str("10a.0 bar").is_err());
        assert!(from_str("h10").is_err());
    }
}
<|endoftext|>


<commit_before>use libc::c_ulonglong;

#[doc(hidden)]
pub fn marshal<T, F>(buf: &[u8],
                     padbefore: usize,
                     bytestodrop: usize,
                     f: F
                     ) -> (Vec<u8>, T)
    where F: Fn(*mut u8, *const u8, c_ulonglong) -> T {
    let mut dst = Vec::with_capacity(buf.len() + padbefore);
    for _ in (0..padbefore) {
        dst.push(0);
    }
    dst.push_all(buf);
    let pdst = dst.as_mut_ptr();
    let psrc = dst.as_ptr();
    let res = f(pdst, psrc, dst.len() as c_ulonglong);
    (dst.into_iter().skip(bytestodrop).collect(), res)
}

macro_rules! newtype_clone (($newtype:ident) => (
        impl Clone for $newtype {
            fn clone(&self) -> $newtype {
                let &$newtype(v) = self;
                $newtype(v)
            }
        }

        ));

macro_rules! newtype_drop (($newtype:ident) => (
        impl Drop for $newtype {
            fn drop(&mut self) {
                use libc::size_t;
                use ffi;
                let &mut $newtype(ref mut v) = self;
                unsafe {
                    ffi::sodium_memzero(v.as_mut_ptr(), v.len() as size_t);
                }
            }
        }
        ));

macro_rules! newtype_impl (($newtype:ident, $len:expr) => (
    impl $newtype {
        /**
         * `from_slice()` creates an object from a byte slice
         *
         * This function will fail and return None if the length of
         * the byte-slice isn't equal to the length of the object
         */
        pub fn from_slice(bs: &[u8]) -> Option<$newtype> {
            if bs.len() != $len {
                return None
            }
            let mut n = $newtype([0; $len]);
            {
                let $newtype(ref mut b) = n;
                for (bi, &bsi) in b.iter_mut().zip(bs.iter()) {
                    *bi = bsi
                }
            }
            Some(n)
        }
    }
    /**
     * Allows a user to access the byte contents of an object as a slice.
     *
     * WARNING: it might be tempting to do comparisons on objects
     * by using `x[a..b] == y[a..b]`. This will open up for timing attacks
     * when comparing for example authenticator tags. Because of this only
     * use the comparison functions exposed by the sodiumoxide API.
     */
    impl Index<Range<usize>> for $newtype {
        type Output = [u8];
        fn index(&self, _index: Range<usize>) -> &[u8] {
            let &$newtype(ref b) = self;
            b.index(_index)
        }
    }
    /**
     * Allows a user to access the byte contents of an object as a slice.
     *
     * WARNING: it might be tempting to do comparisons on objects
     * by using `x[..b] == y[..b]`. This will open up for timing attacks
     * when comparing for example authenticator tags. Because of this only
     * use the comparison functions exposed by the sodiumoxide API.
     */
    impl Index<RangeTo<usize>> for $newtype {
        type Output = [u8];
        fn index(&self, _index: RangeTo<usize>) -> &[u8] {
            let &$newtype(ref b) = self;
            b.index(_index)
        }
    }
    /**
     * Allows a user to access the byte contents of an object as a slice.
     *
     * WARNING: it might be tempting to do comparisons on objects
     * by using `x[a..] == y[a..]`. This will open up for timing attacks
     * when comparing for example authenticator tags. Because of this only
     * use the comparison functions exposed by the sodiumoxide API.
     */
    impl Index<RangeFrom<usize>> for $newtype {
        type Output = [u8];
        fn index(&self, _index: RangeFrom<usize>) -> &[u8] {
            let &$newtype(ref b) = self;
            b.index(_index)
        }
    }
    /**
     * Allows a user to access the byte contents of an object as a slice.
     *
     * WARNING: it might be tempting to do comparisons on objects
     * by using `x[] == y[]`. This will open up for timing attacks
     * when comparing for example authenticator tags. Because of this only
     * use the comparison functions exposed by the sodiumoxide API.
     */
    impl Index<RangeFull> for $newtype {
        type Output = [u8];
        fn index(&self, _index: RangeFull) -> &[u8] {
            let &$newtype(ref b) = self;
            b.index(_index)
        }
    }
    ));
<commit_msg>Replace `push_all()` with `extend()`, #51<commit_after>use libc::c_ulonglong;

#[doc(hidden)]
pub fn marshal<T, F>(buf: &[u8],
                     padbefore: usize,
                     bytestodrop: usize,
                     f: F
                     ) -> (Vec<u8>, T)
    where F: Fn(*mut u8, *const u8, c_ulonglong) -> T {
    let mut dst = Vec::with_capacity(buf.len() + padbefore);
    for _ in (0..padbefore) {
        dst.push(0);
    }
    dst.extend(buf.iter().cloned());
    let pdst = dst.as_mut_ptr();
    let psrc = dst.as_ptr();
    let res = f(pdst, psrc, dst.len() as c_ulonglong);
    (dst.into_iter().skip(bytestodrop).collect(), res)
}

macro_rules! newtype_clone (($newtype:ident) => (
        impl Clone for $newtype {
            fn clone(&self) -> $newtype {
                let &$newtype(v) = self;
                $newtype(v)
            }
        }

        ));

macro_rules! newtype_drop (($newtype:ident) => (
        impl Drop for $newtype {
            fn drop(&mut self) {
                use libc::size_t;
                use ffi;
                let &mut $newtype(ref mut v) = self;
                unsafe {
                    ffi::sodium_memzero(v.as_mut_ptr(), v.len() as size_t);
                }
            }
        }
        ));

macro_rules! newtype_impl (($newtype:ident, $len:expr) => (
    impl $newtype {
        /**
         * `from_slice()` creates an object from a byte slice
         *
         * This function will fail and return None if the length of
         * the byte-slice isn't equal to the length of the object
         */
        pub fn from_slice(bs: &[u8]) -> Option<$newtype> {
            if bs.len() != $len {
                return None
            }
            let mut n = $newtype([0; $len]);
            {
                let $newtype(ref mut b) = n;
                for (bi, &bsi) in b.iter_mut().zip(bs.iter()) {
                    *bi = bsi
                }
            }
            Some(n)
        }
    }
    /**
     * Allows a user to access the byte contents of an object as a slice.
     *
     * WARNING: it might be tempting to do comparisons on objects
     * by using `x[a..b] == y[a..b]`. This will open up for timing attacks
     * when comparing for example authenticator tags. Because of this only
     * use the comparison functions exposed by the sodiumoxide API.
     */
    impl Index<Range<usize>> for $newtype {
        type Output = [u8];
        fn index(&self, _index: Range<usize>) -> &[u8] {
            let &$newtype(ref b) = self;
            b.index(_index)
        }
    }
    /**
     * Allows a user to access the byte contents of an object as a slice.
     *
     * WARNING: it might be tempting to do comparisons on objects
     * by using `x[..b] == y[..b]`. This will open up for timing attacks
     * when comparing for example authenticator tags. Because of this only
     * use the comparison functions exposed by the sodiumoxide API.
     */
    impl Index<RangeTo<usize>> for $newtype {
        type Output = [u8];
        fn index(&self, _index: RangeTo<usize>) -> &[u8] {
            let &$newtype(ref b) = self;
            b.index(_index)
        }
    }
    /**
     * Allows a user to access the byte contents of an object as a slice.
     *
     * WARNING: it might be tempting to do comparisons on objects
     * by using `x[a..] == y[a..]`. This will open up for timing attacks
     * when comparing for example authenticator tags. Because of this only
     * use the comparison functions exposed by the sodiumoxide API.
     */
    impl Index<RangeFrom<usize>> for $newtype {
        type Output = [u8];
        fn index(&self, _index: RangeFrom<usize>) -> &[u8] {
            let &$newtype(ref b) = self;
            b.index(_index)
        }
    }
    /**
     * Allows a user to access the byte contents of an object as a slice.
     *
     * WARNING: it might be tempting to do comparisons on objects
     * by using `x[] == y[]`. This will open up for timing attacks
     * when comparing for example authenticator tags. Because of this only
     * use the comparison functions exposed by the sodiumoxide API.
     */
    impl Index<RangeFull> for $newtype {
        type Output = [u8];
        fn index(&self, _index: RangeFull) -> &[u8] {
            let &$newtype(ref b) = self;
            b.index(_index)
        }
    }
    ));
<|endoftext|>


<commit_before>use std;
use types::*;
use serde_json;

pub fn escape_single_quote(s: &str) -> String {
    s.replace("'", "''")
}

#[test]
fn test_escape_single_quote() {
    assert_eq!(escape_single_quote("my' precious"), "my'' precious");
}

pub fn get_rootPath<'a>(path: &'a Path, languageId: &str, rootMarkers: &Option<RootMarkers>) -> Result<&'a Path> {
    if let Some(ref rootMarkers) = *rootMarkers {
        let empty = vec![];
        let rootMarkers = match *rootMarkers {
            RootMarkers::Array(ref arr) => arr,
            RootMarkers::Map(ref map) => map.get(languageId).unwrap_or(&empty),
        };

        for marker in rootMarkers {
            let ret = traverse_up(path, |dir| {
                let p = dir.join(marker);
                let p = p.to_str();
                if p.is_none() {
                    return false;
                }
                let p = p.unwrap_or_default();
                match glob::glob(p) {
                    Ok(paths) => paths.count() > 0,
                    _ => false,
                }
            });

            if ret.is_ok() {
                return ret;
            }
        }
    }

    match languageId {
        "rust" => traverse_up(path, |dir| dir.join("Cargo.toml").exists()),
        "php" => traverse_up(path, |dir| dir.join("composer.json").exists()),
        "javascript" | "typescript" => traverse_up(path, |dir| dir.join("package.json").exists()),
        "python" => traverse_up(path, |dir| {
            dir.join("__init__.py").exists() || dir.join("setup.py").exists()
        }),
        "c" | "cpp" => traverse_up(path, |dir| {
            dir.join("compile_commands.json").exists() || dir.join("CMakeLists.txt").exists()
        }),
        "cs" => traverse_up(path, is_dotnet_root),
        "java" => traverse_up(path, |dir| {
            dir.join(".project").exists() || dir.join("pom.xml").exists()
        }),
        "haskell" => traverse_up(path, |dir| dir.join("stack.yaml").exists())
            .or_else(|_| traverse_up(path, |dir| dir.join(".cabal").exists())),
        _ => Err(format_err!("Unknown languageId: {}", languageId)),
    }.or_else(|_| {
        traverse_up(path, |dir| {
            dir.join(".git").exists() || dir.join(".hg").exists() || dir.join(".svn").exists()
        })
    })
        .or_else(|_| {
            let parent = path.parent()
                .ok_or_else(|| format_err!("Failed to get file dir"));
            warn!(
                "Unknown project type. Fallback to use dir as project root: {:?}",
                parent
            );
            parent
        })
}

fn traverse_up<F>(path: &Path, predicate: F) -> Result<&Path>
where
    F: Fn(&Path) -> bool,
{
    if predicate(path) {
        return Ok(path);
    }

    let next_path = path.parent().ok_or_else(|| format_err!("Hit root"))?;

    traverse_up(next_path, predicate)
}

fn is_dotnet_root(dir: &Path) -> bool {
    if dir.join("project.json").exists() {
        return true;
    }
    if !dir.is_dir() {
        return false;
    }

    let entries = match dir.read_dir() {
        Ok(entries) => entries,
        Err(_) => return false,
    };
    for entry in entries {
        if let Ok(entry) = entry {
            if entry.path().ends_with(".csproj") {
                return true;
            }
        }
    }

    false
}

pub trait ToUrl {
    fn to_url(&self) -> Result<Url>;
}

impl<P: AsRef<Path> + std::fmt::Debug> ToUrl for P {
    fn to_url(&self) -> Result<Url> {
        Url::from_file_path(self).or_else(|_| {
            Err(format_err!(
                "Failed to convert from path ({:?}) to Url",
                self
            ))
        })
    }
}

pub fn get_logpath() -> PathBuf {
    let dir = env::var("TMP")
        .or_else(|_| env::var("TEMP"))
        .unwrap_or_else(|_| "/tmp".to_owned());

    Path::new(&dir).join("LanguageClient.log")
}

pub fn get_logpath_server() -> PathBuf {
    let dir = env::var("TMP")
        .or_else(|_| env::var("TEMP"))
        .unwrap_or_else(|_| "/tmp".to_owned());

    Path::new(&dir).join("LanguageServer.log")
}

pub fn get_log_server() -> Result<String> {
    let mut f = std::fs::OpenOptions::new()
        .read(true)
        .open(get_logpath_server())?;
    let mut buffer = String::new();
    f.read_to_string(&mut buffer)?;
    Ok(buffer)
}

pub trait Strip {
    fn strip(&self) -> Self;
}

impl<'a> Strip for &'a str {
    fn strip(&self) -> Self {
        self.trim().trim_matches(|c| c == '\r' || c == '\n')
    }
}

impl Strip for String {
    fn strip(&self) -> Self {
        self.as_str().strip().to_owned()
    }
}

pub fn apply_TextEdits(lines: &[String], edits: &[TextEdit]) -> Result<Vec<String>> {
    // Edits are ordered from bottom to top, from right to left.
    let mut edits_by_index = vec![];
    for edit in edits {
        let start_line = edit.range.start.line.to_usize()?;
        let start_character: usize = edit.range.start.character.to_usize()?;
        let end_line: usize = edit.range.end.line.to_usize()?;
        let end_character: usize = edit.range.end.character.to_usize()?;

        let start = lines[..start_line]
            .iter()
            .map(|l| l.len())
            .fold(0, |acc, l| acc + l + 1 /*line ending*/) + start_character;
        let end = lines[..end_line]
            .iter()
            .map(|l| l.len())
            .fold(0, |acc, l| acc + l + 1 /*line ending*/) + end_character;

        edits_by_index.push((start, end, &edit.new_text));
    }

    let mut text = lines.join("\n");
    for (start, end, new_text) in edits_by_index {
        text = String::new() + &text[..start] + new_text + &text[end..];
    }

    Ok(text.split('\n').map(|l| l.to_owned()).collect())
}

#[test]
fn test_apply_TextEdit() {
    let lines: Vec<String> = r#"fn main() {
0;
}
"#.split('\n')
        .map(|l| l.to_owned())
        .collect();

    let expect: Vec<String> = r#"fn main() {
    0;
}
"#.split('\n')
        .map(|l| l.to_owned())
        .collect();

    let edit = TextEdit {
        range: Range {
            start: Position {
                line: 0,
                character: 0,
            },
            end: Position {
                line: 3,
                character: 0,
            },
        },
        new_text: r#"fn main() {
    0;
}
"#.to_owned(),
    };

    assert_eq!(apply_TextEdits(&lines, &[edit]).unwrap(), expect);
}

fn get_command_add_sign(sign: &Sign, filename: &str) -> String {
    format!(
        " | execute 'sign place {} line={} name=LanguageClient{:?} file={}'",
        sign.id, sign.line, sign.severity, filename
    )
}

#[test]
fn test_get_command_add_sign() {
    let sign = Sign::new(1, DiagnosticSeverity::Error);
    assert_eq!(
        get_command_add_sign(&sign, ""),
        " | execute 'sign place 75000 line=1 name=LanguageClientError file='"
    );

    let sign = Sign::new(7, DiagnosticSeverity::Error);
    assert_eq!(
        get_command_add_sign(&sign, ""),
        " | execute 'sign place 75024 line=7 name=LanguageClientError file='"
    );

    let sign = Sign::new(7, DiagnosticSeverity::Hint);
    assert_eq!(
        get_command_add_sign(&sign, ""),
        " | execute 'sign place 75027 line=7 name=LanguageClientHint file='"
    );
}

fn get_command_delete_sign(sign: &Sign, filename: &str) -> String {
    format!(" | execute 'sign unplace {} file={}'", sign.id, filename)
}

#[test]
fn test_get_command_delete_sign() {}

use diff;

pub fn get_command_update_signs(signs_prev: &[Sign], signs: &[Sign], filename: &str) -> String {
    let mut cmd = "echo".to_owned();
    for comp in diff::slice(signs_prev, signs) {
        match comp {
            diff::Result::Left(sign) => {
                cmd += &get_command_delete_sign(sign, filename);
            }
            diff::Result::Right(sign) => {
                cmd += &get_command_add_sign(sign, filename);
            }
            diff::Result::Both(_, _) => (),
        }
    }

    cmd
}

#[test]
fn test_get_command_update_signs() {}

pub trait Merge {
    fn merge(&mut self, other: Self) -> ();
}

impl<K, V> Merge for HashMap<K, V>
where
    K: std::cmp::Eq + std::hash::Hash,
{
    fn merge(&mut self, other: Self) -> () {
        for (k, v) in other {
            self.insert(k, v);
        }
    }
}

pub trait Combine {
    fn combine(self, other: Self) -> Self
    where
        Self: Sized;
}

impl Combine for Value {
    fn combine(self, other: Self) -> Self {
        match (self, other) {
            (this, Value::Null) => this,
            (Value::Object(this), Value::Object(other)) => {
                let mut map = serde_json::map::Map::new();
                let mut keys: HashSet<String> = HashSet::new();
                for k in this.keys() {
                    keys.insert(k.clone());
                }
                for k in other.keys() {
                    keys.insert(k.clone());
                }
                for k in keys.drain() {
                    let v1 = this.get(&k).unwrap_or(&Value::Null).clone();
                    let v2 = other.get(&k).unwrap_or(&Value::Null).clone();
                    map.insert(k, v1.combine(v2));
                }
                Value::Object(map)
            }
            (_, other) => other,
        }
    }
}

pub fn vim_cmd_args_to_value(args: &[String]) -> Result<Value> {
    let mut map = serde_json::map::Map::new();
    for arg in args {
        let mut tokens: Vec<_> = arg.splitn(2, '=').collect();
        tokens.reverse();
        let key = tokens
            .pop()
            .ok_or_else(|| format_err!("Failed to parse command arguments."))?;
        let value = tokens
            .pop()
            .ok_or_else(|| format_err!("Failed to parse command arguments."))?;
        let value = Value::String(value.to_owned());
        map.insert(key.to_owned(), value);
    }

    Ok(Value::Object(map))
}

#[test]
fn test_vim_cmd_args_to_value() {
    let cmdargs = ["rootPath=/tmp".to_owned()];
    assert_eq!(
        vim_cmd_args_to_value(&cmdargs).unwrap(),
        json!({
        "rootPath": "/tmp"
    })
    );
}

pub fn diff_value<'a>(v1: &'a Value, v2: &'a Value, path: &str) -> HashMap<String, (Value, Value)> {
    let mut diffs = HashMap::new();
    match (v1, v2) {
        (&Value::Null, &Value::Null)
        | (&Value::Bool(_), &Value::Bool(_))
        | (&Value::Number(_), &Value::Number(_))
        | (&Value::String(_), &Value::String(_))
        | (&Value::Array(_), &Value::Array(_)) => if v1 != v2 {
            diffs.insert(path.to_owned(), (v1.clone(), v2.clone()));
        },
        (&Value::Object(ref map1), &Value::Object(ref map2)) => {
            let keys1: HashSet<&String> = map1.keys().collect();
            let keys2: HashSet<&String> = map2.keys().collect();
            for k in keys1.union(&keys2) {
                let mut next_path = String::from(path);
                next_path += ".";
                next_path += k;
                let next_diffs = diff_value(
                    map1.get(*k).unwrap_or(&Value::Null),
                    map2.get(*k).unwrap_or(&Value::Null),
                    &next_path,
                );
                diffs.merge(next_diffs);
            }
        }
        _ => {
            diffs.insert(path.to_owned(), (v1.clone(), v2.clone()));
        }
    }

    diffs
}

#[test]
fn test_diff_value() {
    assert_eq!(diff_value(&json!({}), &json!({}), "state",), hashmap!());
    assert_eq!(
        diff_value(
            &json!({
                "line": 1,
            }),
            &json!({
                "line": 3,
            }),
            "state"
        ),
        hashmap!{
            "state.line".to_owned() => (json!(1), json!(3)),
        }
    );
}
<commit_msg>Remove CMakeLists from c++ root heuristic detection.<commit_after>use std;
use types::*;
use serde_json;

pub fn escape_single_quote(s: &str) -> String {
    s.replace("'", "''")
}

#[test]
fn test_escape_single_quote() {
    assert_eq!(escape_single_quote("my' precious"), "my'' precious");
}

pub fn get_rootPath<'a>(path: &'a Path, languageId: &str, rootMarkers: &Option<RootMarkers>) -> Result<&'a Path> {
    if let Some(ref rootMarkers) = *rootMarkers {
        let empty = vec![];
        let rootMarkers = match *rootMarkers {
            RootMarkers::Array(ref arr) => arr,
            RootMarkers::Map(ref map) => map.get(languageId).unwrap_or(&empty),
        };

        for marker in rootMarkers {
            let ret = traverse_up(path, |dir| {
                let p = dir.join(marker);
                let p = p.to_str();
                if p.is_none() {
                    return false;
                }
                let p = p.unwrap_or_default();
                match glob::glob(p) {
                    Ok(paths) => paths.count() > 0,
                    _ => false,
                }
            });

            if ret.is_ok() {
                return ret;
            }
        }
    }

    match languageId {
        "rust" => traverse_up(path, |dir| dir.join("Cargo.toml").exists()),
        "php" => traverse_up(path, |dir| dir.join("composer.json").exists()),
        "javascript" | "typescript" => traverse_up(path, |dir| dir.join("package.json").exists()),
        "python" => traverse_up(path, |dir| {
            dir.join("__init__.py").exists() || dir.join("setup.py").exists()
        }),
        "c" | "cpp" => traverse_up(path, |dir| {
            dir.join("compile_commands.json").exists()
        }),
        "cs" => traverse_up(path, is_dotnet_root),
        "java" => traverse_up(path, |dir| {
            dir.join(".project").exists() || dir.join("pom.xml").exists()
        }),
        "haskell" => traverse_up(path, |dir| dir.join("stack.yaml").exists())
            .or_else(|_| traverse_up(path, |dir| dir.join(".cabal").exists())),
        _ => Err(format_err!("Unknown languageId: {}", languageId)),
    }.or_else(|_| {
        traverse_up(path, |dir| {
            dir.join(".git").exists() || dir.join(".hg").exists() || dir.join(".svn").exists()
        })
    })
        .or_else(|_| {
            let parent = path.parent()
                .ok_or_else(|| format_err!("Failed to get file dir"));
            warn!(
                "Unknown project type. Fallback to use dir as project root: {:?}",
                parent
            );
            parent
        })
}

fn traverse_up<F>(path: &Path, predicate: F) -> Result<&Path>
where
    F: Fn(&Path) -> bool,
{
    if predicate(path) {
        return Ok(path);
    }

    let next_path = path.parent().ok_or_else(|| format_err!("Hit root"))?;

    traverse_up(next_path, predicate)
}

fn is_dotnet_root(dir: &Path) -> bool {
    if dir.join("project.json").exists() {
        return true;
    }
    if !dir.is_dir() {
        return false;
    }

    let entries = match dir.read_dir() {
        Ok(entries) => entries,
        Err(_) => return false,
    };
    for entry in entries {
        if let Ok(entry) = entry {
            if entry.path().ends_with(".csproj") {
                return true;
            }
        }
    }

    false
}

pub trait ToUrl {
    fn to_url(&self) -> Result<Url>;
}

impl<P: AsRef<Path> + std::fmt::Debug> ToUrl for P {
    fn to_url(&self) -> Result<Url> {
        Url::from_file_path(self).or_else(|_| {
            Err(format_err!(
                "Failed to convert from path ({:?}) to Url",
                self
            ))
        })
    }
}

pub fn get_logpath() -> PathBuf {
    let dir = env::var("TMP")
        .or_else(|_| env::var("TEMP"))
        .unwrap_or_else(|_| "/tmp".to_owned());

    Path::new(&dir).join("LanguageClient.log")
}

pub fn get_logpath_server() -> PathBuf {
    let dir = env::var("TMP")
        .or_else(|_| env::var("TEMP"))
        .unwrap_or_else(|_| "/tmp".to_owned());

    Path::new(&dir).join("LanguageServer.log")
}

pub fn get_log_server() -> Result<String> {
    let mut f = std::fs::OpenOptions::new()
        .read(true)
        .open(get_logpath_server())?;
    let mut buffer = String::new();
    f.read_to_string(&mut buffer)?;
    Ok(buffer)
}

pub trait Strip {
    fn strip(&self) -> Self;
}

impl<'a> Strip for &'a str {
    fn strip(&self) -> Self {
        self.trim().trim_matches(|c| c == '\r' || c == '\n')
    }
}

impl Strip for String {
    fn strip(&self) -> Self {
        self.as_str().strip().to_owned()
    }
}

pub fn apply_TextEdits(lines: &[String], edits: &[TextEdit]) -> Result<Vec<String>> {
    // Edits are ordered from bottom to top, from right to left.
    let mut edits_by_index = vec![];
    for edit in edits {
        let start_line = edit.range.start.line.to_usize()?;
        let start_character: usize = edit.range.start.character.to_usize()?;
        let end_line: usize = edit.range.end.line.to_usize()?;
        let end_character: usize = edit.range.end.character.to_usize()?;

        let start = lines[..start_line]
            .iter()
            .map(|l| l.len())
            .fold(0, |acc, l| acc + l + 1 /*line ending*/) + start_character;
        let end = lines[..end_line]
            .iter()
            .map(|l| l.len())
            .fold(0, |acc, l| acc + l + 1 /*line ending*/) + end_character;

        edits_by_index.push((start, end, &edit.new_text));
    }

    let mut text = lines.join("\n");
    for (start, end, new_text) in edits_by_index {
        text = String::new() + &text[..start] + new_text + &text[end..];
    }

    Ok(text.split('\n').map(|l| l.to_owned()).collect())
}

#[test]
fn test_apply_TextEdit() {
    let lines: Vec<String> = r#"fn main() {
0;
}
"#.split('\n')
        .map(|l| l.to_owned())
        .collect();

    let expect: Vec<String> = r#"fn main() {
    0;
}
"#.split('\n')
        .map(|l| l.to_owned())
        .collect();

    let edit = TextEdit {
        range: Range {
            start: Position {
                line: 0,
                character: 0,
            },
            end: Position {
                line: 3,
                character: 0,
            },
        },
        new_text: r#"fn main() {
    0;
}
"#.to_owned(),
    };

    assert_eq!(apply_TextEdits(&lines, &[edit]).unwrap(), expect);
}

fn get_command_add_sign(sign: &Sign, filename: &str) -> String {
    format!(
        " | execute 'sign place {} line={} name=LanguageClient{:?} file={}'",
        sign.id, sign.line, sign.severity, filename
    )
}

#[test]
fn test_get_command_add_sign() {
    let sign = Sign::new(1, DiagnosticSeverity::Error);
    assert_eq!(
        get_command_add_sign(&sign, ""),
        " | execute 'sign place 75000 line=1 name=LanguageClientError file='"
    );

    let sign = Sign::new(7, DiagnosticSeverity::Error);
    assert_eq!(
        get_command_add_sign(&sign, ""),
        " | execute 'sign place 75024 line=7 name=LanguageClientError file='"
    );

    let sign = Sign::new(7, DiagnosticSeverity::Hint);
    assert_eq!(
        get_command_add_sign(&sign, ""),
        " | execute 'sign place 75027 line=7 name=LanguageClientHint file='"
    );
}

fn get_command_delete_sign(sign: &Sign, filename: &str) -> String {
    format!(" | execute 'sign unplace {} file={}'", sign.id, filename)
}

#[test]
fn test_get_command_delete_sign() {}

use diff;

pub fn get_command_update_signs(signs_prev: &[Sign], signs: &[Sign], filename: &str) -> String {
    let mut cmd = "echo".to_owned();
    for comp in diff::slice(signs_prev, signs) {
        match comp {
            diff::Result::Left(sign) => {
                cmd += &get_command_delete_sign(sign, filename);
            }
            diff::Result::Right(sign) => {
                cmd += &get_command_add_sign(sign, filename);
            }
            diff::Result::Both(_, _) => (),
        }
    }

    cmd
}

#[test]
fn test_get_command_update_signs() {}

pub trait Merge {
    fn merge(&mut self, other: Self) -> ();
}

impl<K, V> Merge for HashMap<K, V>
where
    K: std::cmp::Eq + std::hash::Hash,
{
    fn merge(&mut self, other: Self) -> () {
        for (k, v) in other {
            self.insert(k, v);
        }
    }
}

pub trait Combine {
    fn combine(self, other: Self) -> Self
    where
        Self: Sized;
}

impl Combine for Value {
    fn combine(self, other: Self) -> Self {
        match (self, other) {
            (this, Value::Null) => this,
            (Value::Object(this), Value::Object(other)) => {
                let mut map = serde_json::map::Map::new();
                let mut keys: HashSet<String> = HashSet::new();
                for k in this.keys() {
                    keys.insert(k.clone());
                }
                for k in other.keys() {
                    keys.insert(k.clone());
                }
                for k in keys.drain() {
                    let v1 = this.get(&k).unwrap_or(&Value::Null).clone();
                    let v2 = other.get(&k).unwrap_or(&Value::Null).clone();
                    map.insert(k, v1.combine(v2));
                }
                Value::Object(map)
            }
            (_, other) => other,
        }
    }
}

pub fn vim_cmd_args_to_value(args: &[String]) -> Result<Value> {
    let mut map = serde_json::map::Map::new();
    for arg in args {
        let mut tokens: Vec<_> = arg.splitn(2, '=').collect();
        tokens.reverse();
        let key = tokens
            .pop()
            .ok_or_else(|| format_err!("Failed to parse command arguments."))?;
        let value = tokens
            .pop()
            .ok_or_else(|| format_err!("Failed to parse command arguments."))?;
        let value = Value::String(value.to_owned());
        map.insert(key.to_owned(), value);
    }

    Ok(Value::Object(map))
}

#[test]
fn test_vim_cmd_args_to_value() {
    let cmdargs = ["rootPath=/tmp".to_owned()];
    assert_eq!(
        vim_cmd_args_to_value(&cmdargs).unwrap(),
        json!({
        "rootPath": "/tmp"
    })
    );
}

pub fn diff_value<'a>(v1: &'a Value, v2: &'a Value, path: &str) -> HashMap<String, (Value, Value)> {
    let mut diffs = HashMap::new();
    match (v1, v2) {
        (&Value::Null, &Value::Null)
        | (&Value::Bool(_), &Value::Bool(_))
        | (&Value::Number(_), &Value::Number(_))
        | (&Value::String(_), &Value::String(_))
        | (&Value::Array(_), &Value::Array(_)) => if v1 != v2 {
            diffs.insert(path.to_owned(), (v1.clone(), v2.clone()));
        },
        (&Value::Object(ref map1), &Value::Object(ref map2)) => {
            let keys1: HashSet<&String> = map1.keys().collect();
            let keys2: HashSet<&String> = map2.keys().collect();
            for k in keys1.union(&keys2) {
                let mut next_path = String::from(path);
                next_path += ".";
                next_path += k;
                let next_diffs = diff_value(
                    map1.get(*k).unwrap_or(&Value::Null),
                    map2.get(*k).unwrap_or(&Value::Null),
                    &next_path,
                );
                diffs.merge(next_diffs);
            }
        }
        _ => {
            diffs.insert(path.to_owned(), (v1.clone(), v2.clone()));
        }
    }

    diffs
}

#[test]
fn test_diff_value() {
    assert_eq!(diff_value(&json!({}), &json!({}), "state",), hashmap!());
    assert_eq!(
        diff_value(
            &json!({
                "line": 1,
            }),
            &json!({
                "line": 3,
            }),
            "state"
        ),
        hashmap!{
            "state.line".to_owned() => (json!(1), json!(3)),
        }
    );
}
<|endoftext|>


<commit_before>use itertools::Itertools;
use std::collections::{HashMap, HashSet};
use std::fmt;
use std::mem;
use rand::random;

type Point = (isize, isize);

#[derive(Debug, Clone)]
pub struct World {
    width: isize,
    height: isize,
    generation: HashSet<Point>,
    neighbours: HashMap<Point, usize>,
    age: usize,
}

impl World {
    pub fn new(width: isize, height: isize)  -> World {
        World {
            width: width,
            height: height,
            age: 0,
            generation: HashSet::new(),
            neighbours: HashMap::with_capacity(((width * height) as usize ) * mem::size_of::<usize>())
        }
    }

    pub fn seed(mut self) -> World {
        self.generation = (0..self.width).cartesian_product(0..self.height)
                                         .filter(|_| random())
                                         .collect::<HashSet<Point>>();
        self.calculate_neighbours();
        self
    }

    pub fn evolve(&mut self) -> &World {
        self.generation = self.neighbours.iter()
                              .filter(|&(n, c)| self.decide_fate(n, *c))
                              .map(|(n, _)| *n)
                              .collect::<HashSet<Point>>();
        self.calculate_neighbours();
        self.age += 1;
        self
    }

    fn calculate_neighbours(&mut self) {
        self.neighbours.clear();
        for &(x, y) in self.generation.iter() {
            (-1..2)
            .cartesian_product(-1..2)
            .filter(|&(dx, dy)| dx != 0 || dy != 0)
            .map(|(dx, dy)| (dx + x, dy + y))
            .fold(&mut self.neighbours, |acc, point| {
                *acc.entry(point).or_insert(0) += 1;
                acc
            });
        };
    }

    fn decide_fate(&self, p: &Point, c: usize) -> bool {
        if self.generation.contains(p) {
            c == 3 || c == 2
        } else {
            c == 3
        }
    }
}

impl fmt::Display for World {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut buf = String::with_capacity(((self.width + 2) * (self.height + 2) + 50) as usize);
        for x in 0..self.width + 2 {
            buf.push(if x == 0 { '┌' } else if x == self.width + 1 { '┐' } else { '─' });
        }
        buf.push('\n');
        for y in 0..self.height {
            buf.push('│');
            for x in 0..self.width {
                buf.push(if self.generation.contains(&(x, y)) { '*' } else { ' ' });
            }
            buf.push('|');
            if y == 0 {
                buf.push_str(&format!(" cells: {}", self.generation.len()));
            }
            if y == 1 {
                buf.push_str(&format!(" age: {}", self.age));
            }
            buf.push('\n');
        }
        for x in 0..self.width + 2 {
            buf.push(if x == 0 { '└' } else if x == self.width + 1 { '┘' } else { '─' });
        }
        write!(f, "{}", buf)
    }
}
<commit_msg>Remove preallocation of neighbours for new World<commit_after>use itertools::Itertools;
use std::collections::{HashMap, HashSet};
use std::fmt;
use rand::random;

type Point = (isize, isize);

#[derive(Debug, Clone)]
pub struct World {
    width: isize,
    height: isize,
    generation: HashSet<Point>,
    neighbours: HashMap<Point, usize>,
    age: usize,
}

impl World {
    pub fn new(width: isize, height: isize)  -> World {
        World { width: width, height: height, age: 0,
                generation: HashSet::new(), neighbours: HashMap::new(), }
    }

    pub fn seed(mut self) -> World {
        self.generation = (0..self.width).cartesian_product(0..self.height)
                                         .filter(|_| random())
                                         .collect::<HashSet<Point>>();
        self.calculate_neighbours();
        self
    }

    pub fn evolve(&mut self) -> &World {
        self.generation = self.neighbours.iter()
                              .filter(|&(n, c)| self.decide_fate(n, *c))
                              .map(|(n, _)| *n)
                              .collect::<HashSet<Point>>();
        self.calculate_neighbours();
        self.age += 1;
        self
    }

    fn calculate_neighbours(&mut self) {
        self.neighbours.clear();
        for &(x, y) in self.generation.iter() {
            (-1..2)
            .cartesian_product(-1..2)
            .filter(|&(dx, dy)| dx != 0 || dy != 0)
            .map(|(dx, dy)| (dx + x, dy + y))
            .fold(&mut self.neighbours, |acc, point| {
                *acc.entry(point).or_insert(0) += 1;
                acc
            });
        };
    }

    fn decide_fate(&self, p: &Point, c: usize) -> bool {
        if self.generation.contains(p) {
            c == 3 || c == 2
        } else {
            c == 3
        }
    }
}

impl fmt::Display for World {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut buf = String::with_capacity(((self.width + 2) * (self.height + 2) + 50) as usize);
        for x in 0..self.width + 2 {
            buf.push(if x == 0 { '┌' } else if x == self.width + 1 { '┐' } else { '─' });
        }
        buf.push('\n');
        for y in 0..self.height {
            buf.push('│');
            for x in 0..self.width {
                buf.push(if self.generation.contains(&(x, y)) { '*' } else { ' ' });
            }
            buf.push('|');
            if y == 0 {
                buf.push_str(&format!(" cells: {}", self.generation.len()));
            }
            if y == 1 {
                buf.push_str(&format!(" age: {}", self.age));
            }
            buf.push('\n');
        }
        for x in 0..self.width + 2 {
            buf.push(if x == 0 { '└' } else if x == self.width + 1 { '┘' } else { '─' });
        }
        write!(f, "{}", buf)
    }
}
<|endoftext|>


<commit_before>/// Check if needed fields are still public.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

extern crate mp4parse as mp4;

use std::io::{Cursor, Read};
use std::fs::File;

static MINI_MP4: &'static str = "tests/minimal.mp4";
static AUDIO_EME_MP4: &'static str = "tests/bipbop-cenc-audioinit.mp4";
static VIDEO_EME_MP4: &'static str = "tests/bipbop_480wp_1001kbps-cenc-video-key1-init.mp4";

// Taken from https://github.com/GuillaumeGomez/audio-video-metadata/blob/9dff40f565af71d5502e03a2e78ae63df95cfd40/src/metadata.rs#L53
#[test]
fn public_api() {
    let mut fd = File::open(MINI_MP4).expect("Unknown file");
    let mut buf = Vec::new();
    fd.read_to_end(&mut buf).expect("File error");

    let mut c = Cursor::new(&buf);
    let mut context = mp4::MediaContext::new();
    mp4::read_mp4(&mut c, &mut context).expect("read_mp4 failed");
    assert_eq!(context.timescale, Some(mp4::MediaTimeScale(1000)));
    for track in context.tracks {
        match track.data {
            Some(mp4::SampleEntry::Video(v)) => {
                // track part
                assert_eq!(track.duration, Some(mp4::TrackScaledTime(512, 0)));
                assert_eq!(track.empty_duration, Some(mp4::MediaScaledTime(0)));
                assert_eq!(track.media_time, Some(mp4::TrackScaledTime(0, 0)));
                assert_eq!(track.timescale, Some(mp4::TrackTimeScale(12800, 0)));
                assert_eq!(v.width, 320);
                assert_eq!(v.height, 240);

                // track.tkhd part
                let tkhd = track.tkhd.unwrap();
                assert_eq!(tkhd.disabled, false);
                assert_eq!(tkhd.duration, 40);
                assert_eq!(tkhd.width, 20971520);
                assert_eq!(tkhd.height, 15728640);

                // track.data part
                assert_eq!(match v.codec_specific {
                    mp4::VideoCodecSpecific::AVCConfig(v) => {
                        assert!(v.len() > 0);
                        "AVC"
                    }
                    mp4::VideoCodecSpecific::VPxConfig(vpx) => {
                        // We don't enter in here, we just check if fields are public.
                        assert!(vpx.bit_depth > 0);
                        assert!(vpx.color_space > 0);
                        assert!(vpx.chroma_subsampling > 0);
                        assert!(vpx.codec_init.len() > 0);
                        "VPx"
                    }
                }, "AVC");
            }
            Some(mp4::SampleEntry::Audio(a)) => {
                // track part
                assert_eq!(track.duration, Some(mp4::TrackScaledTime(2944, 1)));
                assert_eq!(track.empty_duration, Some(mp4::MediaScaledTime(0)));
                assert_eq!(track.media_time, Some(mp4::TrackScaledTime(1024, 1)));
                assert_eq!(track.timescale, Some(mp4::TrackTimeScale(48000, 1)));

                // track.tkhd part
                let tkhd = track.tkhd.unwrap();
                assert_eq!(tkhd.disabled, false);
                assert_eq!(tkhd.duration, 62);
                assert_eq!(tkhd.width, 0);
                assert_eq!(tkhd.height, 0);

                // track.data part
                assert_eq!(match a.codec_specific {
                    mp4::AudioCodecSpecific::ES_Descriptor(esds) => {
                        assert_eq!(esds.audio_codec, mp4::CodecType::AAC);
                        assert_eq!(esds.audio_sample_rate.unwrap(), 48000);
                        assert_eq!(esds.audio_object_type.unwrap(), 2);
                        "ES"
                    }
                    mp4::AudioCodecSpecific::FLACSpecificBox(flac) => {
                        // STREAMINFO block must be present and first.
                        assert!(flac.blocks.len() > 0);
                        assert_eq!(flac.blocks[0].block_type, 0);
                        assert_eq!(flac.blocks[0].data.len(), 34);
                        "FLAC"
                    }
                    mp4::AudioCodecSpecific::OpusSpecificBox(opus) => {
                        // We don't enter in here, we just check if fields are public.
                        assert!(opus.version > 0);
                        "Opus"
                    }
                    mp4::AudioCodecSpecific::MP3 => {
                        "MP3"
                    }
                }, "ES");
                assert!(a.samplesize > 0);
                assert!(a.samplerate > 0);
            }
            Some(mp4::SampleEntry::Unknown) | None => {}
        }
    }
}

#[test]
fn public_audio_tenc() {
    let kid =
        vec![0x7e, 0x57, 0x1d, 0x04, 0x7e, 0x57, 0x1d, 0x04,
             0x7e, 0x57, 0x1d, 0x04, 0x7e, 0x57, 0x1d, 0x04];

    let mut fd = File::open(AUDIO_EME_MP4).expect("Unknown file");
    let mut buf = Vec::new();
    fd.read_to_end(&mut buf).expect("File error");

    let mut c = Cursor::new(&buf);
    let mut context = mp4::MediaContext::new();
    mp4::read_mp4(&mut c, &mut context).expect("read_mp4 failed");
    for track in context.tracks {
        assert_eq!(track.codec_type, mp4::CodecType::EncryptedAudio);
        match track.data {
            Some(mp4::SampleEntry::Audio(a)) => {
                match a.protection_info.iter().find(|sinf| sinf.tenc.is_some()) {
                    Some(ref p) => {
                        assert_eq!(p.code_name, "mp4a");
                        if let Some(ref tenc) = p.tenc {
                            assert!(tenc.is_encrypted > 0);
                            assert!(tenc.iv_size ==  16);
                            assert!(tenc.kid == kid);
                        } else {
                            assert!(false, "Invalid test condition");
                        }
                    },
                    _=> {
                        assert!(false, "Invalid test condition");
                    },
                }
            },
            _ => {
                assert!(false, "Invalid test condition");
            }
        }
    }
}

#[test]
fn public_video_cenc() {
    let system_id =
        vec![0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02,
             0xac, 0xe3, 0x3c, 0x1e, 0x52, 0xe2, 0xfb, 0x4b];

    let kid =
        vec![0x7e, 0x57, 0x1d, 0x03, 0x7e, 0x57, 0x1d, 0x03,
             0x7e, 0x57, 0x1d, 0x03, 0x7e, 0x57, 0x1d, 0x11];

    let pssh_box =
        vec![0x00, 0x00, 0x00, 0x34, 0x70, 0x73, 0x73, 0x68,
             0x01, 0x00, 0x00, 0x00, 0x10, 0x77, 0xef, 0xec,
             0xc0, 0xb2, 0x4d, 0x02, 0xac, 0xe3, 0x3c, 0x1e,
             0x52, 0xe2, 0xfb, 0x4b, 0x00, 0x00, 0x00, 0x01,
             0x7e, 0x57, 0x1d, 0x03, 0x7e, 0x57, 0x1d, 0x03,
             0x7e, 0x57, 0x1d, 0x03, 0x7e, 0x57, 0x1d, 0x11,
             0x00, 0x00, 0x00, 0x00];

    let mut fd = File::open(VIDEO_EME_MP4).expect("Unknown file");
    let mut buf = Vec::new();
    fd.read_to_end(&mut buf).expect("File error");

    let mut c = Cursor::new(&buf);
    let mut context = mp4::MediaContext::new();
    mp4::read_mp4(&mut c, &mut context).expect("read_mp4 failed");
    for track in context.tracks {
        assert_eq!(track.codec_type, mp4::CodecType::EncryptedVideo);
        match track.data {
            Some(mp4::SampleEntry::Video(v)) => {
                match v.protection_info.iter().find(|sinf| sinf.tenc.is_some()) {
                    Some(ref p) => {
                        assert_eq!(p.code_name, "avc1");
                        if let Some(ref tenc) = p.tenc {
                            assert!(tenc.is_encrypted > 0);
                            assert!(tenc.iv_size ==  16);
                            assert!(tenc.kid == kid);
                        } else {
                            assert!(false, "Invalid test condition");
                        }
                    },
                    _=> {
                        assert!(false, "Invalid test condition");
                    },
                }
            },
            _ => {
                assert!(false, "Invalid test condition");
            }
        }
    }

    for pssh in context.psshs {
        assert_eq!(pssh.system_id, system_id);
        for kid_id in pssh.kid {
            assert_eq!(kid_id, kid);
        }
        assert_eq!(pssh.data.len(), 0);
        assert_eq!(pssh.box_content, pssh_box);
    }
}
<commit_msg>public.rs: Use assert_eq! when possible.<commit_after>/// Check if needed fields are still public.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

extern crate mp4parse as mp4;

use std::io::{Cursor, Read};
use std::fs::File;

static MINI_MP4: &'static str = "tests/minimal.mp4";
static AUDIO_EME_MP4: &'static str = "tests/bipbop-cenc-audioinit.mp4";
static VIDEO_EME_MP4: &'static str = "tests/bipbop_480wp_1001kbps-cenc-video-key1-init.mp4";

// Taken from https://github.com/GuillaumeGomez/audio-video-metadata/blob/9dff40f565af71d5502e03a2e78ae63df95cfd40/src/metadata.rs#L53
#[test]
fn public_api() {
    let mut fd = File::open(MINI_MP4).expect("Unknown file");
    let mut buf = Vec::new();
    fd.read_to_end(&mut buf).expect("File error");

    let mut c = Cursor::new(&buf);
    let mut context = mp4::MediaContext::new();
    mp4::read_mp4(&mut c, &mut context).expect("read_mp4 failed");
    assert_eq!(context.timescale, Some(mp4::MediaTimeScale(1000)));
    for track in context.tracks {
        match track.data {
            Some(mp4::SampleEntry::Video(v)) => {
                // track part
                assert_eq!(track.duration, Some(mp4::TrackScaledTime(512, 0)));
                assert_eq!(track.empty_duration, Some(mp4::MediaScaledTime(0)));
                assert_eq!(track.media_time, Some(mp4::TrackScaledTime(0, 0)));
                assert_eq!(track.timescale, Some(mp4::TrackTimeScale(12800, 0)));
                assert_eq!(v.width, 320);
                assert_eq!(v.height, 240);

                // track.tkhd part
                let tkhd = track.tkhd.unwrap();
                assert_eq!(tkhd.disabled, false);
                assert_eq!(tkhd.duration, 40);
                assert_eq!(tkhd.width, 20971520);
                assert_eq!(tkhd.height, 15728640);

                // track.data part
                assert_eq!(match v.codec_specific {
                    mp4::VideoCodecSpecific::AVCConfig(v) => {
                        assert!(v.len() > 0);
                        "AVC"
                    }
                    mp4::VideoCodecSpecific::VPxConfig(vpx) => {
                        // We don't enter in here, we just check if fields are public.
                        assert!(vpx.bit_depth > 0);
                        assert!(vpx.color_space > 0);
                        assert!(vpx.chroma_subsampling > 0);
                        assert!(vpx.codec_init.len() > 0);
                        "VPx"
                    }
                }, "AVC");
            }
            Some(mp4::SampleEntry::Audio(a)) => {
                // track part
                assert_eq!(track.duration, Some(mp4::TrackScaledTime(2944, 1)));
                assert_eq!(track.empty_duration, Some(mp4::MediaScaledTime(0)));
                assert_eq!(track.media_time, Some(mp4::TrackScaledTime(1024, 1)));
                assert_eq!(track.timescale, Some(mp4::TrackTimeScale(48000, 1)));

                // track.tkhd part
                let tkhd = track.tkhd.unwrap();
                assert_eq!(tkhd.disabled, false);
                assert_eq!(tkhd.duration, 62);
                assert_eq!(tkhd.width, 0);
                assert_eq!(tkhd.height, 0);

                // track.data part
                assert_eq!(match a.codec_specific {
                    mp4::AudioCodecSpecific::ES_Descriptor(esds) => {
                        assert_eq!(esds.audio_codec, mp4::CodecType::AAC);
                        assert_eq!(esds.audio_sample_rate.unwrap(), 48000);
                        assert_eq!(esds.audio_object_type.unwrap(), 2);
                        "ES"
                    }
                    mp4::AudioCodecSpecific::FLACSpecificBox(flac) => {
                        // STREAMINFO block must be present and first.
                        assert!(flac.blocks.len() > 0);
                        assert_eq!(flac.blocks[0].block_type, 0);
                        assert_eq!(flac.blocks[0].data.len(), 34);
                        "FLAC"
                    }
                    mp4::AudioCodecSpecific::OpusSpecificBox(opus) => {
                        // We don't enter in here, we just check if fields are public.
                        assert!(opus.version > 0);
                        "Opus"
                    }
                    mp4::AudioCodecSpecific::MP3 => {
                        "MP3"
                    }
                }, "ES");
                assert!(a.samplesize > 0);
                assert!(a.samplerate > 0);
            }
            Some(mp4::SampleEntry::Unknown) | None => {}
        }
    }
}

#[test]
fn public_audio_tenc() {
    let kid =
        vec![0x7e, 0x57, 0x1d, 0x04, 0x7e, 0x57, 0x1d, 0x04,
             0x7e, 0x57, 0x1d, 0x04, 0x7e, 0x57, 0x1d, 0x04];

    let mut fd = File::open(AUDIO_EME_MP4).expect("Unknown file");
    let mut buf = Vec::new();
    fd.read_to_end(&mut buf).expect("File error");

    let mut c = Cursor::new(&buf);
    let mut context = mp4::MediaContext::new();
    mp4::read_mp4(&mut c, &mut context).expect("read_mp4 failed");
    for track in context.tracks {
        assert_eq!(track.codec_type, mp4::CodecType::EncryptedAudio);
        match track.data {
            Some(mp4::SampleEntry::Audio(a)) => {
                match a.protection_info.iter().find(|sinf| sinf.tenc.is_some()) {
                    Some(ref p) => {
                        assert_eq!(p.code_name, "mp4a");
                        if let Some(ref tenc) = p.tenc {
                            assert!(tenc.is_encrypted > 0);
                            assert_eq!(tenc.iv_size, 16);
                            assert_eq!(tenc.kid, kid);
                        } else {
                            assert!(false, "Invalid test condition");
                        }
                    },
                    _=> {
                        assert!(false, "Invalid test condition");
                    },
                }
            },
            _ => {
                assert!(false, "Invalid test condition");
            }
        }
    }
}

#[test]
fn public_video_cenc() {
    let system_id =
        vec![0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02,
             0xac, 0xe3, 0x3c, 0x1e, 0x52, 0xe2, 0xfb, 0x4b];

    let kid =
        vec![0x7e, 0x57, 0x1d, 0x03, 0x7e, 0x57, 0x1d, 0x03,
             0x7e, 0x57, 0x1d, 0x03, 0x7e, 0x57, 0x1d, 0x11];

    let pssh_box =
        vec![0x00, 0x00, 0x00, 0x34, 0x70, 0x73, 0x73, 0x68,
             0x01, 0x00, 0x00, 0x00, 0x10, 0x77, 0xef, 0xec,
             0xc0, 0xb2, 0x4d, 0x02, 0xac, 0xe3, 0x3c, 0x1e,
             0x52, 0xe2, 0xfb, 0x4b, 0x00, 0x00, 0x00, 0x01,
             0x7e, 0x57, 0x1d, 0x03, 0x7e, 0x57, 0x1d, 0x03,
             0x7e, 0x57, 0x1d, 0x03, 0x7e, 0x57, 0x1d, 0x11,
             0x00, 0x00, 0x00, 0x00];

    let mut fd = File::open(VIDEO_EME_MP4).expect("Unknown file");
    let mut buf = Vec::new();
    fd.read_to_end(&mut buf).expect("File error");

    let mut c = Cursor::new(&buf);
    let mut context = mp4::MediaContext::new();
    mp4::read_mp4(&mut c, &mut context).expect("read_mp4 failed");
    for track in context.tracks {
        assert_eq!(track.codec_type, mp4::CodecType::EncryptedVideo);
        match track.data {
            Some(mp4::SampleEntry::Video(v)) => {
                match v.protection_info.iter().find(|sinf| sinf.tenc.is_some()) {
                    Some(ref p) => {
                        assert_eq!(p.code_name, "avc1");
                        if let Some(ref tenc) = p.tenc {
                            assert!(tenc.is_encrypted > 0);
                            assert_eq!(tenc.iv_size, 16);
                            assert_eq!(tenc.kid, kid);
                        } else {
                            assert!(false, "Invalid test condition");
                        }
                    },
                    _=> {
                        assert!(false, "Invalid test condition");
                    },
                }
            },
            _ => {
                assert!(false, "Invalid test condition");
            }
        }
    }

    for pssh in context.psshs {
        assert_eq!(pssh.system_id, system_id);
        for kid_id in pssh.kid {
            assert_eq!(kid_id, kid);
        }
        assert_eq!(pssh.data.len(), 0);
        assert_eq!(pssh.box_content, pssh_box);
    }
}
<|endoftext|>


<commit_before>use mio::{Events, Poll, PollOpt, Ready, Registration, SetReadiness, Token};
use mio::event::Evented;
use std::time::Duration;

#[test]
fn smoke() {
    let poll = Poll::new().unwrap();
    let mut events = Events::with_capacity(128);

    let (r, set) = Registration::new2();
    r.register(&poll, Token(0), Ready::readable(), PollOpt::edge()).unwrap();

    let n = poll.poll(&mut events, Some(Duration::from_millis(0))).unwrap();
    assert_eq!(n, 0);

    set.set_readiness(Ready::readable()).unwrap();

    let n = poll.poll(&mut events, Some(Duration::from_millis(0))).unwrap();
    assert_eq!(n, 1);

    assert_eq!(events.get(0).unwrap().token(), Token(0));
}

#[test]
fn set_readiness_before_register() {
    use std::sync::{Arc, Barrier};
    use std::thread;

    let poll = Poll::new().unwrap();
    let mut events = Events::with_capacity(128);

    for _ in 0..5_000 {
        let (r, set) = Registration::new2();

        let b1 = Arc::new(Barrier::new(2));
        let b2 = b1.clone();

        let th = thread::spawn(move || {
            b2.wait();
            set.set_readiness(Ready::readable()).unwrap();
        });

        b1.wait();

        poll.register(&r, Token(123), Ready::readable(), PollOpt::edge()).unwrap();

        loop {
            let n = poll.poll(&mut events, None).unwrap();

            if n == 0 {
                continue;
            }

            assert_eq!(n, 1);
            assert_eq!(events.get(0).unwrap().token(), Token(123));
            break;
        }

        th.join().unwrap();
    }
}

#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
mod stress {
    use mio::{Events, Poll, PollOpt, Ready, Registration, SetReadiness, Token};
    use mio::event::Evented;
    use std::time::Duration;

    #[test]
    fn single_threaded_poll() {
        use std::sync::Arc;
        use std::sync::atomic::AtomicUsize;
        use std::sync::atomic::Ordering::{Acquire, Release};
        use std::thread;

        const NUM_ATTEMPTS: usize = 30;
        const NUM_ITERS: usize = 500;
        const NUM_THREADS: usize = 4;
        const NUM_REGISTRATIONS: usize = 128;

        for _ in 0..NUM_ATTEMPTS {
            let poll = Poll::new().unwrap();
            let mut events = Events::with_capacity(128);

            let registrations: Vec<_> = (0..NUM_REGISTRATIONS).map(|i| {
                let (r, s) = Registration::new2();
                r.register(&poll, Token(i), Ready::readable(), PollOpt::edge()).unwrap();
                (r, s)
            }).collect();

            let mut ready: Vec<_> = (0..NUM_REGISTRATIONS).map(|_| Ready::empty()).collect();

            let remaining = Arc::new(AtomicUsize::new(NUM_THREADS));

            for _ in 0..NUM_THREADS {
                let remaining = remaining.clone();

                let set_readiness: Vec<SetReadiness> =
                    registrations.iter().map(|r| r.1.clone()).collect();

                thread::spawn(move || {
                    for _ in 0..NUM_ITERS {
                        for i in 0..NUM_REGISTRATIONS {
                            set_readiness[i].set_readiness(Ready::readable()).unwrap();
                            set_readiness[i].set_readiness(Ready::empty()).unwrap();
                            set_readiness[i].set_readiness(Ready::writable()).unwrap();
                            set_readiness[i].set_readiness(Ready::readable() | Ready::writable()).unwrap();
                            set_readiness[i].set_readiness(Ready::empty()).unwrap();
                        }
                    }

                    for i in 0..NUM_REGISTRATIONS {
                        set_readiness[i].set_readiness(Ready::readable()).unwrap();
                    }

                    remaining.fetch_sub(1, Release);
                });
            }

            while remaining.load(Acquire) > 0 {
                // Set interest
                for (i, &(ref r, _)) in registrations.iter().enumerate() {
                    r.reregister(&poll, Token(i), Ready::writable(), PollOpt::edge()).unwrap();
                }

                poll.poll(&mut events, Some(Duration::from_millis(0))).unwrap();

                for event in &events {
                    ready[event.token().0] = event.readiness();
                }

                // Update registration
                // Set interest
                for (i, &(ref r, _)) in registrations.iter().enumerate() {
                    r.reregister(&poll, Token(i), Ready::readable(), PollOpt::edge()).unwrap();
                }
            }

            // One final poll
            poll.poll(&mut events, Some(Duration::from_millis(0))).unwrap();

            for event in &events {
                ready[event.token().0] = event.readiness();
            }

            // Everything should be flagged as readable
            for ready in ready {
                assert_eq!(ready, Ready::readable());
            }
        }
    }

    #[test]
    fn multi_threaded_poll() {
        use std::sync::{Arc, Barrier};
        use std::sync::atomic::{AtomicUsize};
        use std::sync::atomic::Ordering::{Relaxed, SeqCst};
        use std::thread;

        const ENTRIES: usize = 10_000;
        const PER_ENTRY: usize = 16;
        const THREADS: usize = 4;
        const NUM: usize = ENTRIES * PER_ENTRY;

        struct Entry {
            #[allow(dead_code)]
            registration: Registration,
            set_readiness: SetReadiness,
            num: AtomicUsize,
        }

        impl Entry {
            fn fire(&self) {
                self.set_readiness.set_readiness(Ready::readable()).unwrap();
            }
        }

        let poll = Arc::new(Poll::new().unwrap());
        let mut entries = vec![];

        // Create entries
        for i in 0..ENTRIES {
            let (registration, set_readiness) = Registration::new2();
            registration.register(&poll, Token(i), Ready::readable(), PollOpt::edge()).unwrap();

            entries.push(Entry {
                registration: registration,
                set_readiness: set_readiness,
                num: AtomicUsize::new(0),
            });
        }

        let total = Arc::new(AtomicUsize::new(0));
        let entries = Arc::new(entries);
        let barrier = Arc::new(Barrier::new(THREADS));

        let mut threads = vec![];

        for th in 0..THREADS {
            let poll = poll.clone();
            let total = total.clone();
            let entries = entries.clone();
            let barrier = barrier.clone();

            threads.push(thread::spawn(move || {
                let mut events = Events::with_capacity(128);

                barrier.wait();

                // Prime all the registrations
                let mut i = th;
                while i < ENTRIES {
                    entries[i].fire();
                    i += THREADS;
                }

                let mut n = 0;

                while total.load(SeqCst) < NUM {
                    // A poll timeout is necessary here because there may be more
                    // than one threads blocked in `poll` when the final wakeup
                    // notification arrives (and only notifies one thread).
                    n += poll.poll(&mut events, Some(Duration::from_millis(100))).unwrap();

                    let mut num_this_tick = 0;

                    for event in &events {
                        let e = &entries[event.token().0];

                        let mut num = e.num.load(Relaxed);

                        loop {
                            if num < PER_ENTRY {
                                let actual = e.num.compare_and_swap(num, num + 1, Relaxed);

                                if actual == num {
                                    num_this_tick += 1;
                                    e.fire();
                                    break;
                                }

                                num = actual;
                            } else {
                                break;
                            }
                        }
                    }

                    total.fetch_add(num_this_tick, SeqCst);
                }

                n
            }));
        }

        let per_thread: Vec<_> = threads.into_iter()
            .map(|th| th.join().unwrap())
            .collect();

        for entry in entries.iter() {
            assert_eq!(PER_ENTRY, entry.num.load(Relaxed));
        }

        for th in per_thread {
            // Kind of annoying that we can't really test anything better than this,
            // but CI tends to be very non deterministic when it comes to multi
            // threading.
            assert!(th > 0, "actual={:?}", th);
        }
    }

    #[test]
    fn with_small_events_collection() {
        const N: usize = 8;
        const ITER: usize = 1_000;

        use std::sync::{Arc, Barrier};
        use std::sync::atomic::AtomicBool;
        use std::sync::atomic::Ordering::{Acquire, Release};
        use std::thread;

        let poll = Poll::new().unwrap();
        let mut registrations = vec![];

        let barrier = Arc::new(Barrier::new(N + 1));
        let done = Arc::new(AtomicBool::new(false));

        for i in 0..N {
            let (registration, set_readiness) = Registration::new2();
            poll.register(&registration, Token(i), Ready::readable(), PollOpt::edge()).unwrap();

            registrations.push(registration);

            let barrier = barrier.clone();
            let done = done.clone();

            thread::spawn(move || {
                barrier.wait();

                while !done.load(Acquire) {
                    set_readiness.set_readiness(Ready::readable()).unwrap();
                }

                // Set one last time
                set_readiness.set_readiness(Ready::readable()).unwrap();
            });
        }

        let mut events = Events::with_capacity(4);

        barrier.wait();

        for _ in 0..ITER {
            poll.poll(&mut events, None).unwrap();
        }

        done.store(true, Release);

        let mut final_ready = vec![false; N];

        for _ in 0..5 {
            poll.poll(&mut events, None).unwrap();

            for event in &events {
                final_ready[event.token().0] = true;
            }

            if final_ready.iter().all(|v| *v) {
                return;
            }

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

        panic!("dead lock?");
    }
}

#[test]
fn drop_registration_from_non_main_thread() {
    use std::thread;
    use std::sync::mpsc::channel;

    const THREADS: usize = 8;
    const ITERS: usize = 50_000;

    let mut poll = Poll::new().unwrap();
    let mut events = Events::with_capacity(1024);
    let mut senders = Vec::with_capacity(THREADS);
    let mut token_index = 0;

    // spawn threads, which will send messages to single receiver
    for _ in 0..THREADS {
        let (tx, rx) = channel::<(Registration, SetReadiness)>();
        senders.push(tx);

        thread::spawn(move || {
            for (registration, set_readiness) in rx {
                let _ = set_readiness.set_readiness(Ready::readable());
                drop(registration);
                drop(set_readiness);
            }
        });
    }

    let mut index: usize = 0;
    for _ in 0..ITERS {
        let (registration, set_readiness) = Registration::new2();
        registration.register(&mut poll, Token(token_index), Ready::readable(), PollOpt::edge()).unwrap();
        let _ = senders[index].send((registration, set_readiness));

        token_index += 1;
        index += 1;
        if index == THREADS {
            index = 0;

            let (registration, set_readiness) = Registration::new2();
            registration.register(&mut poll, Token(token_index), Ready::readable(), PollOpt::edge()).unwrap();
            let _ = set_readiness.set_readiness(Ready::readable());
            drop(registration);
            drop(set_readiness);
            token_index += 1;

            thread::park_timeout(Duration::from_millis(0));
            let _ = poll.poll(&mut events, None).unwrap();
        }
    }
}
<commit_msg>fix syncro in test set_readiness_before_register (#784)<commit_after>use mio::{Events, Poll, PollOpt, Ready, Registration, SetReadiness, Token};
use mio::event::Evented;
use std::time::Duration;

#[test]
fn smoke() {
    let poll = Poll::new().unwrap();
    let mut events = Events::with_capacity(128);

    let (r, set) = Registration::new2();
    r.register(&poll, Token(0), Ready::readable(), PollOpt::edge()).unwrap();

    let n = poll.poll(&mut events, Some(Duration::from_millis(0))).unwrap();
    assert_eq!(n, 0);

    set.set_readiness(Ready::readable()).unwrap();

    let n = poll.poll(&mut events, Some(Duration::from_millis(0))).unwrap();
    assert_eq!(n, 1);

    assert_eq!(events.get(0).unwrap().token(), Token(0));
}

#[test]
fn set_readiness_before_register() {
    use std::sync::{Arc, Barrier};
    use std::thread;

    let poll = Poll::new().unwrap();
    let mut events = Events::with_capacity(128);

    for _ in 0..5_000 {
        let (r, set) = Registration::new2();

        let b1 = Arc::new(Barrier::new(2));
        let b2 = b1.clone();

        let th = thread::spawn(move || {
            // set readiness before register
            set.set_readiness(Ready::readable()).unwrap();

            // run into barrier so both can pass
            b2.wait();
        });

        // wait for readiness
        b1.wait();

        // now register
        poll.register(&r, Token(123), Ready::readable(), PollOpt::edge()).unwrap();

        loop {
            let n = poll.poll(&mut events, None).unwrap();

            if n == 0 {
                continue;
            }

            assert_eq!(n, 1);
            assert_eq!(events.get(0).unwrap().token(), Token(123));
            break;
        }

        th.join().unwrap();
    }
}

#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
mod stress {
    use mio::{Events, Poll, PollOpt, Ready, Registration, SetReadiness, Token};
    use mio::event::Evented;
    use std::time::Duration;

    #[test]
    fn single_threaded_poll() {
        use std::sync::Arc;
        use std::sync::atomic::AtomicUsize;
        use std::sync::atomic::Ordering::{Acquire, Release};
        use std::thread;

        const NUM_ATTEMPTS: usize = 30;
        const NUM_ITERS: usize = 500;
        const NUM_THREADS: usize = 4;
        const NUM_REGISTRATIONS: usize = 128;

        for _ in 0..NUM_ATTEMPTS {
            let poll = Poll::new().unwrap();
            let mut events = Events::with_capacity(128);

            let registrations: Vec<_> = (0..NUM_REGISTRATIONS).map(|i| {
                let (r, s) = Registration::new2();
                r.register(&poll, Token(i), Ready::readable(), PollOpt::edge()).unwrap();
                (r, s)
            }).collect();

            let mut ready: Vec<_> = (0..NUM_REGISTRATIONS).map(|_| Ready::empty()).collect();

            let remaining = Arc::new(AtomicUsize::new(NUM_THREADS));

            for _ in 0..NUM_THREADS {
                let remaining = remaining.clone();

                let set_readiness: Vec<SetReadiness> =
                    registrations.iter().map(|r| r.1.clone()).collect();

                thread::spawn(move || {
                    for _ in 0..NUM_ITERS {
                        for i in 0..NUM_REGISTRATIONS {
                            set_readiness[i].set_readiness(Ready::readable()).unwrap();
                            set_readiness[i].set_readiness(Ready::empty()).unwrap();
                            set_readiness[i].set_readiness(Ready::writable()).unwrap();
                            set_readiness[i].set_readiness(Ready::readable() | Ready::writable()).unwrap();
                            set_readiness[i].set_readiness(Ready::empty()).unwrap();
                        }
                    }

                    for i in 0..NUM_REGISTRATIONS {
                        set_readiness[i].set_readiness(Ready::readable()).unwrap();
                    }

                    remaining.fetch_sub(1, Release);
                });
            }

            while remaining.load(Acquire) > 0 {
                // Set interest
                for (i, &(ref r, _)) in registrations.iter().enumerate() {
                    r.reregister(&poll, Token(i), Ready::writable(), PollOpt::edge()).unwrap();
                }

                poll.poll(&mut events, Some(Duration::from_millis(0))).unwrap();

                for event in &events {
                    ready[event.token().0] = event.readiness();
                }

                // Update registration
                // Set interest
                for (i, &(ref r, _)) in registrations.iter().enumerate() {
                    r.reregister(&poll, Token(i), Ready::readable(), PollOpt::edge()).unwrap();
                }
            }

            // One final poll
            poll.poll(&mut events, Some(Duration::from_millis(0))).unwrap();

            for event in &events {
                ready[event.token().0] = event.readiness();
            }

            // Everything should be flagged as readable
            for ready in ready {
                assert_eq!(ready, Ready::readable());
            }
        }
    }

    #[test]
    fn multi_threaded_poll() {
        use std::sync::{Arc, Barrier};
        use std::sync::atomic::{AtomicUsize};
        use std::sync::atomic::Ordering::{Relaxed, SeqCst};
        use std::thread;

        const ENTRIES: usize = 10_000;
        const PER_ENTRY: usize = 16;
        const THREADS: usize = 4;
        const NUM: usize = ENTRIES * PER_ENTRY;

        struct Entry {
            #[allow(dead_code)]
            registration: Registration,
            set_readiness: SetReadiness,
            num: AtomicUsize,
        }

        impl Entry {
            fn fire(&self) {
                self.set_readiness.set_readiness(Ready::readable()).unwrap();
            }
        }

        let poll = Arc::new(Poll::new().unwrap());
        let mut entries = vec![];

        // Create entries
        for i in 0..ENTRIES {
            let (registration, set_readiness) = Registration::new2();
            registration.register(&poll, Token(i), Ready::readable(), PollOpt::edge()).unwrap();

            entries.push(Entry {
                registration: registration,
                set_readiness: set_readiness,
                num: AtomicUsize::new(0),
            });
        }

        let total = Arc::new(AtomicUsize::new(0));
        let entries = Arc::new(entries);
        let barrier = Arc::new(Barrier::new(THREADS));

        let mut threads = vec![];

        for th in 0..THREADS {
            let poll = poll.clone();
            let total = total.clone();
            let entries = entries.clone();
            let barrier = barrier.clone();

            threads.push(thread::spawn(move || {
                let mut events = Events::with_capacity(128);

                barrier.wait();

                // Prime all the registrations
                let mut i = th;
                while i < ENTRIES {
                    entries[i].fire();
                    i += THREADS;
                }

                let mut n = 0;

                while total.load(SeqCst) < NUM {
                    // A poll timeout is necessary here because there may be more
                    // than one threads blocked in `poll` when the final wakeup
                    // notification arrives (and only notifies one thread).
                    n += poll.poll(&mut events, Some(Duration::from_millis(100))).unwrap();

                    let mut num_this_tick = 0;

                    for event in &events {
                        let e = &entries[event.token().0];

                        let mut num = e.num.load(Relaxed);

                        loop {
                            if num < PER_ENTRY {
                                let actual = e.num.compare_and_swap(num, num + 1, Relaxed);

                                if actual == num {
                                    num_this_tick += 1;
                                    e.fire();
                                    break;
                                }

                                num = actual;
                            } else {
                                break;
                            }
                        }
                    }

                    total.fetch_add(num_this_tick, SeqCst);
                }

                n
            }));
        }

        let per_thread: Vec<_> = threads.into_iter()
            .map(|th| th.join().unwrap())
            .collect();

        for entry in entries.iter() {
            assert_eq!(PER_ENTRY, entry.num.load(Relaxed));
        }

        for th in per_thread {
            // Kind of annoying that we can't really test anything better than this,
            // but CI tends to be very non deterministic when it comes to multi
            // threading.
            assert!(th > 0, "actual={:?}", th);
        }
    }

    #[test]
    fn with_small_events_collection() {
        const N: usize = 8;
        const ITER: usize = 1_000;

        use std::sync::{Arc, Barrier};
        use std::sync::atomic::AtomicBool;
        use std::sync::atomic::Ordering::{Acquire, Release};
        use std::thread;

        let poll = Poll::new().unwrap();
        let mut registrations = vec![];

        let barrier = Arc::new(Barrier::new(N + 1));
        let done = Arc::new(AtomicBool::new(false));

        for i in 0..N {
            let (registration, set_readiness) = Registration::new2();
            poll.register(&registration, Token(i), Ready::readable(), PollOpt::edge()).unwrap();

            registrations.push(registration);

            let barrier = barrier.clone();
            let done = done.clone();

            thread::spawn(move || {
                barrier.wait();

                while !done.load(Acquire) {
                    set_readiness.set_readiness(Ready::readable()).unwrap();
                }

                // Set one last time
                set_readiness.set_readiness(Ready::readable()).unwrap();
            });
        }

        let mut events = Events::with_capacity(4);

        barrier.wait();

        for _ in 0..ITER {
            poll.poll(&mut events, None).unwrap();
        }

        done.store(true, Release);

        let mut final_ready = vec![false; N];

        for _ in 0..5 {
            poll.poll(&mut events, None).unwrap();

            for event in &events {
                final_ready[event.token().0] = true;
            }

            if final_ready.iter().all(|v| *v) {
                return;
            }

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

        panic!("dead lock?");
    }
}

#[test]
fn drop_registration_from_non_main_thread() {
    use std::thread;
    use std::sync::mpsc::channel;

    const THREADS: usize = 8;
    const ITERS: usize = 50_000;

    let mut poll = Poll::new().unwrap();
    let mut events = Events::with_capacity(1024);
    let mut senders = Vec::with_capacity(THREADS);
    let mut token_index = 0;

    // spawn threads, which will send messages to single receiver
    for _ in 0..THREADS {
        let (tx, rx) = channel::<(Registration, SetReadiness)>();
        senders.push(tx);

        thread::spawn(move || {
            for (registration, set_readiness) in rx {
                let _ = set_readiness.set_readiness(Ready::readable());
                drop(registration);
                drop(set_readiness);
            }
        });
    }

    let mut index: usize = 0;
    for _ in 0..ITERS {
        let (registration, set_readiness) = Registration::new2();
        registration.register(&mut poll, Token(token_index), Ready::readable(), PollOpt::edge()).unwrap();
        let _ = senders[index].send((registration, set_readiness));

        token_index += 1;
        index += 1;
        if index == THREADS {
            index = 0;

            let (registration, set_readiness) = Registration::new2();
            registration.register(&mut poll, Token(token_index), Ready::readable(), PollOpt::edge()).unwrap();
            let _ = set_readiness.set_readiness(Ready::readable());
            drop(registration);
            drop(set_readiness);
            token_index += 1;

            thread::park_timeout(Duration::from_millis(0));
            let _ = poll.poll(&mut events, None).unwrap();
        }
    }
}
<|endoftext|>