<commit_before>#![feature(box_syntax)]
#![feature(zero_one)]

pub mod expr;
pub mod symbol;

use std::{fmt, iter};
use expr::NumType;

pub use expr::{Expr, Condition, ExprError};

/// Used to name symbols and variables.
pub trait Alphabet: fmt::Debug + PartialEq + Eq + Clone {}

impl Alphabet for &'static str {}
impl Alphabet for char {}
impl Alphabet for u8 {}
impl Alphabet for u16 {}
impl Alphabet for u32 {}
impl Alphabet for u64 {}
impl Alphabet for usize {}

/// The common interface for Symbols. Basically this abstracts over
/// the argument implementation.
pub trait Symbol: Clone + PartialEq + fmt::Debug {
    type A: Alphabet;

    type T: NumType;

    fn symbol(&self) -> &Self::A;

    fn args(&self) -> &[Expr<Self::T>];

    fn from_result_iter<I, E>(symbol: Self::A, args_iter: I) -> Result<Self, E>
        where I: Iterator<Item = Result<Expr<Self::T>, E>>;

    fn new(symbol: Self::A) -> Self {
        Self::from_iter(symbol, iter::empty())
    }

    fn from_iter<I>(symbol: Self::A, args_iter: I) -> Self
        where I: Iterator<Item = Expr<Self::T>>
    {
        let res: Result<_, ()> = Self::from_result_iter(symbol, args_iter.map(|i| Ok(i)));
        res.unwrap()
    }

    fn evaluate(&self, bindings: &[Expr<Self::T>]) -> Result<Self, ExprError> {
        Self::from_result_iter((*self.symbol()).clone(),
                               self.args()
                                   .iter()
                                   .map(|expr| expr.evaluate(bindings).map(|ok| Expr::Const(ok))))

    }

    fn debug_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let args = self.args();
        try!(write!(f, "{:?}", *self.symbol()));
        if args.is_empty() {
            return Ok(());
        }

        try!(write!(f, "("));
        for (i, expr) in args.iter().enumerate() {
            if i > 0 {
                try!(write!(f, ", "));
            }
            try!(write!(f, "{:?}", expr));
        }
        write!(f, ")")
    }
}

/// A list of Symbols.
#[derive(PartialEq, Eq, Clone)]
pub struct SymbolString<S: Symbol>(pub Vec<S>);

impl<S: Symbol> fmt::Debug for SymbolString<S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for sym in self.0.iter() {
            try!(write!(f, "{:?}", sym));
        }
        Ok(())
    }
}

impl<S: Symbol> SymbolString<S> {
    fn from_result_iter<I, E>(symbol_iter: I) -> Result<SymbolString<S>, E>
        where I: Iterator<Item = Result<S, E>>
    {
        let mut symbols = Vec::with_capacity(symbol_iter.size_hint().0);
        for sym in symbol_iter.into_iter() {
            symbols.push(try!(sym));
        }
        Ok(SymbolString(symbols))
    }

    pub fn evaluate(&self, bindings: &[Expr<S::T>]) -> Result<SymbolString<S>, ExprError> {
        SymbolString::from_result_iter(self.0.iter().map(|sym| sym.evaluate(bindings)))
    }
}

#[derive(Debug, Clone)]
pub struct Rule<S: Symbol> {
    pub symbol: S::A,
    pub condition: Condition<S::T>,
    pub successor: SymbolString<S>,
}

#[derive(Debug, Eq, PartialEq)]
pub enum RuleError {
    SymbolMismatch,
    ConditionFalse,
    ConditionFailed,
    ExprFailed(ExprError),
}

impl<S: Symbol> Rule<S> {
    pub fn new(symbol: S::A, successor: SymbolString<S>) -> Rule<S> {
        Rule {
            symbol: symbol,
            condition: Condition::True,
            successor: successor,
        }
    }

    pub fn new_conditional(symbol: S::A,
                           successor: SymbolString<S>,
                           condition: Condition<S::T>)
                           -> Rule<S> {
        Rule {
            symbol: symbol,
            condition: condition,
            successor: successor,
        }
    }

    /// Apply the rule to the given (constant) symbol and if possible, produce
    /// a successor.
    pub fn apply(&self, sym: &S) -> Result<SymbolString<S>, RuleError> {
        let args = sym.args();
        if self.symbol.eq(sym.symbol()) {
            match self.condition.evaluate(args) {
                Ok(true) => {
                    match self.successor.evaluate(args) {
                        Ok(symstr) => Ok(symstr),
                        Err(e) => Err(RuleError::ExprFailed(e)),
                    }
                }
                Ok(false) => Err(RuleError::ConditionFalse),
                _ => Err(RuleError::ConditionFailed),
            }
        } else {
            Err(RuleError::SymbolMismatch)
        }
    }
}

#[test]
fn test_rule_apply() {
    use symbol::DSym;
    let p = DSym::new_parametric("P", vec![Expr::Const(123u32)]);
    let rule = Rule::new("A", SymbolString(vec![p.clone()]));
    assert_eq!(Err(RuleError::SymbolMismatch), rule.apply(&DSym::new("P")));
    assert_eq!(Ok(SymbolString(vec![DSym::new_parametric("P", vec![Expr::Const(123u32)])])),
               rule.apply(&DSym::new("A")));

    let rule = Rule::new_conditional("A", SymbolString(vec![p.clone()]), Condition::False);
    assert_eq!(Err(RuleError::ConditionFalse), rule.apply(&DSym::new("A")));
}

pub trait LSystem<S: Symbol> {
    fn apply_first_rule(&self, sym: &S) -> Option<SymbolString<S>>;

    /// Apply in parallel the first matching rule to each symbol in the string.
    /// Returns the total number of rule applications.
    fn develop_next(&self, axiom: &SymbolString<S>) -> (SymbolString<S>, usize) {
        let mut expanded = Vec::new();
        let mut rule_applications = 0;

        for sym in axiom.0.iter() {
            match self.apply_first_rule(sym) {
                Some(successor) => {
                    expanded.extend(successor.0);
                    rule_applications += 1;
                    // XXX: Count rule applications of the matching rule.
                }
                None => {
                    expanded.push(sym.clone());
                }
            }
        }

        (SymbolString(expanded), rule_applications)
    }

    /// Develop the system starting with `axiom` up to `max_iterations`. Return iteration count.
    fn develop(&self, axiom: SymbolString<S>, max_iterations: usize) -> (SymbolString<S>, usize) {
        let mut current = axiom;

        for iter in 0..max_iterations {
            let (next, rule_applications) = self.develop_next(&current);
            if rule_applications == 0 {
                return (current, iter);
            }
            current = next;
        }
        return (current, max_iterations);
    }
}

#[derive(Debug, Clone)]
pub struct System<S: Symbol> {
    rules: Vec<Rule<S>>,
}

impl<S: Symbol> System<S> {
    pub fn new() -> System<S> {
        System { rules: vec![] }
    }

    pub fn add_rule(&mut self, rule: Rule<S>) {
        self.rules.push(rule);
    }
}

/// Apply first matching rule and return expanded successor.
pub fn apply_first_rule<S:Symbol>(rules: &[Rule<S>], sym: &S) -> Option<SymbolString<S>> {
    for rule in rules {
        if let Ok(successor) = rule.apply(sym) {
            return Some(successor);
        }
    }
    return None;
}

impl<S: Symbol> LSystem<S> for System<S> {
    /// Apply first matching rule and return expanded successor.
    fn apply_first_rule(&self, sym: &S) -> Option<SymbolString<S>> {
        apply_first_rule(&self.rules, sym)
    }
}
<commit_msg>Rename Rule::new_conditional to Rule::new_with_condition<commit_after>#![feature(box_syntax)]
#![feature(zero_one)]

pub mod expr;
pub mod symbol;

use std::{fmt, iter};
use expr::NumType;

pub use expr::{Expr, Condition, ExprError};

/// Used to name symbols and variables.
pub trait Alphabet: fmt::Debug + PartialEq + Eq + Clone {}

impl Alphabet for &'static str {}
impl Alphabet for char {}
impl Alphabet for u8 {}
impl Alphabet for u16 {}
impl Alphabet for u32 {}
impl Alphabet for u64 {}
impl Alphabet for usize {}

/// The common interface for Symbols. Basically this abstracts over
/// the argument implementation.
pub trait Symbol: Clone + PartialEq + fmt::Debug {
    type A: Alphabet;

    type T: NumType;

    fn symbol(&self) -> &Self::A;

    fn args(&self) -> &[Expr<Self::T>];

    fn from_result_iter<I, E>(symbol: Self::A, args_iter: I) -> Result<Self, E>
        where I: Iterator<Item = Result<Expr<Self::T>, E>>;

    fn new(symbol: Self::A) -> Self {
        Self::from_iter(symbol, iter::empty())
    }

    fn from_iter<I>(symbol: Self::A, args_iter: I) -> Self
        where I: Iterator<Item = Expr<Self::T>>
    {
        let res: Result<_, ()> = Self::from_result_iter(symbol, args_iter.map(|i| Ok(i)));
        res.unwrap()
    }

    fn evaluate(&self, bindings: &[Expr<Self::T>]) -> Result<Self, ExprError> {
        Self::from_result_iter((*self.symbol()).clone(),
                               self.args()
                                   .iter()
                                   .map(|expr| expr.evaluate(bindings).map(|ok| Expr::Const(ok))))

    }

    fn debug_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let args = self.args();
        try!(write!(f, "{:?}", *self.symbol()));
        if args.is_empty() {
            return Ok(());
        }

        try!(write!(f, "("));
        for (i, expr) in args.iter().enumerate() {
            if i > 0 {
                try!(write!(f, ", "));
            }
            try!(write!(f, "{:?}", expr));
        }
        write!(f, ")")
    }
}

/// A list of Symbols.
#[derive(PartialEq, Eq, Clone)]
pub struct SymbolString<S: Symbol>(pub Vec<S>);

impl<S: Symbol> fmt::Debug for SymbolString<S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for sym in self.0.iter() {
            try!(write!(f, "{:?}", sym));
        }
        Ok(())
    }
}

impl<S: Symbol> SymbolString<S> {
    fn from_result_iter<I, E>(symbol_iter: I) -> Result<SymbolString<S>, E>
        where I: Iterator<Item = Result<S, E>>
    {
        let mut symbols = Vec::with_capacity(symbol_iter.size_hint().0);
        for sym in symbol_iter.into_iter() {
            symbols.push(try!(sym));
        }
        Ok(SymbolString(symbols))
    }

    pub fn evaluate(&self, bindings: &[Expr<S::T>]) -> Result<SymbolString<S>, ExprError> {
        SymbolString::from_result_iter(self.0.iter().map(|sym| sym.evaluate(bindings)))
    }
}

#[derive(Debug, Clone)]
pub struct Rule<S: Symbol> {
    pub symbol: S::A,
    pub condition: Condition<S::T>,
    pub successor: SymbolString<S>,
}

#[derive(Debug, Eq, PartialEq)]
pub enum RuleError {
    SymbolMismatch,
    ConditionFalse,
    ConditionFailed,
    ExprFailed(ExprError),
}

impl<S: Symbol> Rule<S> {
    pub fn new(symbol: S::A, successor: SymbolString<S>) -> Rule<S> {
        Rule {
            symbol: symbol,
            condition: Condition::True,
            successor: successor,
        }
    }

    pub fn new_with_condition(symbol: S::A,
                              successor: SymbolString<S>,
                              condition: Condition<S::T>)
                              -> Rule<S> {
        Rule {
            symbol: symbol,
            condition: condition,
            successor: successor,
        }
    }

    /// Apply the rule to the given (constant) symbol and if possible, produce
    /// a successor.
    pub fn apply(&self, sym: &S) -> Result<SymbolString<S>, RuleError> {
        let args = sym.args();
        if self.symbol.eq(sym.symbol()) {
            match self.condition.evaluate(args) {
                Ok(true) => {
                    match self.successor.evaluate(args) {
                        Ok(symstr) => Ok(symstr),
                        Err(e) => Err(RuleError::ExprFailed(e)),
                    }
                }
                Ok(false) => Err(RuleError::ConditionFalse),
                _ => Err(RuleError::ConditionFailed),
            }
        } else {
            Err(RuleError::SymbolMismatch)
        }
    }
}

#[test]
fn test_rule_apply() {
    use symbol::DSym;
    let p = DSym::new_parametric("P", vec![Expr::Const(123u32)]);
    let rule = Rule::new("A", SymbolString(vec![p.clone()]));
    assert_eq!(Err(RuleError::SymbolMismatch), rule.apply(&DSym::new("P")));
    assert_eq!(Ok(SymbolString(vec![DSym::new_parametric("P", vec![Expr::Const(123u32)])])),
               rule.apply(&DSym::new("A")));

    let rule = Rule::new_with_condition("A", SymbolString(vec![p.clone()]), Condition::False);
    assert_eq!(Err(RuleError::ConditionFalse), rule.apply(&DSym::new("A")));
}

