<commit_before>// TODO: create Cassandra types

/// Cassandra types

pub const LONG_STR_LEN: usize = 4;
pub const SHORT_LEN: usize = 2;
pub const INT_LEN: usize = 4;

use std::io::{Cursor, Read};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use super::{FromBytes, IntoBytes, FromCursor};

/// Converts u64 numerical value into array of n bytes
pub fn to_n_bytes(int: u64, n: usize) -> Vec<u8> {
    let mut bytes = vec![];
    bytes.write_uint::<BigEndian>(int, n).unwrap();
    return bytes;
}

pub fn i_to_n_bytes(int: i64, n: usize) -> Vec<u8> {
    let mut bytes = vec![];
    bytes.write_int::<BigEndian>(int, n).unwrap();
    return bytes;
}

/// Converts byte-array into u64
pub fn from_bytes(bytes: Vec<u8>) -> u64 {
    let mut c = Cursor::new(bytes.clone());
    return c.read_uint::<BigEndian>(bytes.len()).unwrap()
}

/// Converts number u64 into Cassandra's [short].
pub fn to_short(int: u64) -> Vec<u8> {
    return to_n_bytes(int, SHORT_LEN);
}

/// Convers integer into Cassandra's [int]
pub fn to_int(int: i64) -> Vec<u8> {
    return i_to_n_bytes(int, INT_LEN);
}

pub type CString = String;

// Implementation for Rust std types
// Use extended Rust string as Cassandra [string]
impl IntoBytes for CString {
    /// Converts into Cassandra byte representation of [string]
    fn into_cbytes(&self) -> Vec<u8> {
        let mut v: Vec<u8> = vec![];
        let l = self.len() as i64;
        v.extend_from_slice(to_int(l).as_slice());
        v.extend_from_slice(self.as_bytes());
        return v;
    }
}

impl FromBytes for CString {
    fn from_bytes(bytes: Vec<u8>) -> CString {
        let len: usize = from_bytes(bytes[..SHORT_LEN].to_vec()) as usize;
        return match String::from_utf8(bytes[(SHORT_LEN + 1)..len].to_vec()) {
            Ok(string) => string,
            Err(err) => {
                error!("Parsing string error {:?}", err);
                panic!("Parsing string error {:?}", err);
            }
        };
    }
}

impl FromCursor for CString {
    /// from_cursor gets Cursor who's position is set such that it should be a start of a [string].
    /// It reads required number of bytes and returns a String
    fn from_cursor(mut cursor: &mut Cursor<Vec<u8>>) -> CString {
        let mut len_bytes = [0; SHORT_LEN];
        if let Err(err) = cursor.read(&mut len_bytes) {
            error!("Read Cassandra bytes error: {}", err);
            panic!(err);
        }
        let len: u64 = from_bytes(len_bytes.to_vec());
        let body_bytes = cursor_next_value(&mut cursor, len);

        return String::from_bytes(body_bytes);
    }
}

pub type CStringList = Vec<CString>;

impl FromCursor for CStringList {
    fn from_cursor(mut cursor: &mut Cursor<Vec<u8>>) -> CStringList {
        let mut len_bytes = [0; SHORT_LEN];
        if let Err(err) = cursor.read(&mut len_bytes) {
            error!("Read Cassandra bytes error: {}", err);
            panic!(err);
        }
        let len: u64 = from_bytes(len_bytes.to_vec());

        // let list: CStringList = (0..len).map(|_| CString::from_cursor(&mut cursor)).collect();

        return (0..len).map(|_| CString::from_cursor(&mut cursor)).collect();
    }
}

/**/

pub type CBytes = Vec<u8>;

impl FromCursor for CBytes {
    /// from_cursor gets Cursor who's position is set such that it should be a start of a [bytes].
    /// It reads required number of bytes and returns a CBytes
    fn from_cursor(mut cursor: &mut Cursor<Vec<u8>>) -> CBytes {
        let mut len_bytes = [0; SHORT_LEN];
        if let Err(err) = cursor.read(&mut len_bytes) {
            error!("Read Cassandra bytes error: {}", err);
            panic!(err);
        }
        let len: u64 = from_bytes(len_bytes.to_vec());
        return cursor_next_value(&mut cursor, len);
    }
}

// Use extended Rust Vec<u8> as Cassandra [bytes]
impl IntoBytes for CBytes {
    fn into_cbytes(&self) -> Vec<u8> {
        let mut v: Vec<u8> = vec![];
        let l = self.len() as u64;
        v.extend_from_slice(to_short(l).as_slice());
        v.extend_from_slice(self.as_slice());
        return v;
    }
}

/// Cassandra int type.
pub type CInt = i32;

impl FromCursor for CInt {
    fn from_cursor(mut cursor: &mut Cursor<Vec<u8>>) -> CInt {
        let len_bytes = cursor_next_value(&mut cursor, SHORT_LEN as u64).to_vec();
        let len: u64 = from_bytes(len_bytes.to_vec());
        return from_bytes(cursor_next_value(&mut cursor, len)) as CInt;
    }
}

// Use extended Rust Vec<u8> as Cassandra [bytes]
impl FromBytes for Vec<u8> {
    fn from_bytes(bytes: Vec<u8>) -> Vec<u8> {
        let mut cursor = Cursor::new(bytes);
        let len_bytes = cursor_next_value(&mut cursor, SHORT_LEN as u64).to_vec();
        let len: u64 = from_bytes(len_bytes.to_vec());
        return cursor_next_value(&mut cursor, len).to_vec();
    }
}

pub fn cursor_next_value(cursor: &mut Cursor<Vec<u8>>, len: u64) -> Vec<u8> {
    let mut handle = cursor.take(len);
    let mut v = Vec::new();
    if let Err(err) = handle.read(&mut v) {
        error!("Read from cursor error: {}", err);
        panic!(err);
    }
    return v;
}
<commit_msg>Fix from_cursor parsers<commit_after>// TODO: create Cassandra types
/// Cassandra types

pub const LONG_STR_LEN: usize = 4;
pub const SHORT_LEN: usize = 2;
pub const INT_LEN: usize = 4;

use std::io::{Cursor, Read};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use super::{FromBytes, IntoBytes, FromCursor};

/// Converts u64 numerical value into array of n bytes
pub fn to_n_bytes(int: u64, n: usize) -> Vec<u8> {
    let mut bytes = vec![];
    bytes.write_uint::<BigEndian>(int, n).unwrap();
    return bytes;
}

pub fn i_to_n_bytes(int: i64, n: usize) -> Vec<u8> {
    let mut bytes = vec![];
    bytes.write_int::<BigEndian>(int, n).unwrap();
    return bytes;
}

/// Converts byte-array into u64
pub fn from_bytes(bytes: Vec<u8>) -> u64 {
    let mut c = Cursor::new(bytes.clone());
    return c.read_uint::<BigEndian>(bytes.len()).unwrap()
}

/// Converts number u64 into Cassandra's [short].
pub fn to_short(int: u64) -> Vec<u8> {
    return to_n_bytes(int, SHORT_LEN);
}

/// Convers integer into Cassandra's [int]
pub fn to_int(int: i64) -> Vec<u8> {
    return i_to_n_bytes(int, INT_LEN);
}

pub type CString = String;

// Implementation for Rust std types
// Use extended Rust string as Cassandra [string]
impl IntoBytes for CString {
    /// Converts into Cassandra byte representation of [string]
    fn into_cbytes(&self) -> Vec<u8> {
        let mut v: Vec<u8> = vec![];
        let l = self.len() as i64;
        v.extend_from_slice(to_int(l).as_slice());
        v.extend_from_slice(self.as_bytes());
        return v;
    }
}