pub trait LSystem<S: Symbol> {
    fn apply_first_rule(&self, sym: &S) -> Option<SymbolString<S>>;

    /// Apply in parallel the first matching rule to each symbol in the string.
    /// Returns the total number of rule applications.
    fn develop_next(&self, axiom: &SymbolString<S>) -> (SymbolString<S>, usize) {
        let mut expanded = Vec::new();
        let mut rule_applications = 0;

        for sym in axiom.0.iter() {
            match self.apply_first_rule(sym) {
                Some(successor) => {
                    expanded.extend(successor.0);
                    rule_applications += 1;
                    // XXX: Count rule applications of the matching rule.
                }
                None => {
                    expanded.push(sym.clone());
                }
            }
        }

        (SymbolString(expanded), rule_applications)
    }

    /// Develop the system starting with `axiom` up to `max_iterations`. Return iteration count.
    fn develop(&self, axiom: SymbolString<S>, max_iterations: usize) -> (SymbolString<S>, usize) {
        let mut current = axiom;

        for iter in 0..max_iterations {
            let (next, rule_applications) = self.develop_next(&current);
            if rule_applications == 0 {
                return (current, iter);
            }
            current = next;
        }
        return (current, max_iterations);
    }
}

#[derive(Debug, Clone)]
pub struct System<S: Symbol> {
    rules: Vec<Rule<S>>,
}

impl<S: Symbol> System<S> {
    pub fn new() -> System<S> {
        System { rules: vec![] }
    }

    pub fn add_rule(&mut self, rule: Rule<S>) {
        self.rules.push(rule);
    }
}

/// Apply first matching rule and return expanded successor.
pub fn apply_first_rule<S: Symbol>(rules: &[Rule<S>], sym: &S) -> Option<SymbolString<S>> {
    for rule in rules {
        if let Ok(successor) = rule.apply(sym) {
            return Some(successor);
        }
    }
    return None;
}

impl<S: Symbol> LSystem<S> for System<S> {
    /// Apply first matching rule and return expanded successor.
    fn apply_first_rule(&self, sym: &S) -> Option<SymbolString<S>> {
        apply_first_rule(&self.rules, sym)
    }
}
<|endoftext|>


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

use std::iter::repeat;

pub static SBOX: [u8; 256] = [
  0x29, 0x2e, 0x43, 0xc9, 0xa2, 0xd8, 0x7c, 0x01, 0x3d, 0x36, 0x54, 0xa1, 0xec,
  0xf0, 0x06, 0x13, 0x62, 0xa7, 0x05, 0xf3, 0xc0, 0xc7, 0x73, 0x8c, 0x98, 0x93,
  0x2b, 0xd9, 0xbc, 0x4c, 0x82, 0xca, 0x1e, 0x9b, 0x57, 0x3c, 0xfd, 0xd4, 0xe0,
  0x16, 0x67, 0x42, 0x6f, 0x18, 0x8a, 0x17, 0xe5, 0x12, 0xbe, 0x4e, 0xc4, 0xd6,
  0xda, 0x9e, 0xde, 0x49, 0xa0, 0xfb, 0xf5, 0x8e, 0xbb, 0x2f, 0xee, 0x7a, 0xa9,
  0x68, 0x79, 0x91, 0x15, 0xb2, 0x07, 0x3f, 0x94, 0xc2, 0x10, 0x89, 0x0b, 0x22,
  0x5f, 0x21, 0x80, 0x7f, 0x5d, 0x9a, 0x5a, 0x90, 0x32, 0x27, 0x35, 0x3e, 0xcc,
  0xe7, 0xbf, 0xf7, 0x97, 0x03, 0xff, 0x19, 0x30, 0xb3, 0x48, 0xa5, 0xb5, 0xd1,
  0xd7, 0x5e, 0x92, 0x2a, 0xac, 0x56, 0xaa, 0xc6, 0x4f, 0xb8, 0x38, 0xd2, 0x96,
  0xa4, 0x7d, 0xb6, 0x76, 0xfc, 0x6b, 0xe2, 0x9c, 0x74, 0x04, 0xf1, 0x45, 0x9d,
  0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5b, 0xcf, 0x65, 0xe6, 0x2d, 0xa8,
  0x02, 0x1b, 0x60, 0x25, 0xad, 0xae, 0xb0, 0xb9, 0xf6, 0x1c, 0x46, 0x61, 0x69,
  0x34, 0x40, 0x7e, 0x0f, 0x55, 0x47, 0xa3, 0x23, 0xdd, 0x51, 0xaf, 0x3a, 0xc3,
  0x5c, 0xf9, 0xce, 0xba, 0xc5, 0xea, 0x26, 0x2c, 0x53, 0x0d, 0x6e, 0x85, 0x28,
  0x84, 0x09, 0xd3, 0xdf, 0xcd, 0xf4, 0x41, 0x81, 0x4d, 0x52, 0x6a, 0xdc, 0x37,
  0xc8, 0x6c, 0xc1, 0xab, 0xfa, 0x24, 0xe1, 0x7b, 0x08, 0x0c, 0xbd, 0xb1, 0x4a,
  0x78, 0x88, 0x95, 0x8b, 0xe3, 0x63, 0xe8, 0x6d, 0xe9, 0xcb, 0xd5, 0xfe, 0x3b,
  0x00, 0x1d, 0x39, 0xf2, 0xef, 0xb7, 0x0e, 0x66, 0x58, 0xd0, 0xe4, 0xa6, 0x77,
  0x72, 0xf8, 0xeb, 0x75, 0x4b, 0x0a, 0x31, 0x44, 0x50, 0xb4, 0x8f, 0xed, 0x1f,
  0x1a, 0xdb, 0x99, 0x8d, 0x33, 0x9f, 0x11, 0x83, 0x14
];

pub static SBOXI: [u8; 256] = [
  0xdd, 0x07, 0x8f, 0x5f, 0x7e, 0x12, 0x0e, 0x46, 0xcb, 0xb7, 0xef, 0x4c, 0xcc,
  0xb2, 0xe3, 0x9f, 0x4a, 0xfd, 0x2f, 0x0f, 0xff, 0x44, 0x27, 0x2d, 0x2b, 0x61,
  0xf7, 0x90, 0x98, 0xde, 0x20, 0xf6, 0x87, 0x4f, 0x4d, 0xa3, 0xc8, 0x92, 0xaf,
  0x57, 0xb5, 0x00, 0x6b, 0x1a, 0xb0, 0x8d, 0x01, 0x3d, 0x62, 0xf0, 0x56, 0xfb,
  0x9c, 0x58, 0x09, 0xc2, 0x72, 0xdf, 0xa7, 0xdc, 0x23, 0x08, 0x59, 0x47, 0x9d,
  0xbc, 0x29, 0x02, 0xf1, 0x80, 0x99, 0xa1, 0x64, 0x37, 0xcf, 0xee, 0x1d, 0xbe,
  0x31, 0x70, 0xf2, 0xa5, 0xbf, 0xb1, 0x0a, 0xa0, 0x6d, 0x22, 0xe5, 0x83, 0x54,
  0x89, 0xa9, 0x52, 0x69, 0x4e, 0x91, 0x9a, 0x10, 0xd5, 0x84, 0x8b, 0xe4, 0x28,
  0x41, 0x9b, 0xc0, 0x7a, 0xc4, 0xd7, 0xb3, 0x2a, 0x82, 0x85, 0xea, 0x16, 0x7d,
  0xed, 0x78, 0xe9, 0xd0, 0x42, 0x3f, 0xca, 0x06, 0x76, 0x9e, 0x51, 0x50, 0xbd,
  0x1e, 0xfe, 0xb6, 0xb4, 0x88, 0x86, 0xd1, 0x4b, 0x2c, 0xd3, 0x17, 0xfa, 0x3b,
  0xf4, 0x55, 0x43, 0x6a, 0x19, 0x48, 0xd2, 0x74, 0x5e, 0x18, 0xf9, 0x53, 0x21,
  0x7c, 0x81, 0x35, 0xfc, 0x38, 0x0b, 0x04, 0xa2, 0x75, 0x65, 0xe8, 0x11, 0x8e,
  0x40, 0x6e, 0xc6, 0x6c, 0x93, 0x94, 0xa6, 0x95, 0xce, 0x45, 0x63, 0xf3, 0x66,
  0x77, 0xe2, 0x71, 0x96, 0xac, 0x3c, 0x1c, 0xcd, 0x30, 0x5c, 0x14, 0xc5, 0x49,
  0xa8, 0x32, 0xad, 0x6f, 0x15, 0xc3, 0x03, 0x1f, 0xd9, 0x5a, 0xba, 0xab, 0x8a,
  0xe6, 0x67, 0x73, 0xb8, 0x25, 0xda, 0x33, 0x68, 0x05, 0x1b, 0x34, 0xf8, 0xc1,
  0xa4, 0x36, 0xb9, 0x26, 0xc9, 0x7b, 0xd4, 0xe7, 0x2e, 0x8c, 0x5b, 0xd6, 0xd8,
  0xae, 0xec, 0x0c, 0xf5, 0x3e, 0xe1, 0x0d, 0x7f, 0xe0, 0x13, 0xbb, 0x3a, 0x97,
  0x5d, 0xeb, 0xaa, 0xc7, 0x39, 0x79, 0x24, 0xdb, 0x60
];

fn pad(msg: &[u8]) -> Vec<u8> {
  let mut msg = msg.to_vec();
  let pad = 16 - msg.len() % 16;
  msg.extend(repeat(pad as u8).take(pad));
  msg
}

fn checksum(msg: &[u8]) -> [u8; 16] {
  // Message must be padded.
  assert!(msg.len() % 16 == 0);

  let mut checksum = [0u8; 16];
  let mut last = 0u8;

  for chunk in msg.chunks(16) {
    for (mbyte, cbyte) in chunk.iter().zip(checksum.iter_mut()) {
      *cbyte ^= SBOX[(*mbyte ^ last) as usize];
      last = *cbyte;
    }
  }

  checksum
}

pub fn compress(state: &[u8], msg: &[u8]) -> [u8; 16] {
  // Two 128 bit blocks in.
  assert!(state.len() == 16 && msg.len() == 16);

  let mut x = [0u8; 48];

  // Copy over the current state and the message block.
  for i in 0..16 {
    x[i] = state[i];
    x[i + 16] = msg[i]
  }

  // XOR the previous state and the message block.
  for (i, byte) in msg.iter().enumerate() {
    x[32 + i] = *byte ^ x[i];
  }

  // Encrypt block (18 rounds).
  let mut t = 0u8;
  for i in 0..18 {
    for byte in x.iter_mut() {
      *byte ^= SBOX[t as usize];
      t = *byte;
    }
    t = t.wrapping_add(i);
  }

  // Extract the result.
  let mut result = [0u8; 16];
  for i in 0..16 {
    result[i] = x[i];
  }
  result
}

pub fn digest(msg: &[u8]) -> [u8; 16] {
  // Pad the message to be a multiple of 16 bytes long.
  let mut msg = pad(msg);

  // Compute the message's checksum.
  let csum = checksum(&msg);

  // Append the checksum to the message.
  msg.extend(csum.to_vec());

  // Compress all message blocks.
  msg.chunks(16).fold([0u8; 16], |state, chunk| compress(&state, chunk))
}

#[cfg(test)]
mod test {
  use digest;

  fn check(exp: &str, msg: &str) {
    let hash = digest(msg.as_bytes());
    let hex = hash.iter().fold(String::new(), |a, &b| format!("{}{:02x}", a, b));
    assert_eq!(exp.to_string(), hex);
  }

  #[test]
  fn test() {
    check("8350e5a3e24c153df2275c9f80692773", "");
    check("32ec01ec4a6dac72c0ab96fb34c0b5d1", "a");
    check("da853b0d3f88d99b30283a69e6ded6bb", "abc");
    check("ab4f496bfb2a530b219ff33031fe06b0", "message digest");
    check("4e8ddff3650292ab5a4108c3aa47940b", "abcdefghijklmnopqrstuvwxyz");
    check("da33def2a42df13975352846c30338cd", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
    check("d5976f79d83d3a0dc9806c3c66f3efd8", "12345678901234567890123456789012345678901234567890123456789012345678901234567890");
  }
}
<commit_msg>cleanup<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::iter::repeat;

pub static SBOX: [u8; 256] = [
  0x29, 0x2e, 0x43, 0xc9, 0xa2, 0xd8, 0x7c, 0x01, 0x3d, 0x36, 0x54, 0xa1, 0xec,
  0xf0, 0x06, 0x13, 0x62, 0xa7, 0x05, 0xf3, 0xc0, 0xc7, 0x73, 0x8c, 0x98, 0x93,
  0x2b, 0xd9, 0xbc, 0x4c, 0x82, 0xca, 0x1e, 0x9b, 0x57, 0x3c, 0xfd, 0xd4, 0xe0,
  0x16, 0x67, 0x42, 0x6f, 0x18, 0x8a, 0x17, 0xe5, 0x12, 0xbe, 0x4e, 0xc4, 0xd6,
  0xda, 0x9e, 0xde, 0x49, 0xa0, 0xfb, 0xf5, 0x8e, 0xbb, 0x2f, 0xee, 0x7a, 0xa9,
  0x68, 0x79, 0x91, 0x15, 0xb2, 0x07, 0x3f, 0x94, 0xc2, 0x10, 0x89, 0x0b, 0x22,
  0x5f, 0x21, 0x80, 0x7f, 0x5d, 0x9a, 0x5a, 0x90, 0x32, 0x27, 0x35, 0x3e, 0xcc,
  0xe7, 0xbf, 0xf7, 0x97, 0x03, 0xff, 0x19, 0x30, 0xb3, 0x48, 0xa5, 0xb5, 0xd1,
  0xd7, 0x5e, 0x92, 0x2a, 0xac, 0x56, 0xaa, 0xc6, 0x4f, 0xb8, 0x38, 0xd2, 0x96,
  0xa4, 0x7d, 0xb6, 0x76, 0xfc, 0x6b, 0xe2, 0x9c, 0x74, 0x04, 0xf1, 0x45, 0x9d,
  0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5b, 0xcf, 0x65, 0xe6, 0x2d, 0xa8,
  0x02, 0x1b, 0x60, 0x25, 0xad, 0xae, 0xb0, 0xb9, 0xf6, 0x1c, 0x46, 0x61, 0x69,
  0x34, 0x40, 0x7e, 0x0f, 0x55, 0x47, 0xa3, 0x23, 0xdd, 0x51, 0xaf, 0x3a, 0xc3,
  0x5c, 0xf9, 0xce, 0xba, 0xc5, 0xea, 0x26, 0x2c, 0x53, 0x0d, 0x6e, 0x85, 0x28,
  0x84, 0x09, 0xd3, 0xdf, 0xcd, 0xf4, 0x41, 0x81, 0x4d, 0x52, 0x6a, 0xdc, 0x37,
  0xc8, 0x6c, 0xc1, 0xab, 0xfa, 0x24, 0xe1, 0x7b, 0x08, 0x0c, 0xbd, 0xb1, 0x4a,
  0x78, 0x88, 0x95, 0x8b, 0xe3, 0x63, 0xe8, 0x6d, 0xe9, 0xcb, 0xd5, 0xfe, 0x3b,
  0x00, 0x1d, 0x39, 0xf2, 0xef, 0xb7, 0x0e, 0x66, 0x58, 0xd0, 0xe4, 0xa6, 0x77,
  0x72, 0xf8, 0xeb, 0x75, 0x4b, 0x0a, 0x31, 0x44, 0x50, 0xb4, 0x8f, 0xed, 0x1f,
  0x1a, 0xdb, 0x99, 0x8d, 0x33, 0x9f, 0x11, 0x83, 0x14
];

pub static SBOXI: [u8; 256] = [
  0xdd, 0x07, 0x8f, 0x5f, 0x7e, 0x12, 0x0e, 0x46, 0xcb, 0xb7, 0xef, 0x4c, 0xcc,
  0xb2, 0xe3, 0x9f, 0x4a, 0xfd, 0x2f, 0x0f, 0xff, 0x44, 0x27, 0x2d, 0x2b, 0x61,
  0xf7, 0x90, 0x98, 0xde, 0x20, 0xf6, 0x87, 0x4f, 0x4d, 0xa3, 0xc8, 0x92, 0xaf,
  0x57, 0xb5, 0x00, 0x6b, 0x1a, 0xb0, 0x8d, 0x01, 0x3d, 0x62, 0xf0, 0x56, 0xfb,
  0x9c, 0x58, 0x09, 0xc2, 0x72, 0xdf, 0xa7, 0xdc, 0x23, 0x08, 0x59, 0x47, 0x9d,
  0xbc, 0x29, 0x02, 0xf1, 0x80, 0x99, 0xa1, 0x64, 0x37, 0xcf, 0xee, 0x1d, 0xbe,
  0x31, 0x70, 0xf2, 0xa5, 0xbf, 0xb1, 0x0a, 0xa0, 0x6d, 0x22, 0xe5, 0x83, 0x54,
  0x89, 0xa9, 0x52, 0x69, 0x4e, 0x91, 0x9a, 0x10, 0xd5, 0x84, 0x8b, 0xe4, 0x28,
  0x41, 0x9b, 0xc0, 0x7a, 0xc4, 0xd7, 0xb3, 0x2a, 0x82, 0x85, 0xea, 0x16, 0x7d,
  0xed, 0x78, 0xe9, 0xd0, 0x42, 0x3f, 0xca, 0x06, 0x76, 0x9e, 0x51, 0x50, 0xbd,
  0x1e, 0xfe, 0xb6, 0xb4, 0x88, 0x86, 0xd1, 0x4b, 0x2c, 0xd3, 0x17, 0xfa, 0x3b,
  0xf4, 0x55, 0x43, 0x6a, 0x19, 0x48, 0xd2, 0x74, 0x5e, 0x18, 0xf9, 0x53, 0x21,
  0x7c, 0x81, 0x35, 0xfc, 0x38, 0x0b, 0x04, 0xa2, 0x75, 0x65, 0xe8, 0x11, 0x8e,
  0x40, 0x6e, 0xc6, 0x6c, 0x93, 0x94, 0xa6, 0x95, 0xce, 0x45, 0x63, 0xf3, 0x66,
  0x77, 0xe2, 0x71, 0x96, 0xac, 0x3c, 0x1c, 0xcd, 0x30, 0x5c, 0x14, 0xc5, 0x49,
  0xa8, 0x32, 0xad, 0x6f, 0x15, 0xc3, 0x03, 0x1f, 0xd9, 0x5a, 0xba, 0xab, 0x8a,
  0xe6, 0x67, 0x73, 0xb8, 0x25, 0xda, 0x33, 0x68, 0x05, 0x1b, 0x34, 0xf8, 0xc1,
  0xa4, 0x36, 0xb9, 0x26, 0xc9, 0x7b, 0xd4, 0xe7, 0x2e, 0x8c, 0x5b, 0xd6, 0xd8,
  0xae, 0xec, 0x0c, 0xf5, 0x3e, 0xe1, 0x0d, 0x7f, 0xe0, 0x13, 0xbb, 0x3a, 0x97,
  0x5d, 0xeb, 0xaa, 0xc7, 0x39, 0x79, 0x24, 0xdb, 0x60
];

fn pad(msg: &[u8]) -> Vec<u8> {
  let mut msg = msg.to_vec();
  let pad = 16 - msg.len() % 16;
  msg.extend(repeat(pad as u8).take(pad));
  msg
}

fn checksum(msg: &[u8]) -> [u8; 16] {
  // Message must be padded.
  assert!(msg.len() % 16 == 0);

  let mut checksum = [0u8; 16];
  let mut last = 0u8;

  for chunk in msg.chunks(16) {
    for (mbyte, cbyte) in chunk.iter().zip(checksum.iter_mut()) {
      *cbyte ^= SBOX[(*mbyte ^ last) as usize];
      last = *cbyte;
    }
  }

  checksum
}

pub fn compress(state: &[u8], msg: &[u8]) -> [u8; 16] {
  // Two 128 bit blocks in.
  assert!(state.len() == 16 && msg.len() == 16);

  let mut x = [0u8; 48];

  // Copy over the current state and the message block.
  for i in 0..16 {
    x[i] = state[i];
    x[i + 16] = msg[i]
  }

  // XOR the previous state and the message block.
  for (i, byte) in msg.iter().enumerate() {
    x[32 + i] = *byte ^ x[i];
  }

  // Encrypt block (18 rounds).
  let mut t = 0u8;
  for i in 0..18 {
    for j in 0..x.len() {
      x[j] ^= SBOX[t as usize];
      t = x[j];
    }
    t = t.wrapping_add(i);
  }

  // Extract the result.
  let mut result = [0u8; 16];
  for i in 0..16 {
    result[i] = x[i];
  }
  result
}

pub fn digest(msg: &[u8]) -> [u8; 16] {
  // Pad the message to be a multiple of 16 bytes long.
  let mut msg = pad(msg);

  // Compute the message's checksum.
  let csum = checksum(&msg);

  // Append the checksum to the message.
  msg.extend(csum.to_vec());

  // Compress all message blocks.
  msg.chunks(16).fold([0u8; 16], |state, chunk| compress(&state, chunk))
}

#[cfg(test)]
mod test {
  use digest;

  fn check(exp: &str, msg: &str) {
    let hash = digest(msg.as_bytes());
    let hex = hash.iter().fold(String::new(), |a, &b| format!("{}{:02x}", a, b));
    assert_eq!(exp.to_string(), hex);
  }