impl FromBytes for CString {
    fn from_bytes(bytes: Vec<u8>) -> CString {
        let len: usize = from_bytes(bytes[..SHORT_LEN].to_vec()) as usize;
        return match String::from_utf8(bytes[(SHORT_LEN + 1)..len].to_vec()) {
            Ok(string) => string,
            Err(err) => {
                error!("Parsing string error {:?}", err);
                panic!("Parsing string error {:?}", err);
            }
        };
    }
}

impl FromCursor for CString {
    /// from_cursor gets Cursor who's position is set such that it should be a start of a [string].
    /// It reads required number of bytes and returns a String
    fn from_cursor(mut cursor: &mut Cursor<Vec<u8>>) -> CString {
        let len_bytes = cursor_next_value(&mut cursor, SHORT_LEN as u64);
        let len: u64 = from_bytes(len_bytes.to_vec());
        let body_bytes = cursor_next_value(&mut cursor, len);

        return String::from_utf8(body_bytes).unwrap();
    }
}

pub type CStringList = Vec<CString>;

impl FromCursor for CStringList {
    fn from_cursor(mut cursor: &mut Cursor<Vec<u8>>) -> CStringList {
        let mut len_bytes = [0; SHORT_LEN];
        if let Err(err) = cursor.read(&mut len_bytes) {
            error!("Read Cassandra bytes error: {}", err);
            panic!(err);
        }
        let len: u64 = from_bytes(len_bytes.to_vec());
        return (0..len).map(|_| CString::from_cursor(&mut cursor)).collect();
    }
}

/**/

pub type CBytes = Vec<u8>;

impl FromCursor for CBytes {
    /// from_cursor gets Cursor who's position is set such that it should be a start of a [bytes].
    /// It reads required number of bytes and returns a CBytes
    fn from_cursor(mut cursor: &mut Cursor<Vec<u8>>) -> CBytes {
        let mut len_bytes = [0; SHORT_LEN];
        if let Err(err) = cursor.read(&mut len_bytes) {
            error!("Read Cassandra bytes error: {}", err);
            panic!(err);
        }
        let len: u64 = from_bytes(len_bytes.to_vec());
        return cursor_next_value(&mut cursor, len);
    }
}

// Use extended Rust Vec<u8> as Cassandra [bytes]
impl IntoBytes for CBytes {
    fn into_cbytes(&self) -> Vec<u8> {
        let mut v: Vec<u8> = vec![];
        let l = self.len() as u64;
        v.extend_from_slice(to_short(l).as_slice());
        v.extend_from_slice(self.as_slice());
        return v;
    }
}

/// Cassandra int type.
pub type CInt = i32;

impl FromCursor for CInt {
    fn from_cursor(mut cursor: &mut Cursor<Vec<u8>>) -> CInt {
        let bytes = cursor_next_value(&mut cursor, INT_LEN as u64);
        return from_bytes(bytes) as CInt;
    }
}

// Use extended Rust Vec<u8> as Cassandra [bytes]
impl FromBytes for Vec<u8> {
    fn from_bytes(bytes: Vec<u8>) -> Vec<u8> {
        let mut cursor = Cursor::new(bytes);
        let len_bytes = cursor_next_value(&mut cursor, SHORT_LEN as u64);
        let len: u64 = from_bytes(len_bytes);
        return cursor_next_value(&mut cursor, len);
    }
}

pub fn cursor_next_value(mut cursor: &mut Cursor<Vec<u8>>, len: u64) -> Vec<u8> {
    let l = len as usize;
    let current_position = cursor.position();
    let mut buff: Vec<u8> = Vec::with_capacity(l);
    unsafe {
        buff.set_len(l);
    }
    if let Err(err) = cursor.read(&mut buff) {
        error!("Read from cursor error: {}", err);
        panic!(err);
    }
    cursor.set_position(current_position + len);
    return buff;
}
<|endoftext|>


<commit_before>// Cymbalum, an extensible molecular simulation engine
// Copyright (C) 2015-2016 G. Fraux — BSD license

//! 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.
    assert!(map.insert("A", 1.0).is_none());
    assert!(map.insert("Å", 1.0).is_none());
    assert!(map.insert("nm", 10.0).is_none());
    assert!(map.insert("pm", 1e-2).is_none());
    assert!(map.insert("fm", 1e-5).is_none());
    assert!(map.insert("m", 1e10).is_none());
    assert!(map.insert("bohr", BOHR_RADIUS).is_none());

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

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

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

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

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

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

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

    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{..} => "Parentheses are not equilibrated.",
            UnitParsingError::BadBinary{..} => "Bad binary operator.",
            UnitParsingError::NotFound{..} => "Unit not found.",
        }
    }
}

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

    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());
    }
}
<commit_msg>Use a lazy static for unit convertion factors<commit_after>// Cymbalum, an extensible molecular simulation engine
// Copyright (C) 2015-2016 G. Fraux — BSD license

//! 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::BTreeMap;
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.
lazy_static!(
    static ref FACTORS: BTreeMap<&'static str, f64> = {
        let mut map = BTreeMap::new();
        // Distances units.
        assert!(map.insert("A", 1.0).is_none());
        assert!(map.insert("Å", 1.0).is_none());
        assert!(map.insert("nm", 10.0).is_none());
        assert!(map.insert("pm", 1e-2).is_none());
        assert!(map.insert("fm", 1e-5).is_none());
        assert!(map.insert("m", 1e10).is_none());
        assert!(map.insert("bohr", BOHR_RADIUS).is_none());

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

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

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

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

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

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

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

        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{..} => "Parentheses are not equilibrated.",
            UnitParsingError::BadBinary{..} => "Bad binary operator.",
            UnitParsingError::NotFound{..} => "Unit not found.",
        }
    }
}

/// Recursive unit string parsing function. This return the conversion factor
/// for a given unit.
fn conversion(unit: &str) -> Result<f64, UnitParsingError> {
    let unit = unit.trim();
    // First check if we do already have a known unit
    if let Some(val) = FACTORS.get(unit) {
        return Ok(*val);
    }

    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>// Copyright 2013-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use glib_sys;
use gobject_sys;
use std::borrow::{Borrow, Cow, ToOwned};
use std::cmp::{Eq, PartialEq};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::ops::Deref;
use std::slice;
use translate::*;
use types::StaticType;
use types::Type;
use value::{FromValueOptional, SetValue, SetValueOptional, Value};

/// Describes `Variant` types.
///
/// The `Variant` type system (based on the D-Bus one) describes types with
/// "type strings". `VariantType` is an owned immutable type string (you can
/// think of it as a `Box<str>` statically guaranteed to be a valid type
/// string), `&VariantTy` is a borrowed one (like `&str`).
pub struct VariantType {
    // GVariantType* essentially is a char*, that always is valid UTF-8 but
    // isn't NUL-terminated.
    ptr: *mut glib_sys::GVariantType,
    // We query the length on creation assuming it's cheap (because type strings
    // are short) and likely to happen anyway.
    len: usize,
}

impl VariantType {
    /// Tries to create a `VariantType` from a string slice.
    ///
    /// Returns `Ok` if the string is a valid type string, `Err` otherwise.
    pub fn new(type_string: &str) -> Result<VariantType, ()> {
        VariantTy::new(type_string).map(ToOwned::to_owned)
    }
}

unsafe impl Send for VariantType {}
unsafe impl Sync for VariantType {}

impl Drop for VariantType {
    fn drop(&mut self) {
        unsafe { glib_sys::g_variant_type_free(self.ptr) }
    }
}

impl Borrow<VariantTy> for VariantType {
    fn borrow(&self) -> &VariantTy {
        self
    }
}

impl Clone for VariantType {
    fn clone(&self) -> VariantType {
        unsafe {
            VariantType {
                ptr: glib_sys::g_variant_type_copy(self.ptr),
                len: self.len,
            }
        }
    }
}

impl Deref for VariantType {
    type Target = VariantTy;
    fn deref(&self) -> &VariantTy {
        unsafe {
            &*(slice::from_raw_parts(self.ptr as *const u8, self.len) as *const [u8]
                as *const VariantTy)
        }
    }
}

impl fmt::Debug for VariantType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        <VariantTy as fmt::Debug>::fmt(self, f)
    }
}

impl fmt::Display for VariantType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(self.to_str())
    }
}

impl Hash for VariantType {
    fn hash<H: Hasher>(&self, state: &mut H) {
        <VariantTy as Hash>::hash(self, state)
    }
}

impl<'a> Into<Cow<'a, VariantTy>> for VariantType {
    fn into(self) -> Cow<'a, VariantTy> {
        Cow::Owned(self)
    }
}

#[doc(hidden)]
impl<'a> ToGlibPtrMut<'a, *mut glib_sys::GVariantType> for VariantType {
    type Storage = &'a mut Self;

    fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut glib_sys::GVariantType, Self> {
        StashMut(self.ptr, self)
    }
}

#[doc(hidden)]
impl FromGlibPtrNone<*const glib_sys::GVariantType> for VariantType {
    unsafe fn from_glib_none(ptr: *const glib_sys::GVariantType) -> VariantType {
        VariantTy::from_ptr(ptr).to_owned()
    }
}

#[doc(hidden)]
impl FromGlibPtrFull<*const glib_sys::GVariantType> for VariantType {
    unsafe fn from_glib_full(ptr: *const glib_sys::GVariantType) -> VariantType {
        // Don't assume ownership of a const pointer.
        // A transfer: full annotation on a `const GVariantType*` is likely a bug.
        VariantTy::from_ptr(ptr).to_owned()
    }
}

/// Describes `Variant` types.
///
/// This is a borrowed counterpart of [`VariantType`](struct.VariantType.html).
/// Essentially it's a `str` statically guaranteed to be a valid type string.
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct VariantTy {
    inner: str,
}

impl VariantTy {
    /// Tries to create a `&VariantTy` from a string slice.
    ///
    /// Returns `Ok` if the string is a valid type string, `Err` otherwise.
    pub fn new(type_string: &str) -> Result<&VariantTy, ()> {
        let ptr = type_string.as_ptr();
        let limit = ptr as usize + type_string.len();
        let mut end = 0_usize;
        unsafe {
            let ok = from_glib(glib_sys::g_variant_type_string_scan(
                ptr as *const _,
                limit as *const _,
                &mut end as *mut usize as *mut _,
            ));
            if ok && end == limit {
                Ok(&*(type_string.as_bytes() as *const [u8] as *const VariantTy))
            } else {
                Err(())
            }
        }
    }

    /// Converts a type string into `&VariantTy` without any checks.
    pub unsafe fn from_str_unchecked(type_string: &str) -> &VariantTy {
        &*(type_string as *const str as *const VariantTy)
    }

    /// Creates `&VariantTy` with a wildcard lifetime from a `GVariantType`
    /// pointer.
    #[doc(hidden)]
    pub unsafe fn from_ptr<'a>(ptr: *const glib_sys::GVariantType) -> &'a VariantTy {
        let len = glib_sys::g_variant_type_get_string_length(ptr) as usize;
        &*(slice::from_raw_parts(ptr as *const u8, len) as *const [u8] as *const VariantTy)
    }

    /// Returns a `GVariantType` pointer.
    #[doc(hidden)]
    pub fn as_ptr(&self) -> *const glib_sys::GVariantType {
        self.inner.as_ptr() as *const _
    }

    /// Converts to a string slice.
    pub fn to_str(&self) -> &str {
        &self.inner
    }
}

unsafe impl Sync for VariantTy {}

#[doc(hidden)]
impl<'a> ToGlibPtr<'a, *const glib_sys::GVariantType> for VariantTy {
    type Storage = &'a Self;

    fn to_glib_none(&'a self) -> Stash<'a, *const glib_sys::GVariantType, Self> {
        Stash(self.as_ptr(), self)
    }
}

impl fmt::Display for VariantTy {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(self.to_str())
    }
}

impl<'a> Into<Cow<'a, VariantTy>> for &'a VariantTy {
    fn into(self) -> Cow<'a, VariantTy> {
        Cow::Borrowed(self)
    }
}

impl ToOwned for VariantTy {
    type Owned = VariantType;

    fn to_owned(&self) -> VariantType {
        unsafe {
            VariantType {
                ptr: glib_sys::g_variant_type_copy(self.as_ptr()),
                len: self.inner.len(),
            }
        }
    }
}

impl StaticType for VariantTy {
    fn static_type() -> Type {
        unsafe { from_glib(glib_sys::g_variant_type_get_gtype()) }
    }
}

impl SetValue for VariantTy {
    unsafe fn set_value(value: &mut Value, this: &Self) {
        gobject_sys::g_value_set_boxed(
            value.to_glib_none_mut().0,
            this.to_glib_none().0 as glib_sys::gpointer,
        )
    }
}

impl SetValueOptional for VariantTy {
    unsafe fn set_value_optional(value: &mut Value, this: Option<&Self>) {
        use std::ptr;
        let p = match this {
            Some(ref t) => t.to_glib_none().0 as glib_sys::gpointer,
            None => ptr::null(),
        };
        gobject_sys::g_value_set_boxed(value.to_glib_none_mut().0, p)
    }
}

impl<'a> FromValueOptional<'a> for &'a VariantTy {
    unsafe fn from_value_optional(value: &'a Value) -> Option<Self> {
        let cvty =
            gobject_sys::g_value_get_boxed(value.to_glib_none().0) as *mut glib_sys::GVariantType;
        if cvty.is_null() {
            None
        } else {
            Some(VariantTy::from_ptr(cvty))
        }
    }
}

impl StaticType for VariantType {
    fn static_type() -> Type {
        unsafe { from_glib(glib_sys::g_variant_type_get_gtype()) }
    }
}

impl SetValue for VariantType {
    unsafe fn set_value(value: &mut Value, this: &Self) {
        gobject_sys::g_value_set_boxed(
            value.to_glib_none_mut().0,
            this.to_glib_none().0 as glib_sys::gpointer,
        )
    }
}

impl SetValueOptional for VariantType {
    unsafe fn set_value_optional(value: &mut Value, this: Option<&Self>) {
        use std::ptr;
        let p = match this {
            Some(ref t) => t.to_glib_none().0 as glib_sys::gpointer,
            None => ptr::null(),
        };
        gobject_sys::g_value_set_boxed(value.to_glib_none_mut().0, p)
    }
}

impl<'a> FromValueOptional<'a> for VariantType {
    unsafe fn from_value_optional(value: &'a Value) -> Option<Self> {
        Option::<VariantType>::from_glib_none(
            gobject_sys::g_value_get_boxed(value.to_glib_none().0) as *mut glib_sys::GVariantType,
        )
    }
}

impl PartialEq for VariantType {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        <VariantTy as PartialEq>::eq(self, other)
    }
}

macro_rules! impl_eq {
    ($lhs:ty, $rhs: ty) => {
        impl<'a, 'b> PartialEq<$rhs> for $lhs {
            #[inline]
            fn eq(&self, other: &$rhs) -> bool {
                <VariantTy as PartialEq>::eq(self, other)
            }
        }

        impl<'a, 'b> PartialEq<$lhs> for $rhs {
            #[inline]
            fn eq(&self, other: &$lhs) -> bool {
                <VariantTy as PartialEq>::eq(self, other)
            }
        }
    };
}