  #[test]
  fn test() {
    check("8350e5a3e24c153df2275c9f80692773", "");
    check("32ec01ec4a6dac72c0ab96fb34c0b5d1", "a");
    check("da853b0d3f88d99b30283a69e6ded6bb", "abc");
    check("ab4f496bfb2a530b219ff33031fe06b0", "message digest");
    check("4e8ddff3650292ab5a4108c3aa47940b", "abcdefghijklmnopqrstuvwxyz");
    check("da33def2a42df13975352846c30338cd", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
    check("d5976f79d83d3a0dc9806c3c66f3efd8", "12345678901234567890123456789012345678901234567890123456789012345678901234567890");
  }
}
<|endoftext|>


<commit_before>//! A crate that implements [editorconfig](http://editorconfig.org/).
extern crate regex;

extern crate ordermap;

mod ini;
use regex::{Regex, Captures};

use ordermap::OrderMap;

use std::path::{Path, PathBuf};
use std::error::Error;

/// Finds all possible `conffile`s starting from `path` until root.
fn crawl_paths(path: &Path, conffile: &str) -> Result<Vec<PathBuf>, Box<Error>> {
    let mut path = if path.exists() {
        path.canonicalize()?
    } else {
        path.to_path_buf()
    };

    let mut result = vec![];
    while path.parent().is_some() {
        let mut adjacent_file = path.clone();
        adjacent_file.set_file_name(conffile);
        path.pop();
        if !adjacent_file.exists() {
            continue;
        }
        result.push(adjacent_file);
    }
    return Ok(result);
}

fn glob_match(pattern: &String, candidate: &String) -> bool {
    // Step 1. Escape the crap out of the existing pattern
    // println!("B: {}", pattern);
    let pattern = pattern.replace(".", r"\.");
    let unmatched_open_bracket_regex = Regex::new(r"\[([^\]]*)$").unwrap();
    let pattern = unmatched_open_bracket_regex.replace(&pattern, r"\[$1")
        .to_string();
    // Step 2. Convert sh globs to regexes
    let pattern = pattern.replace("?", ".");
    // Handling * and ** is weird but this actually works
    let pattern = pattern.replace("*", "[^/]*");
    let pattern = pattern.replace("[^/]*[^/]*", ".*");
    // If we had /**/, make the directory and leading / optional
    let pattern = pattern.replace("/.*/", "(/.*)?/");
    let pattern = pattern.replace("[!", "[^");
    let alternation_regex = Regex::new(r"\{(.*,.*)\}").unwrap();
    let pattern = alternation_regex.replace(&pattern, |caps: &Captures| {
            let padded_cases = format!(",{},", &caps[1]);
            let quantifier = if padded_cases.contains(",,") { "?" } else { "" };
            let cases = caps[1].replace(",", "|");
            format!("({}){}", cases, quantifier)
        })
        .to_string();
    let leading_slash_regex = Regex::new(r"^/").unwrap();
    let pattern = leading_slash_regex.replace(&pattern, "^");
    let pattern = pattern.replace("{", r"\{");
    let pattern = pattern.replace("}", r"\}");
    let pattern = pattern.replace("||", "|");
    let pattern = pattern.replace("(|", "(");
    let pattern = pattern.replace("|)", ")");
    let mut pattern = pattern;
    pattern.push('$');
    // println!("A: {}", pattern);
    // Step 3. Actually do the testing
    let final_regex = Regex::new(&pattern).unwrap();
    return final_regex.is_match(candidate);
}

fn parse_config(target: &Path, conf_file: &Path) -> Result<OrderMap<String, String>, Box<Error>> {
    let context = conf_file.parent().unwrap();
    let ini_data = ini::Ini::load_from_file(conf_file)?;
    let mut result = OrderMap::new();
    if let Some(general) = ini_data.section::<String>(None) {
        if let Some(root) = general.get("root") {
            if root.to_lowercase() == "true" {
                result.insert("root".to_string(), "true".to_string());
            }
        }
    }
    let target = target.strip_prefix(&context)?;
    let target = target.as_os_str().to_os_string().into_string().unwrap();
    #[cfg(windows)]
    let target = target.replace("\\", "/");
    for (label, data) in ini_data.iter() {
        if let Some(ref label) = *label {
            if label.len() > 4096 {
                continue;
            }
            if glob_match(label, &target) {
                for (k, v) in data.iter() {
                    result.insert(k.clone(), v.clone());
                }
            }
        }
    }

    // Preprocessing may or may not actually be part of the spec
    // so I'm stealing this from editorconfig-core-py
    if let Some(indent_style) = result.clone().get("indent_style") {
        if indent_style == "tab" {
            if result.get("indent_size").is_none() {
                result.insert("indent_size".to_string(), "tab".to_string());
            }
        }
    }
    if let Some(indent_size) = result.clone().get("indent_size") {
        if indent_size != "tab" {
            if result.get("tab_width").is_none() {
                result.insert("tab_width".to_string(), indent_size.clone());
            }
        } else {
            if let Some(tab_width) = result.clone().get("tab_width") {
                result.insert("indent_size".to_string(), tab_width.clone());
            }
        }
    }
    Ok(result)
}

fn is_known_key(key: &str) -> bool {
    let known_keys = ["indent_style",
                      "indent_size",
                      "tab_width",
                      "end_of_line",
                      "charset",
                      "trim_trailing_whitespace",
                      "insert_final_newline"];
    known_keys.contains(&key)
}

/// Finds the configuration that applies to the file passed in `file_path`.
///
/// The `file_path` argument is the path to a file.
///
/// It looks for a file named `.editorconfig` in the file's directory and in every parent directory.
/// A search for `.editorconfig` files will stop if root (`/`) is reached or an `.editorconfig` file with `root=true` is found.
///
/// # Example
/// ```
/// use std::path::Path;
///
/// let res = editorconfig::get_config(Path::new("./test_files/simple/file.txt")).unwrap();
/// for (k, v) in res.iter() {
///     println!("{}={}", *k, *v);
/// }
/// ```
/// # Errors
///  It returns an error:
///
/// - when the `.editorconfig` file can't be found
///
/// - when it can't parse it
///
/// - when the `file_path` is malformed (check `std::fs::canonicalize` docs) or is a directory.
///
pub fn get_config(file_path: &Path) -> Result<OrderMap<String, String>, Box<Error>> {
    get_config_conffile(file_path, ".editorconfig")
}

/// Finds actual configuration that applies to file with given path.
/// # MAINLY USED FOR TESTING AND INTERNAL USE, CHECK `get_config`.
///
/// Looks for config data in given filename; in normal operation this will be ".editorconfig".
pub fn get_config_conffile(file_path: &Path,
                           conffile: &str)
                           -> Result<OrderMap<String, String>, Box<Error>> {
    let paths = crawl_paths(file_path, conffile)?;

    let mut result = OrderMap::new();
    for conf_path in paths {
        let options = parse_config(file_path, &conf_path)?;
        for (k, v) in options.iter() {
            let k = k.to_lowercase();
            let v = if is_known_key(&k) {
                v.to_lowercase()
            } else {
                v.clone()
            };
            if k.len() > 50 || v.len() > 255 {
                continue;
            }
            if !result.contains_key(&k) && k != "root" {
                result.insert(k, v);
            }
        }
        if let Some(root) = options.get("root") {
            if root.to_lowercase() == "true" {
                break;
            }
        }
    }
    return Ok(result);
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::path::Path;

    #[test]
    fn works_with_multi_level_directories() {
        let cfg = get_config(Path::new("./test_files/multi_level/foo/bar/file.txt")).unwrap();
        let mut map = OrderMap::new();
        map.insert("end_of_line".to_owned(), "lf".to_owned());
        map.insert("insert_final_newline".to_owned(), "true".to_owned());
        assert_eq!(cfg, map);
    }

    #[test]
    fn get_editorconfig_for_non_existing_file() {
        assert!(get_config(Path::new("./test_files/diocano")).is_ok());
    }
}
<commit_msg>Canonicalize paths in tests<commit_after>//! A crate that implements [editorconfig](http://editorconfig.org/).
extern crate regex;

extern crate ordermap;

mod ini;
use regex::{Regex, Captures};

use ordermap::OrderMap;

use std::path::{Path, PathBuf};
use std::error::Error;

/// Finds all possible `conffile`s starting from `path` until root.
fn crawl_paths(path: &Path, conffile: &str) -> Result<Vec<PathBuf>, Box<Error>> {
    let mut path = if path.exists() {
        path.canonicalize()?
    } else {
        path.to_path_buf()
    };

    let mut result = vec![];
    while path.parent().is_some() {
        let mut adjacent_file = path.clone();
        adjacent_file.set_file_name(conffile);
        path.pop();
        if !adjacent_file.exists() {
            continue;
        }
        result.push(adjacent_file);
    }
    return Ok(result);
}

fn glob_match(pattern: &String, candidate: &String) -> bool {
    // Step 1. Escape the crap out of the existing pattern
    // println!("B: {}", pattern);
    let pattern = pattern.replace(".", r"\.");
    let unmatched_open_bracket_regex = Regex::new(r"\[([^\]]*)$").unwrap();
    let pattern = unmatched_open_bracket_regex.replace(&pattern, r"\[$1")
        .to_string();
    // Step 2. Convert sh globs to regexes
    let pattern = pattern.replace("?", ".");
    // Handling * and ** is weird but this actually works
    let pattern = pattern.replace("*", "[^/]*");
    let pattern = pattern.replace("[^/]*[^/]*", ".*");
    // If we had /**/, make the directory and leading / optional
    let pattern = pattern.replace("/.*/", "(/.*)?/");
    let pattern = pattern.replace("[!", "[^");
    let alternation_regex = Regex::new(r"\{(.*,.*)\}").unwrap();
    let pattern = alternation_regex.replace(&pattern, |caps: &Captures| {
            let padded_cases = format!(",{},", &caps[1]);
            let quantifier = if padded_cases.contains(",,") { "?" } else { "" };
            let cases = caps[1].replace(",", "|");
            format!("({}){}", cases, quantifier)
        })
        .to_string();
    let leading_slash_regex = Regex::new(r"^/").unwrap();
    let pattern = leading_slash_regex.replace(&pattern, "^");
    let pattern = pattern.replace("{", r"\{");
    let pattern = pattern.replace("}", r"\}");
    let pattern = pattern.replace("||", "|");
    let pattern = pattern.replace("(|", "(");
    let pattern = pattern.replace("|)", ")");
    let mut pattern = pattern;
    pattern.push('$');
    // println!("A: {}", pattern);
    // Step 3. Actually do the testing
    let final_regex = Regex::new(&pattern).unwrap();
    return final_regex.is_match(candidate);
}

fn parse_config(target: &Path, conf_file: &Path) -> Result<OrderMap<String, String>, Box<Error>> {
    let context = conf_file.parent().unwrap();
    let ini_data = ini::Ini::load_from_file(conf_file)?;
    let mut result = OrderMap::new();
    if let Some(general) = ini_data.section::<String>(None) {
        if let Some(root) = general.get("root") {
            if root.to_lowercase() == "true" {
                result.insert("root".to_string(), "true".to_string());
            }
        }
    }
    let target = target.strip_prefix(&context)?;
    let target = target.as_os_str().to_os_string().into_string().unwrap();
    #[cfg(windows)]
    let target = target.replace("\\", "/");
    for (label, data) in ini_data.iter() {
        if let Some(ref label) = *label {
            if label.len() > 4096 {
                continue;
            }
            if glob_match(label, &target) {
                for (k, v) in data.iter() {
                    result.insert(k.clone(), v.clone());
                }
            }
        }
    }

    // Preprocessing may or may not actually be part of the spec
    // so I'm stealing this from editorconfig-core-py
    if let Some(indent_style) = result.clone().get("indent_style") {
        if indent_style == "tab" {
            if result.get("indent_size").is_none() {
                result.insert("indent_size".to_string(), "tab".to_string());
            }
        }
    }
    if let Some(indent_size) = result.clone().get("indent_size") {
        if indent_size != "tab" {
            if result.get("tab_width").is_none() {
                result.insert("tab_width".to_string(), indent_size.clone());
            }
        } else {
            if let Some(tab_width) = result.clone().get("tab_width") {
                result.insert("indent_size".to_string(), tab_width.clone());
            }
        }
    }
    Ok(result)
}

fn is_known_key(key: &str) -> bool {
    let known_keys = ["indent_style",
                      "indent_size",
                      "tab_width",
                      "end_of_line",
                      "charset",
                      "trim_trailing_whitespace",
                      "insert_final_newline"];
    known_keys.contains(&key)
}

/// Finds the configuration that applies to the file passed in `file_path`.
///
/// The `file_path` argument is the path to a file.
///
/// It looks for a file named `.editorconfig` in the file's directory and in every parent directory.
/// A search for `.editorconfig` files will stop if root (`/`) is reached or an `.editorconfig` file with `root=true` is found.
///
/// # Example
/// ```
/// use std::path::Path;
///
/// let path = Path::new("./test_files/simple/file.txt");
/// let path = path.canonicalize().unwrap();
/// let res = editorconfig::get_config(&path).unwrap();
/// for (k, v) in res.iter() {
///     println!("{}={}", *k, *v);
/// }
/// ```
/// # Errors
///  It returns an error:
///
/// - when the `.editorconfig` file can't be found
///
/// - when it can't parse it
///
/// - when the `file_path` is malformed (check `std::fs::canonicalize` docs) or is a directory.
///
pub fn get_config(file_path: &Path) -> Result<OrderMap<String, String>, Box<Error>> {
    get_config_conffile(file_path, ".editorconfig")
}

/// Finds actual configuration that applies to file with given path.
/// # MAINLY USED FOR TESTING AND INTERNAL USE, CHECK `get_config`.
///
/// Looks for config data in given filename; in normal operation this will be ".editorconfig".
pub fn get_config_conffile(file_path: &Path,
                           conffile: &str)
                           -> Result<OrderMap<String, String>, Box<Error>> {
    let paths = crawl_paths(file_path, conffile)?;

    let mut result = OrderMap::new();
    for conf_path in paths {
        let options = parse_config(file_path, &conf_path)?;
        for (k, v) in options.iter() {
            let k = k.to_lowercase();
            let v = if is_known_key(&k) {
                v.to_lowercase()
            } else {
                v.clone()
            };
            if k.len() > 50 || v.len() > 255 {
                continue;
            }
            if !result.contains_key(&k) && k != "root" {
                result.insert(k, v);
            }
        }
        if let Some(root) = options.get("root") {
            if root.to_lowercase() == "true" {
                break;
            }
        }
    }
    return Ok(result);
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::path::Path;

    #[test]
    fn works_with_multi_level_directories() {
        let path = Path::new("./test_files/multi_level/foo/bar/file.txt");
        let path = path.canonicalize().unwrap();
        let cfg = get_config(&path).unwrap();
        let mut map = OrderMap::new();
        map.insert("end_of_line".to_owned(), "lf".to_owned());
        map.insert("insert_final_newline".to_owned(), "true".to_owned());
        assert_eq!(cfg, map);
    }

    #[test]
    fn get_editorconfig_for_non_existing_file() {
        assert!(get_config(Path::new("./test_files/diocano")).is_ok());
    }
}
<|endoftext|>


<commit_before>#![no_std]
#![feature(phase)]

//! Convert between characters and their standard names.
//!
//! This crate provides two functions for mapping from a `char` to the
//! name given by the Unicode standard (7.0). There are no runtime
//! requirements and this is usable with only `core`, but the
//! associated tables are large (8MB).
//!
//! ```rust
//! extern crate unicode_names;
//!
//! fn main() {
//!     println!("☃ is called {}", unicode_names::name('☃')); // SNOWMAN
//!     println!("{} is happy", unicode_names::character("white smiling face")); // ☺
//!     // (NB. case insensitivity)
//! }
//! ```
//!
//! [**Source**](https://github.com/huonw/unicode_names).
//!
//! # Macros
//!
//! The associated `unicode_names_macros` crate provides two macros
//! for converting at compile-time, giving named literals similar to
//! Python's `"\N{...}"`.
//!
//! - `named_char!(name)` takes a single string `name` and creates a
//!   `char` literal.
//! - `named!(string)` takes a string and replaces any `\\N{name}`
//!   sequences with the character with that name. NB. String escape
//!   sequences cannot be customised, so the extra backslash (or a raw
//!   string) is required.
//!
//! ```rust,ignore
//! #![feature(phase)]
//!
//! #[phase(plugin)] extern crate unicode_names_macros;
//!
//! fn main() {
//!     let x: char = named_char!("snowman");
//!     assert_eq!(x, '☃');
//!
//!     let y: &str = named!("foo bar \\N{BLACK STAR} baz qux");
//!     assert_eq!(y, "foo bar ★ baz qux");
//! }
//! ```
//!
//! # Cargo-enabled
//!
//! ```toml
//! [dependencies.unicode_names]
//! git = "https://github.com/huonw/unicode_names"
//!
//! [dependencies.unicode_names_macros]
//! git = "https://github.com/huonw/unicode_names_macros"
//! ```

#[phase(link, plugin)] extern crate core;

#[cfg(test)] #[phase(link, plugin)] extern crate std;
#[cfg(test)] extern crate native;
#[cfg(test)] extern crate test;

use core::cmp::{Equal, Less, Greater};
use core::collections::Collection;
use core::option::Option;
use core::iter::{order, Iterator, DoubleEndedIterator};
use core::slice::{ImmutableSlice, MutableSlice};
use core::str::StrSlice;

#[allow(dead_code)]
mod generated;

/// Find the name of `c`, or `None` if `c` has no name.
///
/// # Example
///
/// ```rust
/// assert_eq!(unicode_names::name('a'), Some("LATIN SMALL LETTER A"));
/// assert_eq!(unicode_names::name('\u2605'), Some("BLACK STAR"));
/// assert_eq!(unicode_names::name('☃'), Some("SNOWMAN"));
///
/// // control code
/// assert_eq!(unicode_names::name('\x00'), None);
/// // unassigned
/// assert_eq!(unicode_names::name('\U0010FFFF'), None);
/// ```
pub fn name(c: char) -> Option<&'static str> {
    generated::CHARACTER_TO_NAME.binary_search(|&(lo,hi, _)| {
        if c < lo {
            Greater
        } else if hi < c {
            Less
        } else {
            Equal
        }
    }).found().map(|idx| {
        let (lo, _, names) = generated::CHARACTER_TO_NAME[idx];
        names[c as uint - lo as uint]
    })
}

/// Find the character called `name`, or `None` if none exists.
///
/// This searches case-insensitively
///
/// # Example
///
/// ```rust
/// assert_eq!(unicode_names::character("LATIN SMALL LETTER A"), Some('a'));
/// assert_eq!(unicode_names::character("latin SMALL letter A"), Some('a'));
/// assert_eq!(unicode_names::character("latin small letter a"), Some('a'));
/// assert_eq!(unicode_names::character("BLACK STAR"), Some('★'));
/// assert_eq!(unicode_names::character("SNOWMAN"), Some('☃'));
///
/// assert_eq!(unicode_names::character("nonsense"), None);
/// ```
pub fn character(name: &str) -> Option<char> {
    let mut buf = [0u8, .. generated::MAX_NAME_LENGTH + 1];
    for (place, byte) in buf.mut_iter().zip(name.bytes()) {
        *place = ASCII_UPPER_MAP[byte as uint]
    }
    let search_name = buf.slice_to(name.len());

    generated::NAME_TO_CHARACTER.binary_search(|&(this_name, _)| {
        // reverse order because this is more unique, and thus more
        // efficient (less time spend iterating over common LATIN
        // CAPITAL LETTER ... etc. prefixes)
        order::cmp(this_name.bytes().rev(),
                   search_name.iter().map(|&b| b).rev())
    }).found().map(|idx| {
        let (_, c) = generated::NAME_TO_CHARACTER[idx];
        c
    })
}

// FIXME: use the stdlib one if/when std::ascii moves into `core` (or
// some such).
static ASCII_UPPER_MAP: [u8, ..256] = [
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
    0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
    b' ', b'!', b'"', b'#', b'$', b'%', b'&', b'\'', // " // syntax highlighting :/
    b'(', b')', b'*', b'+', b',', b'-', b'.', b'/',
    b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7',
    b'8', b'9', b':', b';', b'<', b'=', b'>', b'?',
    b'@', b'A', b'B', b'C', b'D', b'E', b'F', b'G',
    b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O',
    b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W',
    b'X', b'Y', b'Z', b'[', b'\\', b']', b'^', b'_',
    b'`',

          b'A', b'B', b'C', b'D', b'E', b'F', b'G',
    b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O',
    b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W',
    b'X', b'Y', b'Z',

                      b'{', b'|', b'}', b'~', 0x7f,
    0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
    0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
    0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
    0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
    0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
    0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
    0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
    0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
    0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
    0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
    0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
    0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
    0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
    0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
];

#[cfg(test)]
mod tests {
    use core::collections::Collection;
    use core::slice::ImmutableSlice;
    use core::option::{None, Some};
    use core::iter::{Iterator, range};
    use core::char;