impl_eq!(VariantType, VariantTy);
impl_eq!(VariantType, &'a VariantTy);
impl_eq!(VariantType, Cow<'a, VariantTy>);
impl_eq!(&'a VariantTy, Cow<'b, VariantTy>);

macro_rules! impl_str_eq {
    ($lhs:ty, $rhs: ty) => {
        impl<'a, 'b> PartialEq<$rhs> for $lhs {
            #[inline]
            fn eq(&self, other: &$rhs) -> bool {
                self.to_str().eq(&other[..])
            }
        }

        impl<'a, 'b> PartialEq<$lhs> for $rhs {
            #[inline]
            fn eq(&self, other: &$lhs) -> bool {
                self[..].eq(other.to_str())
            }
        }
    };
}

impl_str_eq!(VariantTy, str);
impl_str_eq!(VariantTy, &'a str);
impl_str_eq!(&'a VariantTy, str);
impl_str_eq!(VariantTy, String);
impl_str_eq!(&'a VariantTy, String);
impl_str_eq!(VariantType, str);
impl_str_eq!(VariantType, &'a str);
impl_str_eq!(VariantType, String);

impl Eq for VariantType {}

#[cfg(test)]
mod tests {
    use super::*;
    use glib_sys;
    use translate::*;
    use value::ToValue;

    unsafe fn equal<T, U>(ptr1: *const T, ptr2: *const U) -> bool {
        from_glib(glib_sys::g_variant_type_equal(
            ptr1 as *const _,
            ptr2 as *const _,
        ))
    }

    #[test]
    fn new() {
        let ty = VariantTy::new("((iii)s)").unwrap();
        unsafe {
            assert!(equal(ty.as_ptr(), b"((iii)s)\0" as *const u8));
        }
    }

    #[test]
    fn new_empty() {
        assert!(VariantTy::new("").is_err());
    }

    #[test]
    fn new_with_nul() {
        assert!(VariantTy::new("((iii\0)s)").is_err());
    }

    #[test]
    fn new_too_short() {
        assert!(VariantTy::new("((iii").is_err());
    }

    #[test]
    fn new_too_long() {
        assert!(VariantTy::new("(iii)s").is_err());
    }

    #[test]
    fn eq() {
        let ty1 = VariantTy::new("((iii)s)").unwrap();
        let ty2 = VariantTy::new("((iii)s)").unwrap();
        assert_eq!(ty1, ty2);
        assert_eq!(ty1, "((iii)s)");
        unsafe {
            assert!(equal(ty1.as_ptr(), ty2.as_ptr()));
        }
    }

    #[test]
    fn ne() {
        let ty1 = VariantTy::new("((iii)s)").unwrap();
        let ty2 = VariantTy::new("((iii)o)").unwrap();
        assert!(ty1 != ty2);
        assert!(ty1 != "((iii)o)");
        unsafe {
            assert!(!equal(ty1.as_ptr(), ty2.as_ptr()));
        }
    }

    #[test]
    fn from_bytes() {
        unsafe {
            let ty = VariantTy::from_ptr(b"((iii)s)" as *const u8 as *const _);
            assert_eq!(ty, "((iii)s)");
            assert!(equal(ty.as_ptr(), "((iii)s)".as_ptr()));
        }
    }

    #[test]
    fn to_owned() {
        let ty1 = VariantTy::new("((iii)s)").unwrap();
        let ty2 = ty1.to_owned();
        assert_eq!(ty1, ty2);
        assert_eq!(ty2, "((iii)s)");
        unsafe {
            assert!(equal(ty1.as_ptr(), ty2.as_ptr()));
        }
    }

    #[test]
    fn value() {
        let ty1 = VariantType::new("*").unwrap();
        let tyv = ty1.to_value();
        let ty2 = tyv.get::<VariantType>().unwrap().unwrap();
        assert_eq!(ty1, ty2);

        let ty3 = VariantTy::new("*").unwrap();
        let tyv2 = ty1.to_value();
        let ty4 = tyv2.get::<VariantType>().unwrap().unwrap();
        assert_eq!(ty3, ty4);

        assert_eq!(VariantTy::static_type(), VariantTy::static_type());
    }

}
<commit_msg>Fix "unused import" warning in variant_type.rs<commit_after>// Copyright 2013-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use glib_sys;
use gobject_sys;
use std::borrow::{Borrow, Cow, ToOwned};
use std::cmp::{Eq, PartialEq};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::ops::Deref;
use std::slice;
use translate::*;
use types::StaticType;
use types::Type;
use value::{FromValueOptional, SetValue, SetValueOptional, Value};

/// Describes `Variant` types.
///
/// The `Variant` type system (based on the D-Bus one) describes types with
/// "type strings". `VariantType` is an owned immutable type string (you can
/// think of it as a `Box<str>` statically guaranteed to be a valid type
/// string), `&VariantTy` is a borrowed one (like `&str`).
pub struct VariantType {
    // GVariantType* essentially is a char*, that always is valid UTF-8 but
    // isn't NUL-terminated.
    ptr: *mut glib_sys::GVariantType,
    // We query the length on creation assuming it's cheap (because type strings
    // are short) and likely to happen anyway.
    len: usize,
}

impl VariantType {
    /// Tries to create a `VariantType` from a string slice.
    ///
    /// Returns `Ok` if the string is a valid type string, `Err` otherwise.
    pub fn new(type_string: &str) -> Result<VariantType, ()> {
        VariantTy::new(type_string).map(ToOwned::to_owned)
    }
}

unsafe impl Send for VariantType {}
unsafe impl Sync for VariantType {}

impl Drop for VariantType {
    fn drop(&mut self) {
        unsafe { glib_sys::g_variant_type_free(self.ptr) }
    }
}

impl Borrow<VariantTy> for VariantType {
    fn borrow(&self) -> &VariantTy {
        self
    }
}

impl Clone for VariantType {
    fn clone(&self) -> VariantType {
        unsafe {
            VariantType {
                ptr: glib_sys::g_variant_type_copy(self.ptr),
                len: self.len,
            }
        }
    }
}

impl Deref for VariantType {
    type Target = VariantTy;
    fn deref(&self) -> &VariantTy {
        unsafe {
            &*(slice::from_raw_parts(self.ptr as *const u8, self.len) as *const [u8]
                as *const VariantTy)
        }
    }
}

impl fmt::Debug for VariantType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        <VariantTy as fmt::Debug>::fmt(self, f)
    }
}

impl fmt::Display for VariantType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(self.to_str())
    }
}

impl Hash for VariantType {
    fn hash<H: Hasher>(&self, state: &mut H) {
        <VariantTy as Hash>::hash(self, state)
    }
}

impl<'a> Into<Cow<'a, VariantTy>> for VariantType {
    fn into(self) -> Cow<'a, VariantTy> {
        Cow::Owned(self)
    }
}

#[doc(hidden)]
impl<'a> ToGlibPtrMut<'a, *mut glib_sys::GVariantType> for VariantType {
    type Storage = &'a mut Self;

    fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut glib_sys::GVariantType, Self> {
        StashMut(self.ptr, self)
    }
}

#[doc(hidden)]
impl FromGlibPtrNone<*const glib_sys::GVariantType> for VariantType {
    unsafe fn from_glib_none(ptr: *const glib_sys::GVariantType) -> VariantType {
        VariantTy::from_ptr(ptr).to_owned()
    }
}

#[doc(hidden)]
impl FromGlibPtrFull<*const glib_sys::GVariantType> for VariantType {
    unsafe fn from_glib_full(ptr: *const glib_sys::GVariantType) -> VariantType {
        // Don't assume ownership of a const pointer.
        // A transfer: full annotation on a `const GVariantType*` is likely a bug.
        VariantTy::from_ptr(ptr).to_owned()
    }
}

/// Describes `Variant` types.
///
/// This is a borrowed counterpart of [`VariantType`](struct.VariantType.html).
/// Essentially it's a `str` statically guaranteed to be a valid type string.
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct VariantTy {
    inner: str,
}

impl VariantTy {
    /// Tries to create a `&VariantTy` from a string slice.
    ///
    /// Returns `Ok` if the string is a valid type string, `Err` otherwise.
    pub fn new(type_string: &str) -> Result<&VariantTy, ()> {
        let ptr = type_string.as_ptr();
        let limit = ptr as usize + type_string.len();
        let mut end = 0_usize;
        unsafe {
            let ok = from_glib(glib_sys::g_variant_type_string_scan(
                ptr as *const _,
                limit as *const _,
                &mut end as *mut usize as *mut _,
            ));
            if ok && end == limit {
                Ok(&*(type_string.as_bytes() as *const [u8] as *const VariantTy))
            } else {
                Err(())
            }
        }
    }

    /// Converts a type string into `&VariantTy` without any checks.
    pub unsafe fn from_str_unchecked(type_string: &str) -> &VariantTy {
        &*(type_string as *const str as *const VariantTy)
    }

    /// Creates `&VariantTy` with a wildcard lifetime from a `GVariantType`
    /// pointer.
    #[doc(hidden)]
    pub unsafe fn from_ptr<'a>(ptr: *const glib_sys::GVariantType) -> &'a VariantTy {
        let len = glib_sys::g_variant_type_get_string_length(ptr) as usize;
        &*(slice::from_raw_parts(ptr as *const u8, len) as *const [u8] as *const VariantTy)
    }

    /// Returns a `GVariantType` pointer.
    #[doc(hidden)]
    pub fn as_ptr(&self) -> *const glib_sys::GVariantType {
        self.inner.as_ptr() as *const _
    }

    /// Converts to a string slice.
    pub fn to_str(&self) -> &str {
        &self.inner
    }
}

unsafe impl Sync for VariantTy {}

#[doc(hidden)]
impl<'a> ToGlibPtr<'a, *const glib_sys::GVariantType> for VariantTy {
    type Storage = &'a Self;

    fn to_glib_none(&'a self) -> Stash<'a, *const glib_sys::GVariantType, Self> {
        Stash(self.as_ptr(), self)
    }
}

impl fmt::Display for VariantTy {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(self.to_str())
    }
}

impl<'a> Into<Cow<'a, VariantTy>> for &'a VariantTy {
    fn into(self) -> Cow<'a, VariantTy> {
        Cow::Borrowed(self)
    }
}

impl ToOwned for VariantTy {
    type Owned = VariantType;

    fn to_owned(&self) -> VariantType {
        unsafe {
            VariantType {
                ptr: glib_sys::g_variant_type_copy(self.as_ptr()),
                len: self.inner.len(),
            }
        }
    }
}

impl StaticType for VariantTy {
    fn static_type() -> Type {
        unsafe { from_glib(glib_sys::g_variant_type_get_gtype()) }
    }
}

impl SetValue for VariantTy {
    unsafe fn set_value(value: &mut Value, this: &Self) {
        gobject_sys::g_value_set_boxed(
            value.to_glib_none_mut().0,
            this.to_glib_none().0 as glib_sys::gpointer,
        )
    }
}

impl SetValueOptional for VariantTy {
    unsafe fn set_value_optional(value: &mut Value, this: Option<&Self>) {
        use std::ptr;
        let p = match this {
            Some(ref t) => t.to_glib_none().0 as glib_sys::gpointer,
            None => ptr::null(),
        };
        gobject_sys::g_value_set_boxed(value.to_glib_none_mut().0, p)
    }
}

impl<'a> FromValueOptional<'a> for &'a VariantTy {
    unsafe fn from_value_optional(value: &'a Value) -> Option<Self> {
        let cvty =
            gobject_sys::g_value_get_boxed(value.to_glib_none().0) as *mut glib_sys::GVariantType;
        if cvty.is_null() {
            None
        } else {
            Some(VariantTy::from_ptr(cvty))
        }
    }
}

impl StaticType for VariantType {
    fn static_type() -> Type {
        unsafe { from_glib(glib_sys::g_variant_type_get_gtype()) }
    }
}

impl SetValue for VariantType {
    unsafe fn set_value(value: &mut Value, this: &Self) {
        gobject_sys::g_value_set_boxed(
            value.to_glib_none_mut().0,
            this.to_glib_none().0 as glib_sys::gpointer,
        )
    }
}

impl SetValueOptional for VariantType {
    unsafe fn set_value_optional(value: &mut Value, this: Option<&Self>) {
        use std::ptr;
        let p = match this {
            Some(ref t) => t.to_glib_none().0 as glib_sys::gpointer,
            None => ptr::null(),
        };
        gobject_sys::g_value_set_boxed(value.to_glib_none_mut().0, p)
    }
}

impl<'a> FromValueOptional<'a> for VariantType {
    unsafe fn from_value_optional(value: &'a Value) -> Option<Self> {
        Option::<VariantType>::from_glib_none(
            gobject_sys::g_value_get_boxed(value.to_glib_none().0) as *mut glib_sys::GVariantType,
        )
    }
}

impl PartialEq for VariantType {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        <VariantTy as PartialEq>::eq(self, other)
    }
}

macro_rules! impl_eq {
    ($lhs:ty, $rhs: ty) => {
        impl<'a, 'b> PartialEq<$rhs> for $lhs {
            #[inline]
            fn eq(&self, other: &$rhs) -> bool {
                <VariantTy as PartialEq>::eq(self, other)
            }
        }

        impl<'a, 'b> PartialEq<$lhs> for $rhs {
            #[inline]
            fn eq(&self, other: &$lhs) -> bool {
                <VariantTy as PartialEq>::eq(self, other)
            }
        }
    };
}

impl_eq!(VariantType, VariantTy);
impl_eq!(VariantType, &'a VariantTy);
impl_eq!(VariantType, Cow<'a, VariantTy>);
impl_eq!(&'a VariantTy, Cow<'b, VariantTy>);

macro_rules! impl_str_eq {
    ($lhs:ty, $rhs: ty) => {
        impl<'a, 'b> PartialEq<$rhs> for $lhs {
            #[inline]
            fn eq(&self, other: &$rhs) -> bool {
                self.to_str().eq(&other[..])
            }
        }

        impl<'a, 'b> PartialEq<$lhs> for $rhs {
            #[inline]
            fn eq(&self, other: &$lhs) -> bool {
                self[..].eq(other.to_str())
            }
        }
    };
}

impl_str_eq!(VariantTy, str);
impl_str_eq!(VariantTy, &'a str);
impl_str_eq!(&'a VariantTy, str);
impl_str_eq!(VariantTy, String);
impl_str_eq!(&'a VariantTy, String);
impl_str_eq!(VariantType, str);
impl_str_eq!(VariantType, &'a str);
impl_str_eq!(VariantType, String);

impl Eq for VariantType {}

#[cfg(test)]
mod tests {
    use super::*;
    use glib_sys;
    use value::ToValue;

    unsafe fn equal<T, U>(ptr1: *const T, ptr2: *const U) -> bool {
        from_glib(glib_sys::g_variant_type_equal(
            ptr1 as *const _,
            ptr2 as *const _,
        ))
    }

    #[test]
    fn new() {
        let ty = VariantTy::new("((iii)s)").unwrap();
        unsafe {
            assert!(equal(ty.as_ptr(), b"((iii)s)\0" as *const u8));
        }
    }

    #[test]
    fn new_empty() {
        assert!(VariantTy::new("").is_err());
    }

    #[test]
    fn new_with_nul() {
        assert!(VariantTy::new("((iii\0)s)").is_err());
    }

    #[test]
    fn new_too_short() {
        assert!(VariantTy::new("((iii").is_err());
    }

    #[test]
    fn new_too_long() {
        assert!(VariantTy::new("(iii)s").is_err());
    }

    #[test]
    fn eq() {
        let ty1 = VariantTy::new("((iii)s)").unwrap();
        let ty2 = VariantTy::new("((iii)s)").unwrap();
        assert_eq!(ty1, ty2);
        assert_eq!(ty1, "((iii)s)");
        unsafe {
            assert!(equal(ty1.as_ptr(), ty2.as_ptr()));
        }
    }

    #[test]
    fn ne() {
        let ty1 = VariantTy::new("((iii)s)").unwrap();
        let ty2 = VariantTy::new("((iii)o)").unwrap();
        assert!(ty1 != ty2);
        assert!(ty1 != "((iii)o)");
        unsafe {
            assert!(!equal(ty1.as_ptr(), ty2.as_ptr()));
        }
    }

    #[test]
    fn from_bytes() {
        unsafe {
            let ty = VariantTy::from_ptr(b"((iii)s)" as *const u8 as *const _);
            assert_eq!(ty, "((iii)s)");
            assert!(equal(ty.as_ptr(), "((iii)s)".as_ptr()));
        }
    }

    #[test]
    fn to_owned() {
        let ty1 = VariantTy::new("((iii)s)").unwrap();
        let ty2 = ty1.to_owned();
        assert_eq!(ty1, ty2);
        assert_eq!(ty2, "((iii)s)");
        unsafe {
            assert!(equal(ty1.as_ptr(), ty2.as_ptr()));
        }
    }

    #[test]
    fn value() {
        let ty1 = VariantType::new("*").unwrap();
        let tyv = ty1.to_value();
        let ty2 = tyv.get::<VariantType>().unwrap().unwrap();
        assert_eq!(ty1, ty2);

        let ty3 = VariantTy::new("*").unwrap();
        let tyv2 = ty1.to_value();
        let ty4 = tyv2.get::<VariantType>().unwrap().unwrap();
        assert_eq!(ty3, ty4);

        assert_eq!(VariantTy::static_type(), VariantTy::static_type());
    }

}
<|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()),
        "cs" => traverse_up(path, is_dotnet_root),
        "java" => traverse_up(path, |dir| {
            dir.join(".project").exists() || dir.join("pom.xml").exists()
        }),
        "scala" => traverse_up(path, |dir| dir.join("build.sbt").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)),
        }
    );
}

pub trait Canonicalize {
    fn canonicalize(&self) -> String;
}

impl<P> Canonicalize for P
where
    P: AsRef<Path>,
{
    fn canonicalize(&self) -> String {
        if let Ok(fc) = std::fs::canonicalize(self) {
            if let Some(fs) = fc.to_str() {
                return fs.to_owned();
            }
        }

        self.as_ref()
            .to_str()
            .map(|s| s.to_owned())
            .unwrap_or_default()
    }
}
<commit_msg>Update tests.<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()
        }),
        "scala" => traverse_up(path, |dir| dir.join("build.sbt").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, "".to_owned(), DiagnosticSeverity::Error);
    assert_eq!(
        get_command_add_sign(&sign, ""),
        " | execute 'sign place 75000 line=1 name=LanguageClientError file='"
    );

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

    let sign = Sign::new(7, "".to_owned(), 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)),
        }
    );
}