    use std::ascii::AsciiExt;
    use std::rand::{Rng, XorShiftRng, SeedableRng};
    use std::str::Str;
    use std::vec::Vec;

    use test::{mod, Bencher};

    use super::{generated, name, character};

    #[test]
    fn exhaustive_positive() {
        for &(n, c) in generated::NAME_TO_CHARACTER.iter() {
            assert_eq!(name(c), Some(n));
            assert_eq!(character(n), Some(c));
            assert_eq!(character(n.to_ascii_lower().as_slice()), Some(c))
        }
    }

    #[test]
    fn exhaustive_name_negative() {
        // check that gaps in the CHARACTER_TO_NAME table have no
        // names (these are unassigned/control codes).
        fn test_range(from: u32, to: u32) {
            for x in range(from, to) {
                match char::from_u32(x) {
                    None => {}
                    Some(c) => {
                        assert_eq!(name(c), None);
                    }
                }
            }
        }

        let mut last = 0;
        for &(lo, hi, _) in generated::CHARACTER_TO_NAME.iter() {
            test_range(last, lo as u32);
            last = hi as u32 + 1;
        }
        test_range(last, 0x10FFFF + 1)
    }

    #[test]
    fn character_negative() {
        let names = [
            "",
            "x",
            "öäå",
            "SPAACE"
            ];
        for &n in names.iter() {
            assert_eq!(character(n), None);
        }
    }

    #[bench]
    fn name_one_hundreth(b: &mut Bencher) {
        let mut chars: Vec<char> = range(0u32, 0x10FFFF + 1).filter_map(char::from_u32).collect();

        // be consistent across runs, but avoid sequential/caching.
        let mut rng: XorShiftRng = SeedableRng::from_seed([0xFF00FF00, 0xF0F0F0F0,
                                                           0x00FF00FF, 0x0F0F0F0F]);
        rng.shuffle(chars.as_mut_slice());
        let new_len = chars.len() / 100;
        chars.truncate(new_len);

        b.iter(|| {
            for c in chars.iter() {
                test::black_box(name(*c));
            }
        })
    }

    #[bench]
    fn character_one_hundreth(b: &mut Bencher) {
        let mut names: Vec<&str> = generated::NAME_TO_CHARACTER.iter().map(|&(n,_)| n).collect();
        // be consistent across runs, but avoid sequential/caching.
        let mut rng: XorShiftRng = SeedableRng::from_seed([0xFF00FF00, 0xF0F0F0F0,
                                                           0x00FF00FF, 0x0F0F0F0F]);
        rng.shuffle(names.as_mut_slice());

        let new_len = names.len() / 100;
        names.truncate(new_len);
        b.iter(|| {
            for n in names.iter() {
                test::black_box(character(*n))
            }
        })
    }
}
<commit_msg>General doc tweaks.<commit_after>#![no_std]
#![feature(phase)]

//! Convert between characters and their standard names.
//!
//! This crate provides two functions for mapping from a `char` to the
//! name given by the Unicode standard (7.0). There are no runtime
//! requirements and this is usable with only `core`, but the
//! associated tables are large (8MB).
//!
//! ```rust
//! extern crate unicode_names;
//!
//! fn main() {
//!     println!("☃ is called {}", unicode_names::name('☃')); // SNOWMAN
//!     println!("{} is happy", unicode_names::character("white smiling face")); // ☺
//!     // (NB. case insensitivity)
//! }
//! ```
//!
//! [**Source**](https://github.com/huonw/unicode_names).
//!
//! # Macros
//!
//! The associated `unicode_names_macros` crate provides two macros
//! for converting at compile-time, giving named literals similar to
//! Python's `"\N{...}"`.
//!
//! - `named_char!(name)` takes a single string `name` and creates a
//!   `char` literal.
//! - `named!(string)` takes a string and replaces any `\\N{name}`
//!   sequences with the character with that name. NB. String escape
//!   sequences cannot be customised, so the extra backslash (or a raw
//!   string) is required.
//!
//! ```rust,ignore
//! #![feature(phase)]
//!
//! #[phase(plugin)] extern crate unicode_names_macros;
//!
//! fn main() {
//!     let x: char = named_char!("snowman");
//!     assert_eq!(x, '☃');
//!
//!     let y: &str = named!("foo bar \\N{BLACK STAR} baz qux");
//!     assert_eq!(y, "foo bar ★ baz qux");
//! }
//! ```
//!
//! # Cargo-enabled
//!
//! Add either (or both!) of the following to your `Cargo.toml`.
//!
//! ```toml
//! [dependencies.unicode_names]
//! git = "https://github.com/huonw/unicode_names"
//!
//! [dependencies.unicode_names_macros]
//! git = "https://github.com/huonw/unicode_names_macros"
//! ```

#[phase(link, plugin)] extern crate core;

#[cfg(test)] #[phase(link, plugin)] extern crate std;
#[cfg(test)] extern crate native;
#[cfg(test)] extern crate test;

use core::cmp::{Equal, Less, Greater};
use core::collections::Collection;
use core::option::Option;
use core::iter::{order, Iterator, DoubleEndedIterator};
use core::slice::{ImmutableSlice, MutableSlice};
use core::str::StrSlice;

#[allow(dead_code)]
mod generated;

/// Find the name of `c`, or `None` if `c` has no name.
///
/// # Example
///
/// ```rust
/// assert_eq!(unicode_names::name('a'), Some("LATIN SMALL LETTER A"));
/// assert_eq!(unicode_names::name('\u2605'), Some("BLACK STAR"));
/// assert_eq!(unicode_names::name('☃'), Some("SNOWMAN"));
///
/// // control code
/// assert_eq!(unicode_names::name('\x00'), None);
/// // unassigned
/// assert_eq!(unicode_names::name('\U0010FFFF'), None);
/// ```
pub fn name(c: char) -> Option<&'static str> {
    generated::CHARACTER_TO_NAME.binary_search(|&(lo,hi, _)| {
        if c < lo {
            Greater
        } else if hi < c {
            Less
        } else {
            Equal
        }
    }).found().map(|idx| {
        let (lo, _, names) = generated::CHARACTER_TO_NAME[idx];
        names[c as uint - lo as uint]
    })
}

/// Find the character called `name`, or `None` if no such character
/// exists.
///
/// This searches case-insensitively.
///
/// # Example
///
/// ```rust
/// assert_eq!(unicode_names::character("LATIN SMALL LETTER A"), Some('a'));
/// assert_eq!(unicode_names::character("latin SMALL letter A"), Some('a'));
/// assert_eq!(unicode_names::character("latin small letter a"), Some('a'));
/// assert_eq!(unicode_names::character("BLACK STAR"), Some('★'));
/// assert_eq!(unicode_names::character("SNOWMAN"), Some('☃'));
///
/// assert_eq!(unicode_names::character("nonsense"), None);
/// ```
pub fn character(name: &str) -> Option<char> {
    let mut buf = [0u8, .. generated::MAX_NAME_LENGTH + 1];
    for (place, byte) in buf.mut_iter().zip(name.bytes()) {
        *place = ASCII_UPPER_MAP[byte as uint]
    }
    let search_name = buf.slice_to(name.len());

    generated::NAME_TO_CHARACTER.binary_search(|&(this_name, _)| {
        // reverse order because this is more unique, and thus more
        // efficient (less time spend iterating over common LATIN
        // CAPITAL LETTER ... etc. prefixes)
        order::cmp(this_name.bytes().rev(),
                   search_name.iter().map(|&b| b).rev())
    }).found().map(|idx| {
        let (_, c) = generated::NAME_TO_CHARACTER[idx];
        c
    })
}