pub trait Canonicalize {
    fn canonicalize(&self) -> String;
}

impl<P> Canonicalize for P
where
    P: AsRef<Path>,
{
    fn canonicalize(&self) -> String {
        if let Ok(fc) = std::fs::canonicalize(self) {
            if let Some(fs) = fc.to_str() {
                return fs.to_owned();
            }
        }

        self.as_ref()
            .to_str()
            .map(|s| s.to_owned())
            .unwrap_or_default()
    }
}
<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::fmt;
use std::time::{Duration, Instant};

use regex::{Captures, Regex};

use console::{measure_text_width, Style};

pub fn duration_to_secs(d: Duration) -> f64 {
    d.as_secs() as f64 + f64::from(d.subsec_nanos()) / 1_000_000_000f64
}

pub fn secs_to_duration(s: f64) -> Duration {
    let secs = s.trunc() as u64;
    let nanos = (s.fract() * 1_000_000_000f64) as u32;
    Duration::new(secs, nanos)
}

/// Ring buffer with constant capacity. Used by `ProgressBar`s to display `{eta}`, `{eta_precise}`,
/// and `{*_per_sec}`.
pub struct Estimate {
    buf: Box<[f64; 15]>,
    /// Lower 4 bits signify the current length, meaning how many values of `buf` are actually
    /// meaningful (and not just set to 0 by initialization).
    ///
    /// The upper 4 bits signify the last used index in the `buf`. The estimate is currently
    /// implemented as a ring buffer and when recording a new step the oldest value is overwritten.
    /// Last index is the most recently used position, and as elements are always stored with
    /// insertion order, `last_index + 1` is the least recently used position and is the first
    /// to be overwritten.
    data: u8,
    start_time: Instant,
    start_value: u64,
}

impl Estimate {
    fn len(&self) -> u8 {
        self.data & 0x0F
    }

    fn set_len(&mut self, len: u8) {
        // Sanity check to make sure math is correct as otherwise it could result in unexpected bugs
        debug_assert!(len < 16);
        self.data = (self.data & 0xF0) | len;
    }

    fn last_idx(&self) -> u8 {
        (self.data & 0xF0) >> 4
    }

    fn set_last_idx(&mut self, last_idx: u8) {
        // This will wrap last_idx on overflow (setting to 16 will result in 0); this is fine
        // because Estimate::buf is 15 elements long and this is a ring buffer, so overwriting
        // the oldest value is correct
        self.data = ((last_idx & 0x0F) << 4) | (self.data & 0x0F);
    }

    pub fn new() -> Self {
        let this = Self {
            buf: Box::new([0.0; 15]),
            data: 0,
            start_time: Instant::now(),
            start_value: 0,
        };
        // Make sure not to break anything accidentally as self.data can't handle bufs longer than
        // 15 elements (not enough space in a u8)
        debug_assert!(this.buf.len() < 16);
        this
    }

    pub fn reset(&mut self, start_value: u64) {
        self.start_time = Instant::now();
        self.start_value = start_value;
        self.data = 0;
    }

    pub fn record_step(&mut self, value: u64) {
        let item = {
            let divisor = value.saturating_sub(self.start_value) as f64;
            if divisor == 0.0 {
                0.0
            } else {
                duration_to_secs(self.start_time.elapsed()) / divisor
            }
        };

        self.push(item);
    }

    /// Adds the `value` into the buffer, overwriting the oldest one if full, or increasing length
    /// by 1 and appending otherwise.
    fn push(&mut self, value: f64) {
        let len = self.len();
        let last_idx = self.last_idx();

        if self.buf.len() > usize::from(len) {
            // Buffer isn't yet full, increase it's size
            self.set_len(len + 1);
            self.buf[usize::from(last_idx)] = value;
        } else {
            // Buffer is full, overwrite the oldest value
            let idx = last_idx % len;
            self.buf[usize::from(idx)] = value;
        }

        self.set_last_idx(last_idx + 1);
    }

    pub fn time_per_step(&self) -> Duration {
        let len = self.len();
        secs_to_duration(self.buf[0..usize::from(len)].iter().sum::<f64>() / f64::from(len))
    }
}

impl fmt::Debug for Estimate {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Estimate")
            .field("buf", &self.buf)
            .field("len", &self.len())
            .field("last_idx", &self.last_idx())
            .field("start_time", &self.start_time)
            .field("start_value", &self.start_value)
            .finish()
    }
}

#[derive(PartialEq, Eq, Debug, Copy, Clone)]
pub enum Alignment {
    Left,
    Center,
    Right,
}

#[derive(Debug)]
pub struct TemplateVar<'a> {
    pub key: &'a str,
    pub align: Alignment,
    pub truncate: bool,
    pub width: Option<usize>,
    pub style: Option<Style>,
    pub alt_style: Option<Style>,
    pub last_element: bool,
}

impl<'a> TemplateVar<'a> {
    pub fn duplicate_for_key<'b>(&self, key: &'b str) -> TemplateVar<'b> {
        TemplateVar {
            key,
            align: self.align,
            truncate: self.truncate,
            width: self.width,
            style: self.style.clone(),
            alt_style: self.alt_style.clone(),
            last_element: self.last_element,
        }
    }
}