// FIXME: use the stdlib one if/when std::ascii moves into `core` (or
// some such).
static ASCII_UPPER_MAP: [u8, ..256] = [
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
    0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
    b' ', b'!', b'"', b'#', b'$', b'%', b'&', b'\'', // " // syntax highlighting :/
    b'(', b')', b'*', b'+', b',', b'-', b'.', b'/',
    b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7',
    b'8', b'9', b':', b';', b'<', b'=', b'>', b'?',
    b'@', b'A', b'B', b'C', b'D', b'E', b'F', b'G',
    b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O',
    b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W',
    b'X', b'Y', b'Z', b'[', b'\\', b']', b'^', b'_',
    b'`',

          b'A', b'B', b'C', b'D', b'E', b'F', b'G',
    b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O',
    b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W',
    b'X', b'Y', b'Z',

                      b'{', b'|', b'}', b'~', 0x7f,
    0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
    0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
    0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
    0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
    0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
    0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
    0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
    0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
    0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
    0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
    0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
    0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
    0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
    0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
];

#[cfg(test)]
mod tests {
    use core::collections::Collection;
    use core::slice::ImmutableSlice;
    use core::option::{None, Some};
    use core::iter::{Iterator, range};
    use core::char;

    use std::ascii::AsciiExt;
    use std::rand::{Rng, XorShiftRng, SeedableRng};
    use std::str::Str;
    use std::vec::Vec;

    use test::{mod, Bencher};

    use super::{generated, name, character};

    #[test]
    fn exhaustive_positive() {
        for &(n, c) in generated::NAME_TO_CHARACTER.iter() {
            assert_eq!(name(c), Some(n));
            assert_eq!(character(n), Some(c));
            assert_eq!(character(n.to_ascii_lower().as_slice()), Some(c))
        }
    }

    #[test]
    fn exhaustive_name_negative() {
        // check that gaps in the CHARACTER_TO_NAME table have no
        // names (these are unassigned/control codes).
        fn test_range(from: u32, to: u32) {
            for x in range(from, to) {
                match char::from_u32(x) {
                    None => {}
                    Some(c) => {
                        assert_eq!(name(c), None);
                    }
                }
            }
        }

        let mut last = 0;
        for &(lo, hi, _) in generated::CHARACTER_TO_NAME.iter() {
            test_range(last, lo as u32);
            last = hi as u32 + 1;
        }
        test_range(last, 0x10FFFF + 1)
    }

    #[test]
    fn character_negative() {
        let names = [
            "",
            "x",
            "öäå",
            "SPAACE"
            ];
        for &n in names.iter() {
            assert_eq!(character(n), None);
        }
    }

    #[bench]
    fn name_one_hundreth(b: &mut Bencher) {
        let mut chars: Vec<char> = range(0u32, 0x10FFFF + 1).filter_map(char::from_u32).collect();

        // be consistent across runs, but avoid sequential/caching.
        let mut rng: XorShiftRng = SeedableRng::from_seed([0xFF00FF00, 0xF0F0F0F0,
                                                           0x00FF00FF, 0x0F0F0F0F]);
        rng.shuffle(chars.as_mut_slice());
        let new_len = chars.len() / 100;
        chars.truncate(new_len);

        b.iter(|| {
            for c in chars.iter() {
                test::black_box(name(*c));
            }
        })
    }

    #[bench]
    fn character_one_hundreth(b: &mut Bencher) {
        let mut names: Vec<&str> = generated::NAME_TO_CHARACTER.iter().map(|&(n,_)| n).collect();
        // be consistent across runs, but avoid sequential/caching.
        let mut rng: XorShiftRng = SeedableRng::from_seed([0xFF00FF00, 0xF0F0F0F0,
                                                           0x00FF00FF, 0x0F0F0F0F]);
        rng.shuffle(names.as_mut_slice());

        let new_len = names.len() / 100;
        names.truncate(new_len);
        b.iter(|| {
            for n in names.iter() {
                test::black_box(character(*n))
            }
        })
    }
}
<|endoftext|>


<commit_before>#![recursion_limit = "1024"]
#[macro_use]
extern crate log;
extern crate proc_macro;
#[macro_use]
extern crate quote;
extern crate syn;

extern crate walkdir;

use proc_macro::TokenStream;
use syn::*;
use quote::Tokens;

#[cfg(debug_assertions)]
fn generate_assets(ident: &syn::Ident, folder_path: String) -> quote::Tokens {
  quote!{
      use std::fs::File;
      use std::io::Read;
      use std::path::Path;

      impl #ident {
          pub fn get(file_path: &str) -> Option<Vec<u8>> {
              let folder_path = #folder_path;
              let name = &format!("{}{}", folder_path, file_path);
              let path = &Path::new(name);
              let key = String::from(path.to_str().expect("Path does not have a string representation"));
              info!("file: {}", key);
              let mut file = match File::open(path) {
                  Ok(mut file) => file,
                  Err(e) => {
                      error!("file: {} {}", key, e);
                      return None
                  }
              };
              let mut data: Vec<u8> = Vec::new();
              match file.read_to_end(&mut data) {
                  Ok(_) => Some(data),
                  Err(e) =>  {
                      error!("file: {} {}", key, e);
                      return None
                  }
              }
          }
      }
  }
}

#[cfg(not(debug_assertions))]
fn generate_assets(ident: &syn::Ident, folder_path: String) -> quote::Tokens {
  use std::fs::File;
  use std::io::Read;
  use std::path::Path;
  use walkdir::WalkDir;
  let mut values = Vec::<Tokens>::new();
  for entry in WalkDir::new(folder_path.clone())
    .into_iter()
    .filter_map(|e| e.ok())
    .filter(|e| e.file_type().is_file())
  {
    println!("   \x1b[92mCompiling\x1b[0m {}", entry.path().display());
    let base = &folder_path.clone();
    let key = String::from(
      entry
        .path()
        .to_str()
        .expect("Path does not have a string representation"),
    ).replace(base, "");
    let mut file = File::open(&Path::new(&entry.path())).unwrap_or_else(|e| {
      panic!("could not open file -> {} {}", key, e);
    });
    let mut data: Vec<u8> = Vec::new();
    file.read_to_end(&mut data).unwrap_or_else(|e| {
      panic!("could not read file -> {} {}", key, e);
    });
    let value = quote!{
      #key => Some(vec!#data),
    };
    values.push(value);
  }
  quote!{
      impl #ident {
          pub fn get(file_path: &str) -> Option<Vec<u8>> {
              match file_path {
                  #(#values)*
                  _ => None,
              }
          }
      }
  }
}

fn help() {
  panic!("#[derive(RustEmbed)] should contain one attribute like this #[folder(\"examples/public/\")]");
}

fn impl_rust_embed(ast: &syn::DeriveInput) -> Tokens {
  match ast.body {
    Body::Enum(_) => help(),
    Body::Struct(ref data) => match data {
      &VariantData::Struct(_) => help(),
      _ => {}
    },
  };
  let ident = &ast.ident;
  if ast.attrs.len() == 0 || ast.attrs.len() > 1 {
    help();
  }
  let value = &ast.attrs[0].value;
  let items = match value {
    &MetaItem::List(ref attr_name, ref items) => {
      if attr_name == "folder" {
        items
      } else {
        panic!("#[derive(RustEmbed)] attribute name must be folder");
      }
    }
    _ => {
      panic!("#[derive(RustEmbed)] attribute name must be folder");
    }
  };
  let item = &items[0];
  let lit = match item {
    &NestedMetaItem::Literal(ref l) => l,
    _ => {
      panic!("Hello");
    }
  };
  let folder_path = match lit {
    &Lit::Str(ref val, _) => val.clone(),
    _ => {
      panic!("#[derive(RustEmbed)] attribute value must be a string literal");
    }
  };
  info!("folder: {}", folder_path);
  generate_assets(ident, folder_path)
}

#[proc_macro_derive(RustEmbed, attributes(folder))]
pub fn derive_input_object(input: TokenStream) -> TokenStream {
  let s = input.to_string();
  let ast = syn::parse_derive_input(&s).unwrap();
  let gen = impl_rust_embed(&ast);
  gen.parse().unwrap()
}
<commit_msg>Use standard logging in debug mode<commit_after>#![recursion_limit = "1024"]
#[macro_use]
extern crate log;
extern crate proc_macro;
#[macro_use]
extern crate quote;
extern crate syn;

extern crate walkdir;

use proc_macro::TokenStream;
use syn::*;
use quote::Tokens;

#[cfg(debug_assertions)]
fn generate_assets(ident: &syn::Ident, folder_path: String) -> quote::Tokens {
  quote!{
      use std::fs::File;
      use std::io::Read;
      use std::path::Path;

      impl #ident {
          pub fn get(file_path: &str) -> Option<Vec<u8>> {
              let folder_path = #folder_path;
              let name = &format!("{}{}", folder_path, file_path);
              let path = &Path::new(name);
              let key = String::from(path.to_str().expect("Path does not have a string representation"));
              println!("file: {}", key);
              let mut file = match File::open(path) {
                  Ok(mut file) => file,
                  Err(e) => {
                      eprintln!("file: {} {}", key, e);
                      return None
                  }
              };
              let mut data: Vec<u8> = Vec::new();
              match file.read_to_end(&mut data) {
                  Ok(_) => Some(data),
                  Err(e) =>  {
                      eprintln!("file: {} {}", key, e);
                      return None
                  }
              }
          }
      }
  }
}

#[cfg(not(debug_assertions))]
fn generate_assets(ident: &syn::Ident, folder_path: String) -> quote::Tokens {
  use std::fs::File;
  use std::io::Read;
  use std::path::Path;
  use walkdir::WalkDir;
  let mut values = Vec::<Tokens>::new();
  for entry in WalkDir::new(folder_path.clone())
    .into_iter()
    .filter_map(|e| e.ok())
    .filter(|e| e.file_type().is_file())
  {
    println!("   \x1b[92mCompiling\x1b[0m {}", entry.path().display());
    let base = &folder_path.clone();
    let key = String::from(
      entry
        .path()
        .to_str()
        .expect("Path does not have a string representation"),
    ).replace(base, "");
    let mut file = File::open(&Path::new(&entry.path())).unwrap_or_else(|e| {
      panic!("could not open file -> {} {}", key, e);
    });
    let mut data: Vec<u8> = Vec::new();
    file.read_to_end(&mut data).unwrap_or_else(|e| {
      panic!("could not read file -> {} {}", key, e);
    });
    let value = quote!{
      #key => Some(vec!#data),
    };
    values.push(value);
  }
  quote!{
      impl #ident {
          pub fn get(file_path: &str) -> Option<Vec<u8>> {
              match file_path {
                  #(#values)*
                  _ => None,
              }
          }
      }
  }
}

fn help() {
  panic!("#[derive(RustEmbed)] should contain one attribute like this #[folder(\"examples/public/\")]");
}

fn impl_rust_embed(ast: &syn::DeriveInput) -> Tokens {
  match ast.body {
    Body::Enum(_) => help(),
    Body::Struct(ref data) => match data {
      &VariantData::Struct(_) => help(),
      _ => {}
    },
  };
  let ident = &ast.ident;
  if ast.attrs.len() == 0 || ast.attrs.len() > 1 {
    help();
  }
  let value = &ast.attrs[0].value;
  let items = match value {
    &MetaItem::List(ref attr_name, ref items) => {
      if attr_name == "folder" {
        items
      } else {
        panic!("#[derive(RustEmbed)] attribute name must be folder");
      }
    }
    _ => {
      panic!("#[derive(RustEmbed)] attribute name must be folder");
    }
  };
  let item = &items[0];
  let lit = match item {
    &NestedMetaItem::Literal(ref l) => l,
    _ => {
      panic!("Hello");
    }
  };
  let folder_path = match lit {
    &Lit::Str(ref val, _) => val.clone(),
    _ => {
      panic!("#[derive(RustEmbed)] attribute value must be a string literal");
    }
  };
  info!("folder: {}", folder_path);
  generate_assets(ident, folder_path)
}

#[proc_macro_derive(RustEmbed, attributes(folder))]
pub fn derive_input_object(input: TokenStream) -> TokenStream {
  let s = input.to_string();
  let ast = syn::parse_derive_input(&s).unwrap();
  let gen = impl_rust_embed(&ast);
  gen.parse().unwrap()
}
<|endoftext|>


<commit_before>//! A generic [Markov chain](https://en.wikipedia.org/wiki/Markov_chain) for almost any type. This
//! uses HashMaps internally, and so Eq and Hash are both required.
//!
//! # Examples
//!
//! ```
//! use markov::Chain;
//!
//! let mut chain = Chain::new();
//! chain.feed_str("I like cats and I like dogs.");
//! println!("{}", chain.generate_str());
//! ```
//!
//! ```
//! use markov::Chain;
//!
//! let mut chain = Chain::new();
//! chain.feed(vec![1u8, 2, 3, 5]).feed(vec![3u8, 9, 2]);
//! println!("{:?}", chain.generate());
//! ```
#![warn(missing_docs)]