pub fn expand_template<F: FnMut(&TemplateVar<'_>) -> String>(s: &str, mut f: F) -> Cow<'_, str> {
    lazy_static::lazy_static! {
        static ref VAR_RE: Regex = Regex::new(r"(\}\})|\{(\{|[^{}}]+\})").unwrap();
        static ref KEY_RE: Regex = Regex::new(
            r"(?x)
                ([^:]+)
                (?:
                    :
                    ([<^>])?
                    ([0-9]+)?
                    (!)?
                    (?:\.([a-z_]+(?:\.[a-z_]+)*))?
                    (?:/([a-z_]+(?:\.[a-z_]+)*))?
                )?
            "
        )
        .unwrap();
    }
    VAR_RE.replace_all(s, |caps: &Captures<'_>| {
        if caps.get(1).is_some() {
            return "}".into();
        }
        let key = &caps[2];
        if key == "{" {
            return "{".into();
        }
        let mut var = TemplateVar {
            key,
            align: Alignment::Left,
            truncate: false,
            width: None,
            style: None,
            alt_style: None,
            last_element: caps.get(0).unwrap().end() >= s.len(),
        };
        if let Some(opt_caps) = KEY_RE.captures(&key[..key.len() - 1]) {
            if let Some(short_key) = opt_caps.get(1) {
                var.key = short_key.as_str();
            }
            var.align = match opt_caps.get(2).map(|x| x.as_str()) {
                Some("<") => Alignment::Left,
                Some("^") => Alignment::Center,
                Some(">") => Alignment::Right,
                _ => Alignment::Left,
            };
            if let Some(width) = opt_caps.get(3) {
                var.width = Some(width.as_str().parse().unwrap());
            }
            if opt_caps.get(4).is_some() {
                var.truncate = true;
            }
            if let Some(style) = opt_caps.get(5) {
                var.style = Some(Style::from_dotted_str(style.as_str()));
            }
            if let Some(alt_style) = opt_caps.get(6) {
                var.alt_style = Some(Style::from_dotted_str(alt_style.as_str()));
            }
        }
        let mut rv = f(&var);
        if let Some(width) = var.width {
            rv = pad_str(&rv, width, var.align, var.truncate).to_string()
        }
        if let Some(s) = var.style {
            rv = s.apply_to(rv).to_string();
        }
        rv
    })
}

pub fn pad_str(s: &str, width: usize, align: Alignment, truncate: bool) -> Cow<'_, str> {
    let cols = measure_text_width(s);

    if cols >= width {
        return if truncate {
            Cow::Borrowed(s.get(..width).unwrap_or(s))
        } else {
            Cow::Borrowed(s)
        };
    }

    let diff = width.saturating_sub(cols);

    let (left_pad, right_pad) = match align {
        Alignment::Left => (0, diff),
        Alignment::Right => (diff, 0),
        Alignment::Center => (diff / 2, diff.saturating_sub(diff / 2)),
    };

    let mut rv = String::new();
    for _ in 0..left_pad {
        rv.push(' ');
    }
    rv.push_str(s);
    for _ in 0..right_pad {
        rv.push(' ');
    }
    Cow::Owned(rv)
}

#[test]
fn test_expand_template() {
    let rv = expand_template("{{ {foo} {bar} }}", |var| var.key.to_uppercase());
    assert_eq!(&rv, "{ FOO BAR }");
    let rv = expand_template(r#"{ "foo": "{foo}", "bar": {bar} }"#, |var| {
        var.key.to_uppercase()
    });
    assert_eq!(&rv, r#"{ "foo": "FOO", "bar": BAR }"#);
}

#[test]
fn test_expand_template_flags() {
    use console::set_colors_enabled;
    set_colors_enabled(true);

    let rv = expand_template("{foo:5}", |var| {
        assert_eq!(var.key, "foo");
        assert_eq!(var.width, Some(5));
        "XXX".into()
    });
    assert_eq!(&rv, "XXX  ");

    let rv = expand_template("{foo:.red.on_blue}", |var| {
        assert_eq!(var.key, "foo");
        assert_eq!(var.width, None);
        assert_eq!(var.align, Alignment::Left);
        assert_eq!(var.style, Some(Style::new().red().on_blue()));
        "XXX".into()
    });
    assert_eq!(&rv, "\u{1b}[31m\u{1b}[44mXXX\u{1b}[0m");

    let rv = expand_template("{foo:^5.red.on_blue}", |var| {
        assert_eq!(var.key, "foo");
        assert_eq!(var.width, Some(5));
        assert_eq!(var.align, Alignment::Center);
        assert_eq!(var.style, Some(Style::new().red().on_blue()));
        "XXX".into()
    });
    assert_eq!(&rv, "\u{1b}[31m\u{1b}[44m XXX \u{1b}[0m");

    let rv = expand_template("{foo:^5.red.on_blue/green.on_cyan}", |var| {
        assert_eq!(var.key, "foo");
        assert_eq!(var.width, Some(5));
        assert_eq!(var.align, Alignment::Center);
        assert_eq!(var.style, Some(Style::new().red().on_blue()));
        assert_eq!(var.alt_style, Some(Style::new().green().on_cyan()));
        "XXX".into()
    });
    assert_eq!(&rv, "\u{1b}[31m\u{1b}[44m XXX \u{1b}[0m");
}

#[test]
fn test_duration_stuff() {
    let duration = Duration::new(42, 100_000_000);
    let secs = duration_to_secs(duration);
    assert_eq!(secs_to_duration(secs), duration);
}
<commit_msg>Update expand_template regex to recognize from_dotted_str() 256 colors<commit_after>use std::borrow::Cow;
use std::fmt;
use std::time::{Duration, Instant};

use regex::{Captures, Regex};

use console::{measure_text_width, Style};

pub fn duration_to_secs(d: Duration) -> f64 {
    d.as_secs() as f64 + f64::from(d.subsec_nanos()) / 1_000_000_000f64
}

pub fn secs_to_duration(s: f64) -> Duration {
    let secs = s.trunc() as u64;
    let nanos = (s.fract() * 1_000_000_000f64) as u32;
    Duration::new(secs, nanos)
}

/// Ring buffer with constant capacity. Used by `ProgressBar`s to display `{eta}`, `{eta_precise}`,
/// and `{*_per_sec}`.
pub struct Estimate {
    buf: Box<[f64; 15]>,
    /// Lower 4 bits signify the current length, meaning how many values of `buf` are actually
    /// meaningful (and not just set to 0 by initialization).
    ///
    /// The upper 4 bits signify the last used index in the `buf`. The estimate is currently
    /// implemented as a ring buffer and when recording a new step the oldest value is overwritten.
    /// Last index is the most recently used position, and as elements are always stored with
    /// insertion order, `last_index + 1` is the least recently used position and is the first
    /// to be overwritten.
    data: u8,
    start_time: Instant,
    start_value: u64,
}

impl Estimate {
    fn len(&self) -> u8 {
        self.data & 0x0F
    }

    fn set_len(&mut self, len: u8) {
        // Sanity check to make sure math is correct as otherwise it could result in unexpected bugs
        debug_assert!(len < 16);
        self.data = (self.data & 0xF0) | len;
    }

    fn last_idx(&self) -> u8 {
        (self.data & 0xF0) >> 4
    }

    fn set_last_idx(&mut self, last_idx: u8) {
        // This will wrap last_idx on overflow (setting to 16 will result in 0); this is fine
        // because Estimate::buf is 15 elements long and this is a ring buffer, so overwriting
        // the oldest value is correct
        self.data = ((last_idx & 0x0F) << 4) | (self.data & 0x0F);
    }

    pub fn new() -> Self {
        let this = Self {
            buf: Box::new([0.0; 15]),
            data: 0,
            start_time: Instant::now(),
            start_value: 0,
        };
        // Make sure not to break anything accidentally as self.data can't handle bufs longer than
        // 15 elements (not enough space in a u8)
        debug_assert!(this.buf.len() < 16);
        this
    }