extern crate rand;

use std::borrow::ToOwned;
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::fmt::Debug;
use std::fs::File;
use std::hash::Hash;
use std::io::{BufReader, Error, ErrorKind, Result};
use std::io::prelude::*;
use std::iter::Map;
use std::path::Path;
use std::rc::Rc;
use rand::{Rng, thread_rng};

/// The definition of all types that can be used in a Chain.
pub trait Chainable: Eq + Hash {}
impl<T> Chainable for T where T: Eq + Hash {}

/// A generic [Markov chain](https://en.wikipedia.org/wiki/Markov_chain) for almost any type. This
/// uses HashMaps internally, and so Eq and Hash are both required.
#[derive(PartialEq, Debug)]
pub struct Chain<T> where T: Chainable {
    map: HashMap<Vec<Option<Rc<T>>>, HashMap<Option<Rc<T>>, usize>>,
    order: usize,
}

impl<T> Chain<T> where T: Chainable {
    /// Constructs a new Markov chain.
    pub fn new() -> Chain<T> {
        Chain {
            map: {
                let mut map = HashMap::new();
                map.insert(vec!(None; 1), HashMap::new());
                map
            },
            order: 1,
        }
    }

    /// Choose a specific Markov chain order. The order is the number of previous tokens to use
    /// as the index into the map.
    pub fn order(&mut self, order: usize) -> &mut Chain<T> {
        assert!(order > 0);
        self.order = order;
        self.map.insert(vec!(None; self.order), HashMap::new());
        self
    }

    /// Determines whether or not the chain is empty. A chain is considered empty if nothing has
    /// been fed into it.
    pub fn is_empty(&self) -> bool {
        self.map[&vec!(None; self.order)].is_empty()
    }

    /// Feeds the chain a collection of tokens. This operation is O(n) where n is the number of
    /// tokens to be fed into the chain.
    pub fn feed(&mut self, tokens: Vec<T>) -> &mut Chain<T> {
        if tokens.len() == 0 { return self }
        let mut toks = vec!(None; self.order);
        toks.extend(tokens.into_iter().map(|token| {
            Some(Rc::new(token))
        }));
        toks.push(None);
        for p in toks.windows(self.order + 1) {
            if !self.map.contains_key(&p[0..self.order].to_vec()) {
                self.map.insert(p[0..self.order].to_vec(), HashMap::new());
            }
            self.map.get_mut(&p[0..self.order].to_vec()).unwrap().add(p[self.order].clone());
        }
        self
    }

    /// Generates a collection of tokens from the chain. This operation is O(mn) where m is the
    /// length of the generated collection, and n is the number of possible states from a given
    /// state.
    pub fn generate(&self) -> Vec<Rc<T>> {
        let mut ret = Vec::new();
        let mut curs = vec!(None; self.order);
        loop {
            let next = self.map[&curs].next();
            curs = curs[1..self.order].to_vec();
            curs.push(next.clone());
            if let Some(next) = next { ret.push(next) };
            if curs[self.order - 1].is_none() { break }
        }
        ret
    }

    /// Generates a collection of tokens from the chain, starting with the given token. This
    /// operation is O(mn) where m is the length of the generated collection, and n is the number
    /// of possible states from a given state. This returns an empty vector if the token is not
    /// found.
    pub fn generate_from_token(&self, token: T) -> Vec<Rc<T>> {
        let token = Rc::new(token);
        if !self.map.contains_key(&vec!(Some(token.clone()); self.order)) { return Vec::new() }
        let mut ret = vec![token.clone()];
        let mut curs = vec!(Some(token.clone()); self.order);
        loop {
            let next = self.map[&curs].next();
            curs = curs[1..self.order].to_vec();
            curs.push(next.clone());
            if let Some(next) = next { ret.push(next) };
            if curs[self.order - 1].is_none() { break }
        }
        ret
    }

    /// Produces an infinite iterator of generated token collections.
    pub fn iter(&self) -> InfiniteChainIterator<T> {
        InfiniteChainIterator { chain: self }
    }

    /// Produces an iterator for the specified number of generated token collections.
    pub fn iter_for(&self, size: usize) -> SizedChainIterator<T> {
        SizedChainIterator { chain: self, size: size }
    }
}

impl Chain<String> {
    /// Feeds a string of text into the chain.
    pub fn feed_str(&mut self, string: &str) -> &mut Chain<String> {
        self.feed(string.split(" ").map(|s| s.to_owned()).collect())
    }

    /// Feeds a properly formatted file into the chain. This file should be formatted such that
    /// each line is a new sentence. Punctuation may be included if it is desired.
    pub fn feed_file(&mut self, path: &Path) -> &mut Chain<String> {
        let reader = BufReader::new(File::open(path).unwrap());
        for line in reader.lines() {
            let line = line.unwrap();
            let words: Vec<_> = line.split(&[' ', '\t', '\n', '\r'][..])
                                    .filter(|word| !word.is_empty())
                                    .collect();
            self.feed(words.iter().map(|&s| s.to_owned()).collect());
        }
        self
    }

    /// Converts the output of generate(...) on a String chain to a single String.
    fn vec_to_string(vec: Vec<Rc<String>>) -> String {
        let mut ret = String::new();
        for s in vec.iter() {
            ret.push_str(&s);
            ret.push_str(" ");
        }
        let len = ret.len();
        if len > 0 {
            ret.truncate(len - 1);
        }
        ret
    }

    /// Generates a random string of text.
    pub fn generate_str(&self) -> String {
        Chain::vec_to_string(self.generate())
    }

    /// Generates a random string of text starting with the desired token. This returns an empty
    /// string if the token is not found.
    pub fn generate_str_from_token(&self, string: &str) -> String {
        Chain::vec_to_string(self.generate_from_token(string.to_owned()))
    }

    /// Produces an infinite iterator of generated strings.
    pub fn str_iter(&self) -> InfiniteChainStringIterator {
        let vec_to_string: fn(Vec<Rc<String>>) -> String = Chain::vec_to_string;
        self.iter().map(vec_to_string)
    }

    /// Produces a sized iterator of generated strings.
    pub fn str_iter_for(&self, size: usize) -> SizedChainStringIterator {
        let vec_to_string: fn(Vec<Rc<String>>) -> String = Chain::vec_to_string;
        self.iter_for(size).map(vec_to_string)
    }
}

/// A sized iterator over a Markov chain of strings.
pub type SizedChainStringIterator<'a> =
Map<SizedChainIterator<'a, String>, fn(Vec<Rc<String>>) -> String>;

/// A sized iterator over a Markov chain.
pub struct SizedChainIterator<'a, T: Chainable + 'a> {
    chain: &'a Chain<T>,
    size: usize,
}

impl<'a, T> Iterator for SizedChainIterator<'a, T> where T: Chainable + 'a {
    type Item = Vec<Rc<T>>;
    fn next(&mut self) -> Option<Vec<Rc<T>>> {
        if self.size > 0 {
            self.size -= 1;
            Some(self.chain.generate())
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.size, Some(self.size))
    }
}

/// An infinite iterator over a Markov chain of strings.
pub type InfiniteChainStringIterator<'a> =
Map<InfiniteChainIterator<'a, String>, fn(Vec<Rc<String>>) -> String>;

/// An infinite iterator over a Markov chain.
pub struct InfiniteChainIterator<'a, T: Chainable + 'a> {
    chain: &'a Chain<T>
}

impl<'a, T> Iterator for InfiniteChainIterator<'a, T> where T: Chainable + 'a {
    type Item = Vec<Rc<T>>;
    fn next(&mut self) -> Option<Vec<Rc<T>>> {
        Some(self.chain.generate())
    }
}

/// A collection of states for the Markov chain.
trait States<T: PartialEq> {
    /// Adds a state to this states collection.
    fn add(&mut self, token: Option<Rc<T>>);
    /// Gets the next state from this collection of states.
    fn next(&self) -> Option<Rc<T>>;
}

impl<T> States<T> for HashMap<Option<Rc<T>>, usize> where T: Chainable {
    fn add(&mut self, token: Option<Rc<T>>) {
        match self.entry(token) {
            Occupied(mut e) => *e.get_mut() += 1,
            Vacant(e) => { e.insert(1); },
        }
    }

    fn next(&self) -> Option<Rc<T>> {
        let mut sum = 0;
        for &value in self.values() {
            sum += value;
        }
        let mut rng = thread_rng();
        let cap = rng.gen_range(0, sum);
        sum = 0;
        for (key, &value) in self.iter() {
            sum += value;
            if sum > cap {
                return key.clone()
            }
        }
        unreachable!("The random number generator failed.")
    }
}

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

    #[test]
    fn new() {
        Chain::<u8>::new();
        Chain::<String>::new();
    }

    #[test]
    fn is_empty() {
        let mut chain = Chain::new();
        assert!(chain.is_empty());
        chain.feed(vec![1u8, 2, 3]);
        assert!(!chain.is_empty());
    }

    #[test]
    fn feed() {
        let mut chain = Chain::new();
        chain.feed(vec![3, 5, 10]).feed(vec![5, 12]);
    }

    #[test]
    fn generate() {
        let mut chain = Chain::new();
        chain.feed(vec![3u8, 5, 10]).feed(vec![5, 12]);
        let v = chain.generate().into_iter().map(|v| *v).collect();
        assert!([vec![3, 5, 10], vec![3, 5, 12], vec![5, 10], vec![5, 12]].contains(&v));
    }

    #[test]
    fn generate_for_higher_order() {
        let mut chain = Chain::new();
        chain.order(2);
        chain.feed(vec![3u8, 5, 10]).feed(vec![2, 3, 5, 12]);
        let v = chain.generate().into_iter().map(|v| *v).collect();
        assert!([vec![3, 5, 10], vec![3, 5, 12], vec![2, 3, 5, 10], vec![2, 3, 5, 12]].contains(&v));
    }

    #[test]
    fn generate_from_token() {
        let mut chain = Chain::new();
        chain.feed(vec![3u8, 5, 10]).feed(vec![5, 12]);
        let v = chain.generate_from_token(5).into_iter().map(|v| *v).collect();
        assert!([vec![5, 10], vec![5, 12]].contains(&v));
    }

    #[test]
    fn generate_from_unfound_token() {
        let mut chain = Chain::new();
        chain.feed(vec![3u8, 5, 10]).feed(vec![5, 12]);
        let v: Vec<_> = chain.generate_from_token(9).into_iter().map(|v| *v).collect();
        assert_eq!(v, vec![]);
    }

    #[test]
    fn iter() {
        let mut chain = Chain::new();
        chain.feed(vec![3u8, 5, 10]).feed(vec![5, 12]);
        assert_eq!(chain.iter().size_hint().1, None);
    }

    #[test]
    fn iter_for() {
        let mut chain = Chain::new();
        chain.feed(vec![3u8, 5, 10]).feed(vec![5, 12]);
        assert_eq!(chain.iter_for(5).collect::<Vec<_>>().len(), 5);
    }

    #[test]
    fn feed_str() {
        let mut chain = Chain::new();
        chain.feed_str("I like cats and dogs");
    }

    #[test]
    fn generate_str() {
        let mut chain = Chain::new();
        chain.feed_str("I like cats").feed_str("I hate cats");
        assert!(["I like cats", "I hate cats"].contains(&&chain.generate_str()[..]));
    }

    #[test]
    fn generate_str_from_token() {
        let mut chain = Chain::new();
        chain.feed_str("I like cats").feed_str("cats are cute");
        assert!(["cats", "cats are cute"].contains(&&chain.generate_str_from_token("cats")[..]));
    }

    #[test]
    fn generate_str_from_unfound_token() {
        let mut chain = Chain::new();
        chain.feed_str("I like cats").feed_str("cats are cute");
        assert_eq!(chain.generate_str_from_token("test"), "");
    }

    #[test]
    fn str_iter() {
        let mut chain = Chain::new();
        chain.feed_str("I like cats and I like dogs");
        assert_eq!(chain.str_iter().size_hint().1, None);
    }

    #[test]
    fn str_iter_for() {
        let mut chain = Chain::new();
        chain.feed_str("I like cats and I like dogs");
        assert_eq!(chain.str_iter_for(5).collect::<Vec<_>>().len(), 5);
    }
}
<commit_msg>Removed unused imports.<commit_after>//! A generic [Markov chain](https://en.wikipedia.org/wiki/Markov_chain) for almost any type. This
//! uses HashMaps internally, and so Eq and Hash are both required.
//!
//! # Examples
//!
//! ```
//! use markov::Chain;
//!
//! let mut chain = Chain::new();
//! chain.feed_str("I like cats and I like dogs.");
//! println!("{}", chain.generate_str());
//! ```
//!
//! ```
//! use markov::Chain;
//!
//! let mut chain = Chain::new();
//! chain.feed(vec![1u8, 2, 3, 5]).feed(vec![3u8, 9, 2]);
//! println!("{:?}", chain.generate());
//! ```
#![warn(missing_docs)]

extern crate rand;

use std::borrow::ToOwned;
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::fs::File;
use std::hash::Hash;
use std::io::BufReader;
use std::io::prelude::*;
use std::iter::Map;
use std::path::Path;
use std::rc::Rc;
use rand::{Rng, thread_rng};

/// The definition of all types that can be used in a Chain.
pub trait Chainable: Eq + Hash {}
impl<T> Chainable for T where T: Eq + Hash {}

/// A generic [Markov chain](https://en.wikipedia.org/wiki/Markov_chain) for almost any type. This
/// uses HashMaps internally, and so Eq and Hash are both required.
#[derive(PartialEq, Debug)]
pub struct Chain<T> where T: Chainable {
    map: HashMap<Vec<Option<Rc<T>>>, HashMap<Option<Rc<T>>, usize>>,
    order: usize,
}

impl<T> Chain<T> where T: Chainable {
    /// Constructs a new Markov chain.
    pub fn new() -> Chain<T> {
        Chain {
            map: {
                let mut map = HashMap::new();
                map.insert(vec!(None; 1), HashMap::new());
                map
            },
            order: 1,
        }
    }

    /// Choose a specific Markov chain order. The order is the number of previous tokens to use
    /// as the index into the map.
    pub fn order(&mut self, order: usize) -> &mut Chain<T> {
        assert!(order > 0);
        self.order = order;
        self.map.insert(vec!(None; self.order), HashMap::new());
        self
    }

    /// Determines whether or not the chain is empty. A chain is considered empty if nothing has
    /// been fed into it.
    pub fn is_empty(&self) -> bool {
        self.map[&vec!(None; self.order)].is_empty()
    }

    /// Feeds the chain a collection of tokens. This operation is O(n) where n is the number of
    /// tokens to be fed into the chain.
    pub fn feed(&mut self, tokens: Vec<T>) -> &mut Chain<T> {
        if tokens.len() == 0 { return self }
        let mut toks = vec!(None; self.order);
        toks.extend(tokens.into_iter().map(|token| {
            Some(Rc::new(token))
        }));
        toks.push(None);
        for p in toks.windows(self.order + 1) {
            if !self.map.contains_key(&p[0..self.order].to_vec()) {
                self.map.insert(p[0..self.order].to_vec(), HashMap::new());
            }
            self.map.get_mut(&p[0..self.order].to_vec()).unwrap().add(p[self.order].clone());
        }
        self
    }

    /// Generates a collection of tokens from the chain. This operation is O(mn) where m is the
    /// length of the generated collection, and n is the number of possible states from a given
    /// state.
    pub fn generate(&self) -> Vec<Rc<T>> {
        let mut ret = Vec::new();
        let mut curs = vec!(None; self.order);
        loop {
            let next = self.map[&curs].next();
            curs = curs[1..self.order].to_vec();
            curs.push(next.clone());
            if let Some(next) = next { ret.push(next) };
            if curs[self.order - 1].is_none() { break }
        }
        ret
    }

    /// Generates a collection of tokens from the chain, starting with the given token. This
    /// operation is O(mn) where m is the length of the generated collection, and n is the number
    /// of possible states from a given state. This returns an empty vector if the token is not
    /// found.
    pub fn generate_from_token(&self, token: T) -> Vec<Rc<T>> {
        let token = Rc::new(token);
        if !self.map.contains_key(&vec!(Some(token.clone()); self.order)) { return Vec::new() }
        let mut ret = vec![token.clone()];
        let mut curs = vec!(Some(token.clone()); self.order);
        loop {
            let next = self.map[&curs].next();
            curs = curs[1..self.order].to_vec();
            curs.push(next.clone());
            if let Some(next) = next { ret.push(next) };
            if curs[self.order - 1].is_none() { break }
        }
        ret
    }

    /// Produces an infinite iterator of generated token collections.
    pub fn iter(&self) -> InfiniteChainIterator<T> {
        InfiniteChainIterator { chain: self }
    }

    /// Produces an iterator for the specified number of generated token collections.
    pub fn iter_for(&self, size: usize) -> SizedChainIterator<T> {
        SizedChainIterator { chain: self, size: size }
    }
}

impl Chain<String> {
    /// Feeds a string of text into the chain.
    pub fn feed_str(&mut self, string: &str) -> &mut Chain<String> {
        self.feed(string.split(" ").map(|s| s.to_owned()).collect())
    }

    /// Feeds a properly formatted file into the chain. This file should be formatted such that
    /// each line is a new sentence. Punctuation may be included if it is desired.
    pub fn feed_file(&mut self, path: &Path) -> &mut Chain<String> {
        let reader = BufReader::new(File::open(path).unwrap());
        for line in reader.lines() {
            let line = line.unwrap();
            let words: Vec<_> = line.split(&[' ', '\t', '\n', '\r'][..])
                                    .filter(|word| !word.is_empty())
                                    .collect();
            self.feed(words.iter().map(|&s| s.to_owned()).collect());
        }
        self
    }

    /// Converts the output of generate(...) on a String chain to a single String.
    fn vec_to_string(vec: Vec<Rc<String>>) -> String {
        let mut ret = String::new();
        for s in vec.iter() {
            ret.push_str(&s);
            ret.push_str(" ");
        }
        let len = ret.len();
        if len > 0 {
            ret.truncate(len - 1);
        }
        ret
    }

    /// Generates a random string of text.
    pub fn generate_str(&self) -> String {
        Chain::vec_to_string(self.generate())
    }

    /// Generates a random string of text starting with the desired token. This returns an empty
    /// string if the token is not found.
    pub fn generate_str_from_token(&self, string: &str) -> String {
        Chain::vec_to_string(self.generate_from_token(string.to_owned()))
    }

    /// Produces an infinite iterator of generated strings.
    pub fn str_iter(&self) -> InfiniteChainStringIterator {
        let vec_to_string: fn(Vec<Rc<String>>) -> String = Chain::vec_to_string;
        self.iter().map(vec_to_string)
    }

    /// Produces a sized iterator of generated strings.
    pub fn str_iter_for(&self, size: usize) -> SizedChainStringIterator {
        let vec_to_string: fn(Vec<Rc<String>>) -> String = Chain::vec_to_string;
        self.iter_for(size).map(vec_to_string)
    }
}

/// A sized iterator over a Markov chain of strings.
pub type SizedChainStringIterator<'a> =
Map<SizedChainIterator<'a, String>, fn(Vec<Rc<String>>) -> String>;

/// A sized iterator over a Markov chain.
pub struct SizedChainIterator<'a, T: Chainable + 'a> {
    chain: &'a Chain<T>,
    size: usize,
}

impl<'a, T> Iterator for SizedChainIterator<'a, T> where T: Chainable + 'a {
    type Item = Vec<Rc<T>>;
    fn next(&mut self) -> Option<Vec<Rc<T>>> {
        if self.size > 0 {
            self.size -= 1;
            Some(self.chain.generate())
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.size, Some(self.size))
    }
}

/// An infinite iterator over a Markov chain of strings.
pub type InfiniteChainStringIterator<'a> =
Map<InfiniteChainIterator<'a, String>, fn(Vec<Rc<String>>) -> String>;

/// An infinite iterator over a Markov chain.
pub struct InfiniteChainIterator<'a, T: Chainable + 'a> {
    chain: &'a Chain<T>
}

impl<'a, T> Iterator for InfiniteChainIterator<'a, T> where T: Chainable + 'a {
    type Item = Vec<Rc<T>>;
    fn next(&mut self) -> Option<Vec<Rc<T>>> {
        Some(self.chain.generate())
    }
}

/// A collection of states for the Markov chain.
trait States<T: PartialEq> {
    /// Adds a state to this states collection.
    fn add(&mut self, token: Option<Rc<T>>);
    /// Gets the next state from this collection of states.
    fn next(&self) -> Option<Rc<T>>;
}

impl<T> States<T> for HashMap<Option<Rc<T>>, usize> where T: Chainable {
    fn add(&mut self, token: Option<Rc<T>>) {
        match self.entry(token) {
            Occupied(mut e) => *e.get_mut() += 1,
            Vacant(e) => { e.insert(1); },
        }
    }

    fn next(&self) -> Option<Rc<T>> {
        let mut sum = 0;
        for &value in self.values() {
            sum += value;
        }
        let mut rng = thread_rng();
        let cap = rng.gen_range(0, sum);
        sum = 0;
        for (key, &value) in self.iter() {
            sum += value;
            if sum > cap {
                return key.clone()
            }
        }
        unreachable!("The random number generator failed.")
    }
}

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

    #[test]
    fn new() {
        Chain::<u8>::new();
        Chain::<String>::new();
    }

    #[test]
    fn is_empty() {
        let mut chain = Chain::new();
        assert!(chain.is_empty());
        chain.feed(vec![1u8, 2, 3]);
        assert!(!chain.is_empty());
    }

    #[test]
    fn feed() {
        let mut chain = Chain::new();
        chain.feed(vec![3, 5, 10]).feed(vec![5, 12]);
    }

    #[test]
    fn generate() {
        let mut chain = Chain::new();
        chain.feed(vec![3u8, 5, 10]).feed(vec![5, 12]);
        let v = chain.generate().into_iter().map(|v| *v).collect();
        assert!([vec![3, 5, 10], vec![3, 5, 12], vec![5, 10], vec![5, 12]].contains(&v));
    }

    #[test]
    fn generate_for_higher_order() {
        let mut chain = Chain::new();
        chain.order(2);
        chain.feed(vec![3u8, 5, 10]).feed(vec![2, 3, 5, 12]);
        let v = chain.generate().into_iter().map(|v| *v).collect();
        assert!([vec![3, 5, 10], vec![3, 5, 12], vec![2, 3, 5, 10], vec![2, 3, 5, 12]].contains(&v));
    }

    #[test]
    fn generate_from_token() {
        let mut chain = Chain::new();
        chain.feed(vec![3u8, 5, 10]).feed(vec![5, 12]);
        let v = chain.generate_from_token(5).into_iter().map(|v| *v).collect();
        assert!([vec![5, 10], vec![5, 12]].contains(&v));
    }

    #[test]
    fn generate_from_unfound_token() {
        let mut chain = Chain::new();
        chain.feed(vec![3u8, 5, 10]).feed(vec![5, 12]);
        let v: Vec<_> = chain.generate_from_token(9).into_iter().map(|v| *v).collect();
        assert_eq!(v, vec![]);
    }

    #[test]
    fn iter() {
        let mut chain = Chain::new();
        chain.feed(vec![3u8, 5, 10]).feed(vec![5, 12]);
        assert_eq!(chain.iter().size_hint().1, None);
    }

    #[test]
    fn iter_for() {
        let mut chain = Chain::new();
        chain.feed(vec![3u8, 5, 10]).feed(vec![5, 12]);
        assert_eq!(chain.iter_for(5).collect::<Vec<_>>().len(), 5);
    }

    #[test]
    fn feed_str() {
        let mut chain = Chain::new();
        chain.feed_str("I like cats and dogs");
    }

    #[test]
    fn generate_str() {
        let mut chain = Chain::new();
        chain.feed_str("I like cats").feed_str("I hate cats");
        assert!(["I like cats", "I hate cats"].contains(&&chain.generate_str()[..]));
    }

    #[test]
    fn generate_str_from_token() {
        let mut chain = Chain::new();
        chain.feed_str("I like cats").feed_str("cats are cute");
        assert!(["cats", "cats are cute"].contains(&&chain.generate_str_from_token("cats")[..]));
    }

    #[test]
    fn generate_str_from_unfound_token() {
        let mut chain = Chain::new();
        chain.feed_str("I like cats").feed_str("cats are cute");
        assert_eq!(chain.generate_str_from_token("test"), "");
    }

    #[test]
    fn str_iter() {
        let mut chain = Chain::new();
        chain.feed_str("I like cats and I like dogs");
        assert_eq!(chain.str_iter().size_hint().1, None);
    }

    #[test]
    fn str_iter_for() {
        let mut chain = Chain::new();
        chain.feed_str("I like cats and I like dogs");
        assert_eq!(chain.str_iter_for(5).collect::<Vec<_>>().len(), 5);
    }
}
<|endoftext|>