    pub fn reset(&mut self, start_value: u64) {
        self.start_time = Instant::now();
        self.start_value = start_value;
        self.data = 0;
    }

    pub fn record_step(&mut self, value: u64) {
        let item = {
            let divisor = value.saturating_sub(self.start_value) as f64;
            if divisor == 0.0 {
                0.0
            } else {
                duration_to_secs(self.start_time.elapsed()) / divisor
            }
        };

        self.push(item);
    }

    /// Adds the `value` into the buffer, overwriting the oldest one if full, or increasing length
    /// by 1 and appending otherwise.
    fn push(&mut self, value: f64) {
        let len = self.len();
        let last_idx = self.last_idx();

        if self.buf.len() > usize::from(len) {
            // Buffer isn't yet full, increase it's size
            self.set_len(len + 1);
            self.buf[usize::from(last_idx)] = value;
        } else {
            // Buffer is full, overwrite the oldest value
            let idx = last_idx % len;
            self.buf[usize::from(idx)] = value;
        }

        self.set_last_idx(last_idx + 1);
    }

    pub fn time_per_step(&self) -> Duration {
        let len = self.len();
        secs_to_duration(self.buf[0..usize::from(len)].iter().sum::<f64>() / f64::from(len))
    }
}

impl fmt::Debug for Estimate {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Estimate")
            .field("buf", &self.buf)
            .field("len", &self.len())
            .field("last_idx", &self.last_idx())
            .field("start_time", &self.start_time)
            .field("start_value", &self.start_value)
            .finish()
    }
}

#[derive(PartialEq, Eq, Debug, Copy, Clone)]
pub enum Alignment {
    Left,
    Center,
    Right,
}

#[derive(Debug)]
pub struct TemplateVar<'a> {
    pub key: &'a str,
    pub align: Alignment,
    pub truncate: bool,
    pub width: Option<usize>,
    pub style: Option<Style>,
    pub alt_style: Option<Style>,
    pub last_element: bool,
}

impl<'a> TemplateVar<'a> {
    pub fn duplicate_for_key<'b>(&self, key: &'b str) -> TemplateVar<'b> {
        TemplateVar {
            key,
            align: self.align,
            truncate: self.truncate,
            width: self.width,
            style: self.style.clone(),
            alt_style: self.alt_style.clone(),
            last_element: self.last_element,
        }
    }
}

pub fn expand_template<F: FnMut(&TemplateVar<'_>) -> String>(s: &str, mut f: F) -> Cow<'_, str> {
    lazy_static::lazy_static! {
        static ref VAR_RE: Regex = Regex::new(r"(\}\})|\{(\{|[^{}}]+\})").unwrap();
        static ref KEY_RE: Regex = Regex::new(
            r"(?x)
                ([^:]+)
                (?:
                    :
                    ([<^>])?
                    ([0-9]+)?
                    (!)?
                    (?:\.([0-9a-z_]+(?:\.[0-9a-z_]+)*))?
                    (?:/([a-z_]+(?:\.[a-z_]+)*))?
                )?
            "
        )
        .unwrap();
    }
    VAR_RE.replace_all(s, |caps: &Captures<'_>| {
        if caps.get(1).is_some() {
            return "}".into();
        }
        let key = &caps[2];
        if key == "{" {
            return "{".into();
        }
        let mut var = TemplateVar {
            key,
            align: Alignment::Left,
            truncate: false,
            width: None,
            style: None,
            alt_style: None,
            last_element: caps.get(0).unwrap().end() >= s.len(),
        };
        if let Some(opt_caps) = KEY_RE.captures(&key[..key.len() - 1]) {
            if let Some(short_key) = opt_caps.get(1) {
                var.key = short_key.as_str();
            }
            var.align = match opt_caps.get(2).map(|x| x.as_str()) {
                Some("<") => Alignment::Left,
                Some("^") => Alignment::Center,
                Some(">") => Alignment::Right,
                _ => Alignment::Left,
            };
            if let Some(width) = opt_caps.get(3) {
                var.width = Some(width.as_str().parse().unwrap());
            }
            if opt_caps.get(4).is_some() {
                var.truncate = true;
            }
            if let Some(style) = opt_caps.get(5) {
                var.style = Some(Style::from_dotted_str(style.as_str()));
            }
            if let Some(alt_style) = opt_caps.get(6) {
                var.alt_style = Some(Style::from_dotted_str(alt_style.as_str()));
            }
        }
        let mut rv = f(&var);
        if let Some(width) = var.width {
            rv = pad_str(&rv, width, var.align, var.truncate).to_string()
        }
        if let Some(s) = var.style {
            rv = s.apply_to(rv).to_string();
        }
        rv
    })
}

pub fn pad_str(s: &str, width: usize, align: Alignment, truncate: bool) -> Cow<'_, str> {
    let cols = measure_text_width(s);

    if cols >= width {
        return if truncate {
            Cow::Borrowed(s.get(..width).unwrap_or(s))
        } else {
            Cow::Borrowed(s)
        };
    }

    let diff = width.saturating_sub(cols);

    let (left_pad, right_pad) = match align {
        Alignment::Left => (0, diff),
        Alignment::Right => (diff, 0),
        Alignment::Center => (diff / 2, diff.saturating_sub(diff / 2)),
    };

    let mut rv = String::new();
    for _ in 0..left_pad {
        rv.push(' ');
    }
    rv.push_str(s);
    for _ in 0..right_pad {
        rv.push(' ');
    }
    Cow::Owned(rv)
}

#[test]
fn test_expand_template() {
    let rv = expand_template("{{ {foo} {bar} }}", |var| var.key.to_uppercase());
    assert_eq!(&rv, "{ FOO BAR }");
    let rv = expand_template(r#"{ "foo": "{foo}", "bar": {bar} }"#, |var| {
        var.key.to_uppercase()
    });
    assert_eq!(&rv, r#"{ "foo": "FOO", "bar": BAR }"#);
}

#[test]
fn test_expand_template_flags() {
    use console::set_colors_enabled;
    set_colors_enabled(true);

    let rv = expand_template("{foo:5}", |var| {
        assert_eq!(var.key, "foo");
        assert_eq!(var.width, Some(5));
        "XXX".into()
    });
    assert_eq!(&rv, "XXX  ");

    let rv = expand_template("{foo:.red.on_blue}", |var| {
        assert_eq!(var.key, "foo");
        assert_eq!(var.width, None);
        assert_eq!(var.align, Alignment::Left);
        assert_eq!(var.style, Some(Style::new().red().on_blue()));
        "XXX".into()
    });
    assert_eq!(&rv, "\u{1b}[31m\u{1b}[44mXXX\u{1b}[0m");

    let rv = expand_template("{foo:^5.red.on_blue}", |var| {
        assert_eq!(var.key, "foo");
        assert_eq!(var.width, Some(5));
        assert_eq!(var.align, Alignment::Center);
        assert_eq!(var.style, Some(Style::new().red().on_blue()));
        "XXX".into()
    });
    assert_eq!(&rv, "\u{1b}[31m\u{1b}[44m XXX \u{1b}[0m");

    let rv = expand_template("{foo:^5.red.on_blue/green.on_cyan}", |var| {
        assert_eq!(var.key, "foo");
        assert_eq!(var.width, Some(5));
        assert_eq!(var.align, Alignment::Center);
        assert_eq!(var.style, Some(Style::new().red().on_blue()));
        assert_eq!(var.alt_style, Some(Style::new().green().on_cyan()));
        "XXX".into()
    });
    assert_eq!(&rv, "\u{1b}[31m\u{1b}[44m XXX \u{1b}[0m");
}

#[test]
fn test_duration_stuff() {
    let duration = Duration::new(42, 100_000_000);
    let secs = duration_to_secs(duration);
    assert_eq!(secs_to_duration(secs), duration);
}
<|endoftext|>