<commit_before>use super::semigroup::{Semigroup, Product, All, Any};
use std::collections::*;
use std::hash::Hash;

pub trait Monoid: Semigroup {
    fn empty() -> Self;
}

/// Return this combined with itself `n` times.
pub fn combine_n<T>(o: &T, times: u32) -> T
    where T: Monoid + Semigroup + Clone
{
    if times == 0 {
        <T as Monoid>::empty()
    } else {
        super::semigroup::combine_n(o, times)
    }
}

/// Given a sequence of `xs`, combine them and return the total
///
/// ```
/// # use frust::monoid::*;
///
/// assert_eq!(combine_all(&vec![Some(1), Some(3)]), Some(4));
///
/// let empty_vec_opt_int:  Vec<Option<i32>> = Vec::new();
/// assert_eq!(combine_all(&empty_vec_opt_int), None);
///
/// let vec_of_some_strings = vec![Some("Hello".to_owned()), Some(" World".to_owned())];
/// assert_eq!(combine_all(&vec_of_some_strings), Some("Hello World".to_owned()));
/// ```
pub fn combine_all<T>(xs: &Vec<T>) -> T
    where T: Monoid + Semigroup + Clone
{
    let mut r = <T as Monoid>::empty();
    for i in xs {
        r = r.combine(i);
    }
    r
}

impl<T> Monoid for Option<T>
    where T: Semigroup + Clone
{
    fn empty() -> Self {
        None
    }
}

impl Monoid for String {
    fn empty() -> Self {
        String::new()
    }
}

impl<T> Monoid for Vec<T> where T: Clone {
    fn empty() -> Self {
        Vec::new()
    }
}

impl<T> Monoid for HashSet<T>
    where T: Hash + Eq + Clone
{
    fn empty() -> Self {
        HashSet::new()
    }
}

impl<K, V> Monoid for HashMap<K, V>
    where K: Eq + Hash + Clone,
          V: Semigroup + Clone
{
    fn empty() -> Self {
        HashMap::new()
    }
}

impl Monoid for All<bool> {
    fn empty() -> Self { All(true) }
}

impl Monoid for Any<bool> {
    fn empty() -> Self { Any(false) }
}

macro_rules! numeric_all_impls {
    ($($tr:ty)*) => {
      $(
        impl Monoid for All<$tr> {
            fn empty() -> Self { All(!0) }
        }
      )*
    }
}

numeric_all_impls! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 }

macro_rules! numeric_any_impls {
    ($($tr:ty)*) => {
      $(
        impl Monoid for Any<$tr> {
            fn empty() -> Self { Any(0) }
        }
      )*
    }
}

numeric_any_impls! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 }

macro_rules! numeric_monoid_imps {
  ($($zero: expr; $tr:ty),*) => {
    $(
      impl Monoid for $tr {
        fn empty() -> Self { $zero }
      }
    )*
  }
}

numeric_monoid_imps! {
    0; i8,
    0; i16,
    0; i32,
    0; i64,
    0; u8,
    0; u16,
    0; u32,
    0; u64,
    0; isize,
    0; usize,
    0f32; f32,
    0f64; f64
}

macro_rules! numeric_product_monoid_imps {
  ($($one: expr; $tr:ty),*) => {
    $(
      impl Monoid for Product<$tr> {
        fn empty() -> Self { Product($one) }
      }
    )*
  }
}

numeric_product_monoid_imps! {
    1; i8,
    1; i16,
    1; i32,
    1; i64,
    1; u8,
    1; u16,
    1; u32,
    1; u64,
    1; isize,
    1; usize,
    1f32; f32,
    1f64; f64
}

macro_rules! tuple_impls {
    () => {}; // no more

    (($idx:tt => $typ:ident), $( ($nidx:tt => $ntyp:ident), )*) => {
// Invoke recursive reversal of list that ends in the macro expansion implementation
// of the reversed list
//
        tuple_impls!([($idx, $typ);] $( ($nidx => $ntyp), )*);
        tuple_impls!($( ($nidx => $ntyp), )*); // invoke macro on tail
    };

// ([accumulatedList], listToReverse); recursively calls tuple_impls until the list to reverse
// + is empty (see next pattern)
//
    ([$(($accIdx: tt, $accTyp: ident);)+]  ($idx:tt => $typ:ident), $( ($nidx:tt => $ntyp:ident), )*) => {
      tuple_impls!([($idx, $typ); $(($accIdx, $accTyp); )*] $( ($nidx => $ntyp), ) *);
    };

// Finally expand into our implementation
    ([($idx:tt, $typ:ident); $( ($nidx:tt, $ntyp:ident); )*]) => {
        impl<$typ: Monoid, $( $ntyp: Monoid),*> Monoid for ($typ, $( $ntyp ),*) {
            fn empty() -> Self {
              (<$typ as Monoid>::empty(), $(<$ntyp as Monoid>::empty(), )*)
            }
        }
    }
}

tuple_impls! {
    (20 => U),
    (19 => T),
    (18 => S),
    (17 => R),
    (16 => Q),
    (15 => P),
    (14 => O),
    (13 => N),
    (12 => M),
    (11 => L),
    (10 => K),
    (9 => J),
    (8 => I),
    (7 => H),
    (6 => G),
    (5 => F),
    (4 => E),
    (3 => D),
    (2 => C),
    (1 => B),
    (0 => A),
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::super::semigroup::{Product, All, Any};
    use std::collections::*;

    #[test]
    fn test_combine_n() {
        assert_eq!(combine_n(&1, 0), 0);
        assert_eq!(combine_n(&2, 1), 2);
        assert_eq!(combine_n(&Some(2), 0), None);
        assert_eq!(combine_n(&Some(2), 4), Some(8));
    }

    #[test]
    fn test_combine_all_basic() {
        assert_eq!(combine_all(&vec![1, 2, 3]), 6);

        let empty_vec_int: Vec<i32> = Vec::new();
        assert_eq!(combine_all(&empty_vec_int), 0);

        let empty_vec_opt_int: Vec<Option<i32>> = Vec::new();
        assert_eq!(combine_all(&empty_vec_opt_int), None);

        let vec_of_some_strings = vec![Some("Hello".to_owned()), Some(" World".to_owned())];
        assert_eq!(combine_all(&vec_of_some_strings),
                   Some("Hello World".to_owned()));
    }

    #[test]
    fn test_combine_all_hashset() {
        let vec_of_no_hashes: Vec<HashSet<i32>> = Vec::new();
        assert_eq!(combine_all(&vec_of_no_hashes),
                   <HashSet<i32> as Monoid>::empty());

        let mut h1 = HashSet::new();
        h1.insert(1);
        let mut h2 = HashSet::new();
        h2.insert(2);
        let mut h3 = HashSet::new();
        h3.insert(3);
        let vec_of_hashes = vec![h1, h2, h3];
        let mut h_expected = HashSet::new();
        h_expected.insert(1);
        h_expected.insert(2);
        h_expected.insert(3);
        assert_eq!(combine_all(&vec_of_hashes), h_expected);
    }

    #[test]
    fn test_combine_all_hashmap() {
        let vec_of_no_hashmaps: Vec<HashMap<i32, String>> = Vec::new();
        assert_eq!(combine_all(&vec_of_no_hashmaps),
                   <HashMap<i32, String> as Monoid>::empty());

        let mut h1: HashMap<i32, String> = HashMap::new();
        h1.insert(1, String::from("Hello"));  // h1 is HashMap( 1 -> "Hello")
        let mut h2: HashMap<i32, String> = HashMap::new();
        h2.insert(1, String::from(" World"));
        h2.insert(2, String::from("Goodbye"));  // h2 is HashMap( 1 -> " World", 2 -> "Goodbye")
        let mut h3: HashMap<i32, String> = HashMap::new();
        h3.insert(3, String::from("Cruel World")); // h3 is HashMap( 3 -> "Cruel World")
        let vec_of_hashes = vec![h1, h2, h3];

        let mut h_expected: HashMap<i32, String> = HashMap::new();
        h_expected.insert(1, String::from("Hello World"));
        h_expected.insert(2, String::from("Goodbye"));
        h_expected.insert(3, String::from("Cruel World")); // h_expected is HashMap ( 1 -> "Hello World", 2 -> "Goodbye", 3 -> "Cruel World")
        assert_eq!(combine_all(&vec_of_hashes), h_expected);
    }

    #[test]
    fn test_combine_all_all(){
        let v1: Vec<All<i32>> = Vec::new();
        assert_eq!(combine_all(&v1), All(!0));
        assert_eq!(combine_all(&vec![All(3), All(7)]), All(3));

        assert_eq!(combine_all(&vec![All(false), All(false)]), All(false));
        assert_eq!(combine_all(&vec![All(true), All(true)]), All(true));
    }

    #[test]
    fn test_combine_all_any(){
        let v1: Vec<Any<i32>> = Vec::new();
        assert_eq!(combine_all(&v1), Any(0));
        assert_eq!(combine_all(&vec![Any(3), Any(8)]), Any(11));

        let v2 : Vec<Any<bool>> = Vec::new();
        assert_eq!(combine_all(&v2), Any(false));
        assert_eq!(combine_all(&vec![Any(false), Any(false)]), Any(false));
        assert_eq!(combine_all(&vec![Any(true), Any(false)]), Any(true));
    }

    #[test]
    fn test_combine_all_tuple() {
        let t1 = (1, 2.5f32, String::from("hi"), Some(3));
        let t2 = (1, 2.5f32, String::from(" world"), None);
        let t3 = (1, 2.5f32, String::from(", goodbye"), Some(10));
        let tuples = vec![t1, t2, t3];

        let expected = (3, 7.5f32, String::from("hi world, goodbye"), Some(13));
        assert_eq!(combine_all(&tuples), expected)
    }

    #[test]
    fn test_combine_all_product() {
        let v = vec![Product(2), Product(3), Product(4)];
        assert_eq!(combine_all(&v), Product(24))
    }

}
<commit_msg>Add a test for All bool<commit_after>use super::semigroup::{Semigroup, Product, All, Any};
use std::collections::*;
use std::hash::Hash;

pub trait Monoid: Semigroup {
    fn empty() -> Self;
}

/// Return this combined with itself `n` times.
pub fn combine_n<T>(o: &T, times: u32) -> T
    where T: Monoid + Semigroup + Clone
{
    if times == 0 {
        <T as Monoid>::empty()
    } else {
        super::semigroup::combine_n(o, times)
    }
}

/// Given a sequence of `xs`, combine them and return the total
///
/// ```
/// # use frust::monoid::*;
///
/// assert_eq!(combine_all(&vec![Some(1), Some(3)]), Some(4));
///
/// let empty_vec_opt_int:  Vec<Option<i32>> = Vec::new();
/// assert_eq!(combine_all(&empty_vec_opt_int), None);
///
/// let vec_of_some_strings = vec![Some("Hello".to_owned()), Some(" World".to_owned())];
/// assert_eq!(combine_all(&vec_of_some_strings), Some("Hello World".to_owned()));
/// ```
pub fn combine_all<T>(xs: &Vec<T>) -> T
    where T: Monoid + Semigroup + Clone
{
    let mut r = <T as Monoid>::empty();
    for i in xs {
        r = r.combine(i);
    }
    r
}

impl<T> Monoid for Option<T>
    where T: Semigroup + Clone
{
    fn empty() -> Self {
        None
    }
}

impl Monoid for String {
    fn empty() -> Self {
        String::new()
    }
}

impl<T> Monoid for Vec<T> where T: Clone {
    fn empty() -> Self {
        Vec::new()
    }
}

impl<T> Monoid for HashSet<T>
    where T: Hash + Eq + Clone
{
    fn empty() -> Self {
        HashSet::new()
    }
}

impl<K, V> Monoid for HashMap<K, V>
    where K: Eq + Hash + Clone,
          V: Semigroup + Clone
{
    fn empty() -> Self {
        HashMap::new()
    }
}

impl Monoid for All<bool> {
    fn empty() -> Self { All(true) }
}

impl Monoid for Any<bool> {
    fn empty() -> Self { Any(false) }
}

macro_rules! numeric_all_impls {
    ($($tr:ty)*) => {
      $(
        impl Monoid for All<$tr> {
            fn empty() -> Self { All(!0) }
        }
      )*
    }
}

numeric_all_impls! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 }

macro_rules! numeric_any_impls {
    ($($tr:ty)*) => {
      $(
        impl Monoid for Any<$tr> {
            fn empty() -> Self { Any(0) }
        }
      )*
    }
}

numeric_any_impls! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 }

macro_rules! numeric_monoid_imps {
  ($($zero: expr; $tr:ty),*) => {
    $(
      impl Monoid for $tr {
        fn empty() -> Self { $zero }
      }
    )*
  }
}

numeric_monoid_imps! {
    0; i8,
    0; i16,
    0; i32,
    0; i64,
    0; u8,
    0; u16,
    0; u32,
    0; u64,
    0; isize,
    0; usize,
    0f32; f32,
    0f64; f64
}

macro_rules! numeric_product_monoid_imps {
  ($($one: expr; $tr:ty),*) => {
    $(
      impl Monoid for Product<$tr> {
        fn empty() -> Self { Product($one) }
      }
    )*
  }
}

numeric_product_monoid_imps! {
    1; i8,
    1; i16,
    1; i32,
    1; i64,
    1; u8,
    1; u16,
    1; u32,
    1; u64,
    1; isize,
    1; usize,
    1f32; f32,
    1f64; f64
}

macro_rules! tuple_impls {
    () => {}; // no more

    (($idx:tt => $typ:ident), $( ($nidx:tt => $ntyp:ident), )*) => {
// Invoke recursive reversal of list that ends in the macro expansion implementation
// of the reversed list
//
        tuple_impls!([($idx, $typ);] $( ($nidx => $ntyp), )*);
        tuple_impls!($( ($nidx => $ntyp), )*); // invoke macro on tail
    };

// ([accumulatedList], listToReverse); recursively calls tuple_impls until the list to reverse
// + is empty (see next pattern)
//
    ([$(($accIdx: tt, $accTyp: ident);)+]  ($idx:tt => $typ:ident), $( ($nidx:tt => $ntyp:ident), )*) => {
      tuple_impls!([($idx, $typ); $(($accIdx, $accTyp); )*] $( ($nidx => $ntyp), ) *);
    };

// Finally expand into our implementation
    ([($idx:tt, $typ:ident); $( ($nidx:tt, $ntyp:ident); )*]) => {
        impl<$typ: Monoid, $( $ntyp: Monoid),*> Monoid for ($typ, $( $ntyp ),*) {
            fn empty() -> Self {
              (<$typ as Monoid>::empty(), $(<$ntyp as Monoid>::empty(), )*)
            }
        }
    }
}

tuple_impls! {
    (20 => U),
    (19 => T),
    (18 => S),
    (17 => R),
    (16 => Q),
    (15 => P),
    (14 => O),
    (13 => N),
    (12 => M),
    (11 => L),
    (10 => K),
    (9 => J),
    (8 => I),
    (7 => H),
    (6 => G),
    (5 => F),
    (4 => E),
    (3 => D),
    (2 => C),
    (1 => B),
    (0 => A),
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::super::semigroup::{Product, All, Any};
    use std::collections::*;

    #[test]
    fn test_combine_n() {
        assert_eq!(combine_n(&1, 0), 0);
        assert_eq!(combine_n(&2, 1), 2);
        assert_eq!(combine_n(&Some(2), 0), None);
        assert_eq!(combine_n(&Some(2), 4), Some(8));
    }

    #[test]
    fn test_combine_all_basic() {
        assert_eq!(combine_all(&vec![1, 2, 3]), 6);

        let empty_vec_int: Vec<i32> = Vec::new();
        assert_eq!(combine_all(&empty_vec_int), 0);

        let empty_vec_opt_int: Vec<Option<i32>> = Vec::new();
        assert_eq!(combine_all(&empty_vec_opt_int), None);

        let vec_of_some_strings = vec![Some("Hello".to_owned()), Some(" World".to_owned())];
        assert_eq!(combine_all(&vec_of_some_strings),
                   Some("Hello World".to_owned()));
    }

    #[test]
    fn test_combine_all_hashset() {
        let vec_of_no_hashes: Vec<HashSet<i32>> = Vec::new();
        assert_eq!(combine_all(&vec_of_no_hashes),
                   <HashSet<i32> as Monoid>::empty());

        let mut h1 = HashSet::new();
        h1.insert(1);
        let mut h2 = HashSet::new();
        h2.insert(2);
        let mut h3 = HashSet::new();
        h3.insert(3);
        let vec_of_hashes = vec![h1, h2, h3];
        let mut h_expected = HashSet::new();
        h_expected.insert(1);
        h_expected.insert(2);
        h_expected.insert(3);
        assert_eq!(combine_all(&vec_of_hashes), h_expected);
    }

    #[test]
    fn test_combine_all_hashmap() {
        let vec_of_no_hashmaps: Vec<HashMap<i32, String>> = Vec::new();
        assert_eq!(combine_all(&vec_of_no_hashmaps),
                   <HashMap<i32, String> as Monoid>::empty());

        let mut h1: HashMap<i32, String> = HashMap::new();
        h1.insert(1, String::from("Hello"));  // h1 is HashMap( 1 -> "Hello")
        let mut h2: HashMap<i32, String> = HashMap::new();
        h2.insert(1, String::from(" World"));
        h2.insert(2, String::from("Goodbye"));  // h2 is HashMap( 1 -> " World", 2 -> "Goodbye")
        let mut h3: HashMap<i32, String> = HashMap::new();
        h3.insert(3, String::from("Cruel World")); // h3 is HashMap( 3 -> "Cruel World")
        let vec_of_hashes = vec![h1, h2, h3];

        let mut h_expected: HashMap<i32, String> = HashMap::new();
        h_expected.insert(1, String::from("Hello World"));
        h_expected.insert(2, String::from("Goodbye"));
        h_expected.insert(3, String::from("Cruel World")); // h_expected is HashMap ( 1 -> "Hello World", 2 -> "Goodbye", 3 -> "Cruel World")
        assert_eq!(combine_all(&vec_of_hashes), h_expected);
    }

    #[test]
    fn test_combine_all_all(){
        let v1: Vec<All<i32>> = Vec::new();
        assert_eq!(combine_all(&v1), All(!0));
        assert_eq!(combine_all(&vec![All(3), All(7)]), All(3));

        let v2 : Vec<All<bool>> = Vec::new();
        assert_eq!(combine_all(&v2), All(true));
        assert_eq!(combine_all(&vec![All(false), All(false)]), All(false));
        assert_eq!(combine_all(&vec![All(true), All(true)]), All(true));
    }

    #[test]
    fn test_combine_all_any(){
        let v1: Vec<Any<i32>> = Vec::new();
        assert_eq!(combine_all(&v1), Any(0));
        assert_eq!(combine_all(&vec![Any(3), Any(8)]), Any(11));

        let v2 : Vec<Any<bool>> = Vec::new();
        assert_eq!(combine_all(&v2), Any(false));
        assert_eq!(combine_all(&vec![Any(false), Any(false)]), Any(false));
        assert_eq!(combine_all(&vec![Any(true), Any(false)]), Any(true));
    }

    #[test]
    fn test_combine_all_tuple() {
        let t1 = (1, 2.5f32, String::from("hi"), Some(3));
        let t2 = (1, 2.5f32, String::from(" world"), None);
        let t3 = (1, 2.5f32, String::from(", goodbye"), Some(10));
        let tuples = vec![t1, t2, t3];

        let expected = (3, 7.5f32, String::from("hi world, goodbye"), Some(13));
        assert_eq!(combine_all(&tuples), expected)
    }

    #[test]
    fn test_combine_all_product() {
        let v = vec![Product(2), Product(3), Product(4)];
        assert_eq!(combine_all(&v), Product(24))
    }

}
<|endoftext|>


<commit_before>use std::cmp::min;
use std::iter::IteratorExt;
use std::collections::{BTreeMap, RingBuf};
use std::string::ToString;
use serialize::json::Json;

use self::TemplateElement::{RawString, Expression, HelperExpression,
                            HTMLExpression, HelperBlock, Comment};

#[derive(PartialEq, Clone)]
pub struct Template {
    pub elements: Vec<TemplateElement>
}

#[derive(PartialEq, Debug)]
enum ParserState {
    Text,
    HtmlExpression,
    Comment,
    HelperStart,
    HelperEnd,
    Expression,
    Invalid
}

#[derive(PartialEq, Clone)]
pub struct Helper {
    name: String,
    params: Vec<String>,
    hash: BTreeMap<String, Json>,
    template: Option<Template>,
    inverse: Option<Template>,
    block: bool
}

impl Helper {
    pub fn name(&self) -> &String {
        &self.name
    }

    pub fn params(&self) -> &Vec<String> {
        &self.params
    }

    pub fn hash(&self) -> &BTreeMap<String, Json> {
        &self.hash
    }

    pub fn template(&self) -> Option<&Template> {
        match self.template {
            Some(ref t) => {
                Some(t)
            },
            None => None
        }
    }

    pub fn inverse(&self) -> Option<&Template> {
        match self.inverse {
            Some(ref t) => {
                Some(t)
            },
            None => None
        }
    }

    pub fn is_block(&self) -> bool {
        self.block
    }
}

impl ToString for Helper {
    fn to_string(&self) -> String {

        let mut buf = String::new();

        if self.block {
            buf.push_str(format!("{{{{#{}", self.name).as_slice());
        } else {
            buf.push_str(format!("{{{{{}", self.name).as_slice());
        }

        for p in self.params.iter() {
            buf.push_str(format!(" {}", p).as_slice());
        }

        for k in self.hash.keys() {
            buf.push_str(format!(" {}={}", k, self.hash.get(k).unwrap()).as_slice());
        }

        buf.push_str("}}");

        if self.block {
            let tpl = self.template();
            if tpl.is_some() {
                buf.push_str(tpl.unwrap().to_string().as_slice());
            }
            let ivs = self.inverse();
            if ivs.is_some() {
                buf.push_str("{{else}}");
                buf.push_str(ivs.unwrap().to_string().as_slice());
            }
            buf.push_str(format!("{{{{/{}}}}}", self.name).as_slice());
        }
        buf
    }
}

#[derive(Debug, Copy)]
pub struct TemplateError;

impl Helper {
    fn parse(source: String, block: bool) -> Result<Helper, TemplateError> {
        let mut tokens = source.split(|&: c: char| c.is_whitespace())
            .filter(|s: &&str| !(*s).is_empty());

        let name = tokens.next();
        match name {
            Some(n) => {
                let mut params: Vec<String> = Vec::new();
                let mut hash: BTreeMap<String, Json> = BTreeMap::new();

                for t in tokens {
                    if t.contains_char('=') {
                        let kv = t.split('=').collect::<Vec<&str>>();
                        hash.insert(kv.get(0).unwrap().to_string(),
                                    kv.get(1).unwrap().parse::<Json>().unwrap());
                    } else {
                        params.push(t.to_string());
                    }
                }

                Ok(Helper{
                    name: n.to_string(),
                    params: params,
                    hash: hash,
                    template: Option::None,
                    inverse: Option::None,
                    block: block
                })
            },
            None =>
                Err(TemplateError)
        }
    }
}

impl Template {
    pub fn compile(source: String) -> Result<Template, TemplateError> {
        let mut helper_stack: RingBuf<Helper> = RingBuf::new();
        let mut template_stack: RingBuf<Template> = RingBuf::new();
        template_stack.push_front(Template{ elements: Vec::new() });

        let mut buffer: String = String::new();
        let mut state = ParserState::Text;

        let mut c:usize = 0;
        let source_len = source.chars().count();
        while c < source_len {
            let slice = source.slice_chars(c, min(c+3, source_len));
            state = match slice {
                "{{{" | "{{!" | "{{#" | "{{/" => {
                    c += 2;
                    if !buffer.is_empty() {
                        let mut t = template_stack.front_mut().unwrap();
                        t.elements.push(RawString(buffer.clone()));
                        buffer.clear();
                    }
                    match slice {
                        "{{{" => ParserState::HtmlExpression,
                        "{{!" => ParserState::Comment,
                        "{{#" => ParserState::HelperStart,
                        "{{/" => {
                            let t = template_stack.pop_front().unwrap();
                            let h = helper_stack.front_mut().unwrap();
                            if h.template.is_some() {
                                h.inverse = Some(t);
                            } else {
                                h.template = Some(t);
                            }
                            ParserState::HelperEnd
                        },
                        _ => ParserState::Invalid
                    }
                },
                "}}}" => {
                    c += 2;
                    let mut t = template_stack.front_mut().unwrap();
                    t.elements.push(HTMLExpression(
                        buffer.clone().trim_matches(' ').to_string()));
                    buffer.clear();
                    ParserState::Text
                },
                _ => {
                    match if slice.chars().count() > 2 { slice.slice_chars(0, 2) } else { slice } {
                        "{{" => {
                            c += 1;
                            if !buffer.is_empty() {
                                let mut t = template_stack.front_mut().unwrap();
                                t.elements.push(RawString(buffer.clone()));
                                buffer.clear();
                            }
                            ParserState::Expression
                        },
                        "}}" => {
                            c += 1;
                            match state {
                                ParserState::Expression => {
                                    if !buffer.is_empty() {
                                        // {{else}} within a helper block
                                        if buffer.trim_matches(' ') == "else" {
                                            buffer.clear(); // drop else
                                            let t = template_stack.pop_front().unwrap();
                                            let h = helper_stack.front_mut().unwrap();
                                            h.template = Some(t);
                                            template_stack.push_front(Template{ elements: Vec::new() });
                                            ParserState::Text
                                        } else if buffer.contains_char(' ') {
                                            //inline helper
                                            match Helper::parse(buffer.clone(), false){
                                                Ok(helper) => {
                                                    let mut t = template_stack.front_mut().unwrap();
                                                    t.elements.push(HelperExpression(helper));
                                                    buffer.clear();
                                                    ParserState::Text
                                                },
                                                Err(_) => ParserState::Invalid
                                            }
                                        } else {
                                            let mut t = template_stack.front_mut().unwrap();
                                            t.elements.push(Expression(
                                                buffer.clone().trim_matches(' ').to_string()));
                                            buffer.clear();
                                            ParserState::Text
                                        }

                                    } else {
                                        ParserState::Invalid
                                    }
                                },
                                ParserState::Comment => {
                                    let mut t = template_stack.front_mut().unwrap();
                                    t.elements.push(Comment(buffer.clone()));
                                    buffer.clear();
                                    ParserState::Text
                                },
                                ParserState::HelperStart => {
                                    match Helper::parse(buffer.clone(), true) {
                                        Ok(helper) => {
                                            helper_stack.push_front(helper);
                                            template_stack.push_front(Template{ elements: Vec::new() });

                                            buffer.clear();
                                            ParserState::Text
                                        },
                                        Err(_) => ParserState::Invalid
                                    }
                                },
                                ParserState::HelperEnd => {
                                    let name = buffer.trim_matches(' ').to_string();
                                    if name == helper_stack.front().unwrap().name {
                                        let h = helper_stack.pop_front().unwrap();
                                        let mut t = template_stack.front_mut().unwrap();
                                        t.elements.push(HelperBlock(h));
                                        buffer.clear();
                                        ParserState::Text
                                    } else {
                                        ParserState::Invalid
                                    }
                                },
                                _ => ParserState::Invalid
                            }
                        },
                        _ => {
                            buffer.push(slice.char_at(0));
                            state
                        }
                    }
                }
            };
            if state == ParserState::Invalid {
                return Err(TemplateError);
            }
            c += 1;
        }

        if !buffer.is_empty() {
            let mut t = template_stack.front_mut().unwrap();
            t.elements.push(TemplateElement::RawString(buffer.clone()));
        }

        if !helper_stack.is_empty() {
            return Err(TemplateError);
        }

        return Ok(template_stack.pop_front().unwrap());
    }
}

impl ToString for Template {
    fn to_string(&self) -> String {
        let mut buf = String::new();
        for v in self.elements.iter() {
            buf.push_str(v.to_string().as_slice());
        }
        buf
    }
}

#[derive(PartialEq, Clone)]
pub enum TemplateElement {
    RawString(String),
    Expression(String),
    HTMLExpression(String),
    HelperExpression(Helper),
    HelperBlock(Helper),
    Comment(String),
}

impl ToString for TemplateElement {
    fn to_string(&self) -> String {
        match *self {
            RawString(ref v) => {
                v.clone()
            },
            Expression(ref v) => {
                // {{ escape to {
                format!("{{{{{}}}}}", v)
            },
            HTMLExpression(ref v) => {
                format!("{{{{{{{}}}}}}}", v)
            },
            HelperExpression(ref helper) => {
                helper.to_string()
            }
            HelperBlock(ref helper) => {
                helper.to_string()
            }
            Comment(ref v) => {
                format!("{{!{}}}", v)
            }
        }
    }
}

#[test]
fn test_parse_helper_start_tag() {
    let source = "if not name compare=1".to_string();
    let h = Helper::parse(source, true).ok().unwrap();

    assert_eq!(h.name, "if".to_string());
    assert_eq!(h.params, vec::<String>!["not".to_string(), "name".to_string()]);

    let key = "compare".to_string();
    let value = h.hash.get(&key).unwrap();
    assert_eq!(value.as_u64().unwrap(), 1u64);
}

#[test]
fn test_parse_template() {
    let source = "
{{title}} 你好
 {{{content}}}
{{#if date}}
good
{{else}}
bad
{{/if}}{{foo bar}}";
    let t = Template::compile(source.to_string()).ok().unwrap();

    assert_eq!(t.elements.len(), 8);
    assert_eq!((*t.elements.get(0).unwrap()).to_string(), "
".to_string());
    assert_eq!((*t.elements.get(1).unwrap()).to_string(),
               Expression("title".to_string()).to_string());

    assert_eq!((*t.elements.get(3).unwrap()).to_string(), "{{{content}}}".to_string());

    match *t.elements.get(5).unwrap() {
        HelperBlock(ref h) => {
            assert_eq!(h.name, "if".to_string());
            assert_eq!(h.params.len(), 1);
            assert_eq!(h.template.as_ref().unwrap().elements.len(), 1);
        },
        _ => {
            panic!("Helper expected here.");
        }
    };

    match *t.elements.get(7).unwrap() {
        HelperExpression(ref h) => {
            assert_eq!(h.name, "foo".to_string());
            assert_eq!(h.params.len(), 1);
            assert_eq!(*(h.params.get(0).unwrap()), "bar".to_string());
        },
        _ => {
            panic!("Helper expression here");
        }
    };
}

#[test]
fn test_helper_to_string() {
    let source = "{{#ifequals name compare=\"hello\"}}hello{{else}}good{{/ifequals}}".to_string();

    let t = Template::compile(source.to_string()).ok().unwrap();

    assert_eq!(t.elements.len(), 1);
    assert_eq!(t.elements.get(0).unwrap().to_string(), source);
}

#[test]
fn test_parse_error() {
    let source = "{{#ifequals name compare=\"hello\"}}hello{{else}}good".to_string();

    let t = Template::compile(source.to_string());

    assert!(t.is_err());
}
<commit_msg>(feat) support ^ as else in block helper [#11]<commit_after>use std::cmp::min;
use std::iter::IteratorExt;
use std::collections::{BTreeMap, RingBuf};
use std::string::ToString;
use serialize::json::Json;

use self::TemplateElement::{RawString, Expression, HelperExpression,
                            HTMLExpression, HelperBlock, Comment};

#[derive(PartialEq, Clone)]
pub struct Template {
    pub elements: Vec<TemplateElement>
}

#[derive(PartialEq, Debug)]
enum ParserState {
    Text,
    HtmlExpression,
    Comment,
    HelperStart,
    HelperEnd,
    Expression,
    Invalid
}

#[derive(PartialEq, Clone)]
pub struct Helper {
    name: String,
    params: Vec<String>,
    hash: BTreeMap<String, Json>,
    template: Option<Template>,
    inverse: Option<Template>,
    block: bool
}

impl Helper {
    pub fn name(&self) -> &String {
        &self.name
    }

    pub fn params(&self) -> &Vec<String> {
        &self.params
    }

    pub fn hash(&self) -> &BTreeMap<String, Json> {
        &self.hash
    }

    pub fn template(&self) -> Option<&Template> {
        match self.template {
            Some(ref t) => {
                Some(t)
            },
            None => None
        }
    }

    pub fn inverse(&self) -> Option<&Template> {
        match self.inverse {
            Some(ref t) => {
                Some(t)
            },
            None => None
        }
    }

    pub fn is_block(&self) -> bool {
        self.block
    }
}

impl ToString for Helper {
    fn to_string(&self) -> String {

        let mut buf = String::new();

        if self.block {
            buf.push_str(format!("{{{{#{}", self.name).as_slice());
        } else {
            buf.push_str(format!("{{{{{}", self.name).as_slice());
        }

        for p in self.params.iter() {
            buf.push_str(format!(" {}", p).as_slice());
        }

        for k in self.hash.keys() {
            buf.push_str(format!(" {}={}", k, self.hash.get(k).unwrap()).as_slice());
        }

        buf.push_str("}}");

        if self.block {
            let tpl = self.template();
            if tpl.is_some() {
                buf.push_str(tpl.unwrap().to_string().as_slice());
            }
            let ivs = self.inverse();
            if ivs.is_some() {
                buf.push_str("{{else}}");
                buf.push_str(ivs.unwrap().to_string().as_slice());
            }
            buf.push_str(format!("{{{{/{}}}}}", self.name).as_slice());
        }
        buf
    }
}

#[derive(Debug, Copy)]
pub struct TemplateError;

impl Helper {
    fn parse(source: String, block: bool) -> Result<Helper, TemplateError> {
        let mut tokens = source.split(|&: c: char| c.is_whitespace())
            .filter(|s: &&str| !(*s).is_empty());

        let name = tokens.next();
        match name {
            Some(n) => {
                let mut params: Vec<String> = Vec::new();
                let mut hash: BTreeMap<String, Json> = BTreeMap::new();

                for t in tokens {
                    if t.contains_char('=') {
                        let kv = t.split('=').collect::<Vec<&str>>();
                        hash.insert(kv.get(0).unwrap().to_string(),
                                    kv.get(1).unwrap().parse::<Json>().unwrap());
                    } else {
                        params.push(t.to_string());
                    }
                }

                Ok(Helper{
                    name: n.to_string(),
                    params: params,
                    hash: hash,
                    template: Option::None,
                    inverse: Option::None,
                    block: block
                })
            },
            None =>
                Err(TemplateError)
        }
    }
}

impl Template {
    pub fn compile(source: String) -> Result<Template, TemplateError> {
        let mut helper_stack: RingBuf<Helper> = RingBuf::new();
        let mut template_stack: RingBuf<Template> = RingBuf::new();
        template_stack.push_front(Template{ elements: Vec::new() });

        let mut buffer: String = String::new();
        let mut state = ParserState::Text;

        let mut c:usize = 0;
        let source_len = source.chars().count();
        while c < source_len {
            let slice = source.slice_chars(c, min(c+3, source_len));
            state = match slice {
                "{{{" | "{{!" | "{{#" | "{{/" => {
                    c += 2;
                    if !buffer.is_empty() {
                        let mut t = template_stack.front_mut().unwrap();
                        t.elements.push(RawString(buffer.clone()));
                        buffer.clear();
                    }
                    match slice {
                        "{{{" => ParserState::HtmlExpression,
                        "{{!" => ParserState::Comment,
                        "{{#" => ParserState::HelperStart,
                        "{{/" => {
                            let t = template_stack.pop_front().unwrap();
                            let h = helper_stack.front_mut().unwrap();
                            if h.template.is_some() {
                                h.inverse = Some(t);
                            } else {
                                h.template = Some(t);
                            }
                            ParserState::HelperEnd
                        },
                        _ => ParserState::Invalid
                    }
                },
                "}}}" => {
                    c += 2;
                    let mut t = template_stack.front_mut().unwrap();
                    t.elements.push(HTMLExpression(
                        buffer.clone().trim_matches(' ').to_string()));
                    buffer.clear();
                    ParserState::Text
                },
                _ => {
                    match if slice.chars().count() > 2 { slice.slice_chars(0, 2) } else { slice } {
                        "{{" => {
                            c += 1;
                            if !buffer.is_empty() {
                                let mut t = template_stack.front_mut().unwrap();
                                t.elements.push(RawString(buffer.clone()));
                                buffer.clear();
                            }
                            ParserState::Expression
                        },
                        "}}" => {
                            c += 1;
                            match state {
                                ParserState::Expression => {
                                    if !buffer.is_empty() {
                                        // {{else}} or {{^}} within a helper block
                                        if buffer.trim() == "else" || buffer.trim() == "^" {
                                            buffer.clear(); // drop else
                                            let t = template_stack.pop_front().unwrap();
                                            let h = helper_stack.front_mut().unwrap();
                                            h.template = Some(t);
                                            template_stack.push_front(Template{ elements: Vec::new() });
                                            ParserState::Text
                                        } else if buffer.contains_char(' ') {
                                            //inline helper
                                            match Helper::parse(buffer.clone(), false){
                                                Ok(helper) => {
                                                    let mut t = template_stack.front_mut().unwrap();
                                                    t.elements.push(HelperExpression(helper));
                                                    buffer.clear();
                                                    ParserState::Text
                                                },
                                                Err(_) => ParserState::Invalid
                                            }
                                        } else {
                                            let mut t = template_stack.front_mut().unwrap();
                                            t.elements.push(Expression(
                                                buffer.clone().trim_matches(' ').to_string()));
                                            buffer.clear();
                                            ParserState::Text
                                        }

                                    } else {
                                        ParserState::Invalid
                                    }
                                },
                                ParserState::Comment => {
                                    let mut t = template_stack.front_mut().unwrap();
                                    t.elements.push(Comment(buffer.clone()));
                                    buffer.clear();
                                    ParserState::Text
                                },
                                ParserState::HelperStart => {
                                    match Helper::parse(buffer.clone(), true) {
                                        Ok(helper) => {
                                            helper_stack.push_front(helper);
                                            template_stack.push_front(Template{ elements: Vec::new() });

                                            buffer.clear();
                                            ParserState::Text
                                        },
                                        Err(_) => ParserState::Invalid
                                    }
                                },
                                ParserState::HelperEnd => {
                                    let name = buffer.trim_matches(' ').to_string();
                                    if name == helper_stack.front().unwrap().name {
                                        let h = helper_stack.pop_front().unwrap();
                                        let mut t = template_stack.front_mut().unwrap();
                                        t.elements.push(HelperBlock(h));
                                        buffer.clear();
                                        ParserState::Text
                                    } else {
                                        ParserState::Invalid
                                    }
                                },
                                _ => ParserState::Invalid
                            }
                        },
                        _ => {
                            buffer.push(slice.char_at(0));
                            state
                        }
                    }
                }
            };
            if state == ParserState::Invalid {
                return Err(TemplateError);
            }
            c += 1;
        }

        if !buffer.is_empty() {
            let mut t = template_stack.front_mut().unwrap();
            t.elements.push(TemplateElement::RawString(buffer.clone()));
        }

        if !helper_stack.is_empty() {
            return Err(TemplateError);
        }

        return Ok(template_stack.pop_front().unwrap());
    }
}

impl ToString for Template {
    fn to_string(&self) -> String {
        let mut buf = String::new();
        for v in self.elements.iter() {
            buf.push_str(v.to_string().as_slice());
        }
        buf
    }
}

#[derive(PartialEq, Clone)]
pub enum TemplateElement {
    RawString(String),
    Expression(String),
    HTMLExpression(String),
    HelperExpression(Helper),
    HelperBlock(Helper),
    Comment(String),
}

impl ToString for TemplateElement {
    fn to_string(&self) -> String {
        match *self {
            RawString(ref v) => {
                v.clone()
            },
            Expression(ref v) => {
                // {{ escape to {
                format!("{{{{{}}}}}", v)
            },
            HTMLExpression(ref v) => {
                format!("{{{{{{{}}}}}}}", v)
            },
            HelperExpression(ref helper) => {
                helper.to_string()
            }
            HelperBlock(ref helper) => {
                helper.to_string()
            }
            Comment(ref v) => {
                format!("{{!{}}}", v)
            }
        }
    }
}

#[test]
fn test_parse_helper_start_tag() {
    let source = "if not name compare=1".to_string();
    let h = Helper::parse(source, true).ok().unwrap();

    assert_eq!(h.name, "if".to_string());
    assert_eq!(h.params, vec::<String>!["not".to_string(), "name".to_string()]);

    let key = "compare".to_string();
    let value = h.hash.get(&key).unwrap();
    assert_eq!(value.as_u64().unwrap(), 1u64);
}

#[test]
fn test_parse_template() {
    let source = "
{{title}} 你好
 {{{content}}}
{{#if date}}
good
{{else}}
bad
{{/if}}{{foo bar}}{{#unless true}}kitkat{{^}}lollipop{{/unless}}";
    let t = Template::compile(source.to_string()).ok().unwrap();

    assert_eq!(t.elements.len(), 9);
    assert_eq!((*t.elements.get(0).unwrap()).to_string(), "
".to_string());
    assert_eq!((*t.elements.get(1).unwrap()).to_string(),
               Expression("title".to_string()).to_string());

    assert_eq!((*t.elements.get(3).unwrap()).to_string(), "{{{content}}}".to_string());

    match *t.elements.get(5).unwrap() {
        HelperBlock(ref h) => {
            assert_eq!(h.name, "if".to_string());
            assert_eq!(h.params.len(), 1);
            assert_eq!(h.template.as_ref().unwrap().elements.len(), 1);
        },
        _ => {
            panic!("Helper expected here.");
        }
    };

    match *t.elements.get(7).unwrap() {
        HelperExpression(ref h) => {
            assert_eq!(h.name, "foo".to_string());
            assert_eq!(h.params.len(), 1);
            assert_eq!(*(h.params.get(0).unwrap()), "bar".to_string());
        },
        _ => {
            panic!("Helper expression here");
        }
    };

    match *t.elements.get(8).unwrap() {
        HelperBlock(ref h) => {
            assert_eq!(h.name, "unless".to_string());
            assert_eq!(h.params.len(), 1);
            assert_eq!(h.inverse.as_ref().unwrap().elements.len(), 1);
        },
        _ => {
            panic!("Helper expression here");
        }
    };

}

#[test]
fn test_helper_to_string() {
    let source = "{{#ifequals name compare=\"hello\"}}hello{{else}}good{{/ifequals}}".to_string();

    let t = Template::compile(source.to_string()).ok().unwrap();

    assert_eq!(t.elements.len(), 1);
    assert_eq!(t.elements.get(0).unwrap().to_string(), source);
}

#[test]
fn test_parse_error() {
    let source = "{{#ifequals name compare=\"hello\"}}hello{{else}}good".to_string();

    let t = Template::compile(source.to_string());

    assert!(t.is_err());
}
<|endoftext|>


<commit_before>// Tests for calx_ecs are off-crate because the Ecs macro expects to
// find Ecs stuff with an absolute crate path.

#[derive(Clone, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable)]
struct Desc {
    name: String,
    icon: usize,
}

#[derive(Clone, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable)]
struct Pos {
    x: i32,
    y: i32,
}

Ecs! {
    desc: ::test_ecs::Desc,
    pos: ::test_ecs::Pos,
}

#[test]
fn test_ecs() {
    let mut ecs = Ecs::new();

    let e1 = ecs.make();
    assert!(ecs.contains(e1));

    assert!(!ecs.pos.contains(e1));
    ecs.pos.insert(e1, Pos { x: 3, y: 4 });
    assert_eq!(ecs.pos[e1], Pos { x: 3, y: 4 });

    Desc { name: "Orc".to_string(), icon: 8 }.add_to(&mut ecs, e1);
    assert_eq!(ecs.desc[e1].name, "Orc");

    ecs.remove(e1);
    assert!(!ecs.pos.contains(e1));
    assert!(!ecs.contains(e1));

    let e2 = ecs.make();
    assert!(e2 != e1);

    assert_eq!(Desc::type_num(), 0);
    assert_eq!(Pos::type_num(), 1);
}
<commit_msg>Fix unit test<commit_after>// Tests for calx_ecs are off-crate because the Ecs macro expects to
// find Ecs stuff with an absolute crate path.

#[derive(Clone, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable)]
pub struct Desc {
    name: String,
    icon: usize,
}

#[derive(Clone, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable)]
pub struct Pos {
    x: i32,
    y: i32,
}

Ecs! {
    desc: ::test_ecs::Desc,
    pos: ::test_ecs::Pos,
}

#[test]
fn test_ecs() {
    let mut ecs = Ecs::new();

    let e1 = ecs.make();
    assert!(ecs.contains(e1));

    assert!(!ecs.pos.contains(e1));
    ecs.pos.insert(e1, Pos { x: 3, y: 4 });
    assert_eq!(ecs.pos[e1], Pos { x: 3, y: 4 });

    Desc { name: "Orc".to_string(), icon: 8 }.add_to(&mut ecs, e1);
    assert_eq!(ecs.desc[e1].name, "Orc");

    ecs.remove(e1);
    assert!(!ecs.pos.contains(e1));
    assert!(!ecs.contains(e1));

    let e2 = ecs.make();
    assert!(e2 != e1);
}
<|endoftext|>


<commit_before>use std::num::FloatMath;
use color::Color;
use dimensions::Dimensions;
use graphics::{
    AddColor,
    AddLine,
    AddRoundBorder,
    Context,
    Draw,
};
use label;
use label::FontSize;
use mouse_state::{
    MouseState,
    MouseButtonState
};
use opengl_graphics::Gl;
use input::keyboard::{
    Backspace,
    Left,
    Right,
    Return,
};
use point::Point;
use rectangle;
use std::num::Float;
use time::precise_time_s;
use ui_context::{
    UIID,
    UiContext,
};
use vecmath::{
    vec2_add,
    vec2_sub,
};
use widget::Widget::TextBox;
use std::cmp;

pub type Idx = uint;
pub type CursorX = f64;

/// Represents the state of the text_box widget.
#[deriving(Show, PartialEq, Clone)]
pub struct State(DrawState, Capturing);

/// Represents the next tier of state.
#[deriving(Show, PartialEq, Clone)]
pub enum DrawState {
    Normal,
    Highlighted(Element),
    Clicked(Element),
}

/// Whether the textbox is currently captured or not.
#[deriving(Show, PartialEq, Clone)]
pub enum Capturing {
    Uncaptured,
    Captured(Idx, CursorX),
}

/// Represents an element of the TextBox widget.
#[deriving(Show, PartialEq, Clone)]
pub enum Element {
    Nill,
    Rect,
    Text(Idx, CursorX),
}

impl State {
    /// Return the associated Rectangle state.
    fn as_rectangle_state(&self) -> rectangle::State {
        match self {
            &State(state, capturing) => match capturing {
                Capturing::Captured(_, _) => rectangle::State::Normal,
                Capturing::Uncaptured => match state {
                    DrawState::Normal => rectangle::State::Normal,
                    DrawState::Highlighted(_) => rectangle::State::Highlighted,
                    DrawState::Clicked(_) => rectangle::State::Clicked,
                },
            }
        }
    }
}

widget_fns!(TextBox, State, TextBox(State(DrawState::Normal, Capturing::Uncaptured)))

static TEXT_PADDING: f64 = 5f64;

/// Check if cursor is over the pad and if so, which
fn over_elem(uic: &mut UiContext,
             pos: Point,
             mouse_pos: Point,
             rect_dim: Dimensions,
             pad_pos: Point,
             pad_dim: Dimensions,
             text_pos: Point,
             text_w: f64,
             font_size: FontSize,
             text: &str) -> Element {
    match rectangle::is_over(pos, mouse_pos, rect_dim) {
        false => Element::Nill,
        true => match rectangle::is_over(pad_pos, mouse_pos, pad_dim) {
            false => Element::Rect,
            true => {
                let (idx, cursor_x) = closest_idx(uic, mouse_pos, text_pos[0], text_w, font_size, text);
                Element::Text(idx, cursor_x)
            },
        },
    }
}

/// Check which character is closest to the mouse cursor.
fn closest_idx(uic: &mut UiContext,
               mouse_pos: Point,
               text_x: f64,
               text_w: f64,
               font_size: FontSize,
               text: &str) -> (Idx, f64) {
    if mouse_pos[0] <= text_x { return (0u, text_x) }
    let mut x = text_x;
    let mut prev_x = x;
    let mut left_x = text_x;
    for (i, ch) in text.chars().enumerate() {
        let character = uic.get_character(font_size, ch);
        let char_w = (character.glyph.advance().x >> 16) as f64;
        x += char_w;
        let right_x = prev_x + char_w / 2.0;
        if mouse_pos[0] > left_x && mouse_pos[0] < right_x { return (i, prev_x) }
        prev_x = x;
        left_x = right_x;
    }
    (text.len(), text_x + text_w)
}

/// Check and return the current state of the TextBox.
fn get_new_state(over_elem: Element,
                 prev_box_state: State,
                 mouse: MouseState) -> State {
    match prev_box_state {
        State(prev, Capturing::Uncaptured) => {
            match (over_elem, prev, mouse.left) {
                (_, DrawState::Normal, MouseButtonState::Down) => State(DrawState::Normal, Capturing::Uncaptured),
                (Element::Nill, DrawState::Normal, MouseButtonState::Up) | (Element::Nill, DrawState::Highlighted(_), MouseButtonState::Up) => State(DrawState::Normal, Capturing::Uncaptured),
                (_, DrawState::Normal, MouseButtonState::Up) | (_, DrawState::Highlighted(_), MouseButtonState::Up) => State(DrawState::Highlighted(over_elem), Capturing::Uncaptured),
                (_, DrawState::Highlighted(p_elem), MouseButtonState::Down) | (_, DrawState::Clicked(p_elem), MouseButtonState::Down) =>
                    State(DrawState::Clicked(p_elem), Capturing::Uncaptured),
                (Element::Text(idx, x), DrawState::Clicked(Element::Text(_, _)), MouseButtonState::Up) => State(DrawState::Highlighted(over_elem), Capturing::Captured(idx, x)),
                (Element::Nill, _, _) => State(DrawState::Normal, Capturing::Uncaptured),
                _ => prev_box_state,
            }
        },
        State(prev, Capturing::Captured(p_idx, p_x)) => {
            match (over_elem, prev, mouse.left) {
                (Element::Nill, DrawState::Clicked(Element::Nill), MouseButtonState::Up) => State(DrawState::Normal, Capturing::Uncaptured),
                (Element::Text(idx, x), DrawState::Clicked(Element::Text(_, _)), MouseButtonState::Up) => State(DrawState::Highlighted(over_elem), Capturing::Captured(idx, x)),
                (_, DrawState::Normal, MouseButtonState::Up) | (_, DrawState::Highlighted(_), MouseButtonState::Up) | (_, DrawState::Clicked(_), MouseButtonState::Up)  =>
                    State(DrawState::Highlighted(over_elem), Capturing::Captured(p_idx, p_x)),
                (_, DrawState::Highlighted(p_elem), MouseButtonState::Down) | (_, DrawState::Clicked(p_elem), MouseButtonState::Down) =>
                    State(DrawState::Clicked(p_elem), Capturing::Captured(p_idx, p_x)),
                _ => prev_box_state,
            }
        },
    }
}

/// Draw the text cursor.
fn draw_cursor(
    win_w: f64,
    win_h: f64,
    graphics: &mut Gl,
    color: Color,
    cursor_x: f64,
    pad_pos_y: f64,
    pad_h: f64
) {
    let context = Context::abs(win_w, win_h);
    let (r, g, b, a) = color.plain_contrast().as_tuple();
    context
        .line(cursor_x, pad_pos_y, cursor_x, pad_pos_y + pad_h)
        .round_border_width(1f64)
        .rgba(r, g, b, (a * (precise_time_s() * 2.5).sin() as f32).abs())
        .draw(graphics);
}

/// A context on which the builder pattern can be implemented.
pub struct TextBoxContext<'a> {
    uic: &'a mut UiContext,
    ui_id: UIID,
    text: &'a mut String,
    font_size: u32,
    pos: Point,
    dim: Dimensions,
    maybe_callback: Option<|&mut String|:'a>,
    maybe_color: Option<Color>,
    maybe_frame: Option<f64>,
    maybe_frame_color: Option<Color>,
}

impl<'a> TextBoxContext<'a> {
    pub fn font_size(self, font_size: FontSize) -> TextBoxContext<'a> {
        TextBoxContext { font_size: font_size, ..self }
    }
}

pub trait TextBoxBuilder<'a> {
    /// An text box builder method to be implemented by the UiContext.
    fn text_box(&'a mut self, ui_id: UIID, text: &'a mut String) -> TextBoxContext<'a>;
}

impl<'a> TextBoxBuilder<'a> for UiContext {
    /// Initialise a TextBoxContext.
    fn text_box(&'a mut self, ui_id: UIID, text: &'a mut String) -> TextBoxContext<'a> {
        TextBoxContext {
            uic: self,
            ui_id: ui_id,
            text: text,
            font_size: 24u32, // Default font_size.
            pos: [0.0, 0.0],
            dim: [192.0, 48.0],
            maybe_callback: None,
            maybe_color: None,
            maybe_frame: None,
            maybe_frame_color: None,
        }
    }
}

impl_callable!(TextBoxContext, |&mut String|:'a)
impl_colorable!(TextBoxContext)
impl_frameable!(TextBoxContext)
impl_positionable!(TextBoxContext)
impl_shapeable!(TextBoxContext)

impl<'a> ::draw::Drawable for TextBoxContext<'a> {
    #[inline]
    fn draw(&mut self, graphics: &mut Gl) {
        let mouse = self.uic.get_mouse_state();
        let state = *get_state(self.uic, self.ui_id);

        // Rect.
        let color = self.maybe_color.unwrap_or(self.uic.theme.shape_color);
        let frame_w = self.maybe_frame.unwrap_or(self.uic.theme.frame_width);
        let frame_w2 = frame_w * 2.0;
        let maybe_frame = match frame_w > 0.0 {
            true => Some((frame_w, self.maybe_frame_color.unwrap_or(self.uic.theme.frame_color))),
            false => None,
        };
        let pad_pos = vec2_add(self.pos, [frame_w, ..2]);
        let pad_dim = vec2_sub(self.dim, [frame_w2, ..2]);
        let text_x = pad_pos[0] + TEXT_PADDING;
        let text_y = pad_pos[1] + (pad_dim[1] - self.font_size as f64) / 2.0;
        let text_pos = [text_x, text_y];
        let text_w = label::width(self.uic, self.font_size, self.text.as_slice());
        let over_elem = over_elem(self.uic, self.pos, mouse.pos, self.dim,
                                  pad_pos, pad_dim, text_pos, text_w,
                                  self.font_size, self.text.as_slice());
        let new_state = get_new_state(over_elem, state, mouse);

        rectangle::draw(self.uic.win_w, self.uic.win_h, graphics, new_state.as_rectangle_state(),
                        self.pos, self.dim, maybe_frame, color);
        label::draw(graphics, self.uic, text_pos, self.font_size,
                    color.plain_contrast(), self.text.as_slice());

        let new_state = match new_state { State(w_state, capturing) => match capturing {
            Capturing::Uncaptured => new_state,
            Capturing::Captured(idx, cursor_x) => {
                draw_cursor(self.uic.win_w, self.uic.win_h, graphics, color,
                            cursor_x, pad_pos[1], pad_dim[1]);
                let mut new_idx = idx;
                let mut new_cursor_x = cursor_x;

                // Check for entered text.
                let entered_text = self.uic.get_entered_text();
                for t in entered_text.iter() {
                    let mut entered_text_width = 0f64;
                    for ch in t.as_slice().chars() {
                        let c = self.uic.get_character(self.font_size, ch);
                        entered_text_width += (c.glyph.advance().x >> 16) as f64;
                    }
                    if new_cursor_x + entered_text_width < pad_pos[0] + pad_dim[0] - TEXT_PADDING {
                        new_cursor_x += entered_text_width;
                    }
                    else {
                        break;
                    }
                    let new_text = format!("{}{}{}", self.text.as_slice().slice_to(idx),
                                           t, self.text.as_slice().slice_from(idx));
                    *self.text = new_text;
                    new_idx += t.len();
                }

                // Check for control keys.
                let pressed_keys = self.uic.get_pressed_keys();
                for key in pressed_keys.iter() {
                    match *key {
                        Backspace => {
                            if self.text.len() > 0u
                            && self.text.len() >= idx
                            && idx > 0u {
                                let rem_idx = idx - 1u;
                                new_cursor_x -= self.uic.get_character_w(
                                    self.font_size, self.text.as_slice().char_at(rem_idx)
                                );
                                let new_text = format!("{}{}",
                                                       self.text.as_slice().slice_to(rem_idx),
                                                       self.text.as_slice().slice_from(idx));
                                *self.text = new_text;
                                new_idx = rem_idx;
                            }
                        },
                        Left => {
                            if idx > 0 {
                                new_cursor_x -= self.uic.get_character_w(
                                    self.font_size, self.text.as_slice().char_at(idx - 1u)
                                );
                                new_idx -= 1u;
                            }
                        },
                        Right => {
                            if self.text.len() > idx {
                                new_cursor_x += self.uic.get_character_w(
                                    self.font_size, self.text.as_slice().char_at(idx)
                                );
                                new_idx += 1u;
                            }
                        },
                        Return => if self.text.len() > 0u {
                            let TextBoxContext { // borrowck
                                ref mut maybe_callback,
                                ref mut uic,
                                ref font_size,
                                ref mut text,
                                ..
                            } = *self;
                            match *maybe_callback {
                                Some(ref mut callback) => {
                                    (*callback)(*text);

                                    new_idx = cmp::min(new_idx, text.len());
                                    new_cursor_x = text.as_slice()
                                                       .chars()
                                                       // Add text_pos.x for padding
                                                       .fold(text_pos[0], |acc, c| {
                                        acc + uic.get_character_w(*font_size, c)
                                    });
                                },
                                None => (),
                            }
                        },
                        _ => (),
                    }
                }

                State(w_state, Capturing::Captured(new_idx, new_cursor_x))
            },
        }};

        set_state(self.uic, self.ui_id, new_state, self.pos, self.dim);

    }
}

<commit_msg>Fixed issue with as_slice<commit_after>use std::num::FloatMath;
use color::Color;
use dimensions::Dimensions;
use graphics::{
    AddColor,
    AddLine,
    AddRoundBorder,
    Context,
    Draw,
};
use label;
use label::FontSize;
use mouse_state::{
    MouseState,
    MouseButtonState
};
use opengl_graphics::Gl;
use input::keyboard::{
    Backspace,
    Left,
    Right,
    Return,
};
use point::Point;
use rectangle;
use std::num::Float;
use time::precise_time_s;
use ui_context::{
    UIID,
    UiContext,
};
use vecmath::{
    vec2_add,
    vec2_sub,
};
use widget::Widget::TextBox;
use std::cmp;

pub type Idx = uint;
pub type CursorX = f64;

/// Represents the state of the text_box widget.
#[deriving(Show, PartialEq, Clone)]
pub struct State(DrawState, Capturing);

/// Represents the next tier of state.
#[deriving(Show, PartialEq, Clone)]
pub enum DrawState {
    Normal,
    Highlighted(Element),
    Clicked(Element),
}

/// Whether the textbox is currently captured or not.
#[deriving(Show, PartialEq, Clone)]
pub enum Capturing {
    Uncaptured,
    Captured(Idx, CursorX),
}

/// Represents an element of the TextBox widget.
#[deriving(Show, PartialEq, Clone)]
pub enum Element {
    Nill,
    Rect,
    Text(Idx, CursorX),
}

impl State {
    /// Return the associated Rectangle state.
    fn as_rectangle_state(&self) -> rectangle::State {
        match self {
            &State(state, capturing) => match capturing {
                Capturing::Captured(_, _) => rectangle::State::Normal,
                Capturing::Uncaptured => match state {
                    DrawState::Normal => rectangle::State::Normal,
                    DrawState::Highlighted(_) => rectangle::State::Highlighted,
                    DrawState::Clicked(_) => rectangle::State::Clicked,
                },
            }
        }
    }
}

widget_fns!(TextBox, State, TextBox(State(DrawState::Normal, Capturing::Uncaptured)))

static TEXT_PADDING: f64 = 5f64;

/// Check if cursor is over the pad and if so, which
fn over_elem(uic: &mut UiContext,
             pos: Point,
             mouse_pos: Point,
             rect_dim: Dimensions,
             pad_pos: Point,
             pad_dim: Dimensions,
             text_pos: Point,
             text_w: f64,
             font_size: FontSize,
             text: &str) -> Element {
    match rectangle::is_over(pos, mouse_pos, rect_dim) {
        false => Element::Nill,
        true => match rectangle::is_over(pad_pos, mouse_pos, pad_dim) {
            false => Element::Rect,
            true => {
                let (idx, cursor_x) = closest_idx(uic, mouse_pos, text_pos[0], text_w, font_size, text);
                Element::Text(idx, cursor_x)
            },
        },
    }
}

/// Check which character is closest to the mouse cursor.
fn closest_idx(uic: &mut UiContext,
               mouse_pos: Point,
               text_x: f64,
               text_w: f64,
               font_size: FontSize,
               text: &str) -> (Idx, f64) {
    if mouse_pos[0] <= text_x { return (0u, text_x) }
    let mut x = text_x;
    let mut prev_x = x;
    let mut left_x = text_x;
    for (i, ch) in text.chars().enumerate() {
        let character = uic.get_character(font_size, ch);
        let char_w = (character.glyph.advance().x >> 16) as f64;
        x += char_w;
        let right_x = prev_x + char_w / 2.0;
        if mouse_pos[0] > left_x && mouse_pos[0] < right_x { return (i, prev_x) }
        prev_x = x;
        left_x = right_x;
    }
    (text.len(), text_x + text_w)
}

/// Check and return the current state of the TextBox.
fn get_new_state(over_elem: Element,
                 prev_box_state: State,
                 mouse: MouseState) -> State {
    match prev_box_state {
        State(prev, Capturing::Uncaptured) => {
            match (over_elem, prev, mouse.left) {
                (_, DrawState::Normal, MouseButtonState::Down) => State(DrawState::Normal, Capturing::Uncaptured),
                (Element::Nill, DrawState::Normal, MouseButtonState::Up) | (Element::Nill, DrawState::Highlighted(_), MouseButtonState::Up) => State(DrawState::Normal, Capturing::Uncaptured),
                (_, DrawState::Normal, MouseButtonState::Up) | (_, DrawState::Highlighted(_), MouseButtonState::Up) => State(DrawState::Highlighted(over_elem), Capturing::Uncaptured),
                (_, DrawState::Highlighted(p_elem), MouseButtonState::Down) | (_, DrawState::Clicked(p_elem), MouseButtonState::Down) =>
                    State(DrawState::Clicked(p_elem), Capturing::Uncaptured),
                (Element::Text(idx, x), DrawState::Clicked(Element::Text(_, _)), MouseButtonState::Up) => State(DrawState::Highlighted(over_elem), Capturing::Captured(idx, x)),
                (Element::Nill, _, _) => State(DrawState::Normal, Capturing::Uncaptured),
                _ => prev_box_state,
            }
        },
        State(prev, Capturing::Captured(p_idx, p_x)) => {
            match (over_elem, prev, mouse.left) {
                (Element::Nill, DrawState::Clicked(Element::Nill), MouseButtonState::Up) => State(DrawState::Normal, Capturing::Uncaptured),
                (Element::Text(idx, x), DrawState::Clicked(Element::Text(_, _)), MouseButtonState::Up) => State(DrawState::Highlighted(over_elem), Capturing::Captured(idx, x)),
                (_, DrawState::Normal, MouseButtonState::Up) | (_, DrawState::Highlighted(_), MouseButtonState::Up) | (_, DrawState::Clicked(_), MouseButtonState::Up)  =>
                    State(DrawState::Highlighted(over_elem), Capturing::Captured(p_idx, p_x)),
                (_, DrawState::Highlighted(p_elem), MouseButtonState::Down) | (_, DrawState::Clicked(p_elem), MouseButtonState::Down) =>
                    State(DrawState::Clicked(p_elem), Capturing::Captured(p_idx, p_x)),
                _ => prev_box_state,
            }
        },
    }
}

/// Draw the text cursor.
fn draw_cursor(
    win_w: f64,
    win_h: f64,
    graphics: &mut Gl,
    color: Color,
    cursor_x: f64,
    pad_pos_y: f64,
    pad_h: f64
) {
    let context = Context::abs(win_w, win_h);
    let (r, g, b, a) = color.plain_contrast().as_tuple();
    context
        .line(cursor_x, pad_pos_y, cursor_x, pad_pos_y + pad_h)
        .round_border_width(1f64)
        .rgba(r, g, b, (a * (precise_time_s() * 2.5).sin() as f32).abs())
        .draw(graphics);
}

/// A context on which the builder pattern can be implemented.
pub struct TextBoxContext<'a> {
    uic: &'a mut UiContext,
    ui_id: UIID,
    text: &'a mut String,
    font_size: u32,
    pos: Point,
    dim: Dimensions,
    maybe_callback: Option<|&mut String|:'a>,
    maybe_color: Option<Color>,
    maybe_frame: Option<f64>,
    maybe_frame_color: Option<Color>,
}

impl<'a> TextBoxContext<'a> {
    pub fn font_size(self, font_size: FontSize) -> TextBoxContext<'a> {
        TextBoxContext { font_size: font_size, ..self }
    }
}

pub trait TextBoxBuilder<'a> {
    /// An text box builder method to be implemented by the UiContext.
    fn text_box(&'a mut self, ui_id: UIID, text: &'a mut String) -> TextBoxContext<'a>;
}

impl<'a> TextBoxBuilder<'a> for UiContext {
    /// Initialise a TextBoxContext.
    fn text_box(&'a mut self, ui_id: UIID, text: &'a mut String) -> TextBoxContext<'a> {
        TextBoxContext {
            uic: self,
            ui_id: ui_id,
            text: text,
            font_size: 24u32, // Default font_size.
            pos: [0.0, 0.0],
            dim: [192.0, 48.0],
            maybe_callback: None,
            maybe_color: None,
            maybe_frame: None,
            maybe_frame_color: None,
        }
    }
}

impl_callable!(TextBoxContext, |&mut String|:'a)
impl_colorable!(TextBoxContext)
impl_frameable!(TextBoxContext)
impl_positionable!(TextBoxContext)
impl_shapeable!(TextBoxContext)

impl<'a> ::draw::Drawable for TextBoxContext<'a> {
    #[inline]
    fn draw(&mut self, graphics: &mut Gl) {
        let mouse = self.uic.get_mouse_state();
        let state = *get_state(self.uic, self.ui_id);

        // Rect.
        let color = self.maybe_color.unwrap_or(self.uic.theme.shape_color);
        let frame_w = self.maybe_frame.unwrap_or(self.uic.theme.frame_width);
        let frame_w2 = frame_w * 2.0;
        let maybe_frame = match frame_w > 0.0 {
            true => Some((frame_w, self.maybe_frame_color.unwrap_or(self.uic.theme.frame_color))),
            false => None,
        };
        let pad_pos = vec2_add(self.pos, [frame_w, ..2]);
        let pad_dim = vec2_sub(self.dim, [frame_w2, ..2]);
        let text_x = pad_pos[0] + TEXT_PADDING;
        let text_y = pad_pos[1] + (pad_dim[1] - self.font_size as f64) / 2.0;
        let text_pos = [text_x, text_y];
        let text_w = label::width(self.uic, self.font_size, self.text.as_slice());
        let over_elem = over_elem(self.uic, self.pos, mouse.pos, self.dim,
                                  pad_pos, pad_dim, text_pos, text_w,
                                  self.font_size, self.text.as_slice());
        let new_state = get_new_state(over_elem, state, mouse);

        rectangle::draw(self.uic.win_w, self.uic.win_h, graphics, new_state.as_rectangle_state(),
                        self.pos, self.dim, maybe_frame, color);
        label::draw(graphics, self.uic, text_pos, self.font_size,
                    color.plain_contrast(), self.text.as_slice());

        let new_state = match new_state { State(w_state, capturing) => match capturing {
            Capturing::Uncaptured => new_state,
            Capturing::Captured(idx, cursor_x) => {
                draw_cursor(self.uic.win_w, self.uic.win_h, graphics, color,
                            cursor_x, pad_pos[1], pad_dim[1]);
                let mut new_idx = idx;
                let mut new_cursor_x = cursor_x;

                // Check for entered text.
                let entered_text = self.uic.get_entered_text();
                for t in entered_text.iter() {
                    let mut entered_text_width = 0f64;
                    for ch in t.as_slice().chars() {
                        let c = self.uic.get_character(self.font_size, ch);
                        entered_text_width += (c.glyph.advance().x >> 16) as f64;
                    }
                    if new_cursor_x + entered_text_width < pad_pos[0] + pad_dim[0] - TEXT_PADDING {
                        new_cursor_x += entered_text_width;
                    }
                    else {
                        break;
                    }
                    let new_text = format!("{}{}{}", self.text.as_slice().slice_to(idx),
                                           t, self.text.as_slice().slice_from(idx));
                    *self.text = new_text;
                    new_idx += t.len();
                }

                // Check for control keys.
                let pressed_keys = self.uic.get_pressed_keys();
                for key in pressed_keys.iter() {
                    match *key {
                        Backspace => {
                            if self.text.len() > 0u
                            && self.text.len() >= idx
                            && idx > 0u {
                                let rem_idx = idx - 1u;
                                new_cursor_x -= self.uic.get_character_w(
                                    self.font_size, self.text.as_slice().char_at(rem_idx)
                                );
                                let new_text = format!("{}{}",
                                                       self.text.as_slice().slice_to(rem_idx),
                                                       self.text.as_slice().slice_from(idx));
                                *self.text = new_text;
                                new_idx = rem_idx;
                            }
                        },
                        Left => {
                            if idx > 0 {
                                new_cursor_x -= self.uic.get_character_w(
                                    self.font_size, self.text.as_slice().char_at(idx - 1u)
                                );
                                new_idx -= 1u;
                            }
                        },
                        Right => {
                            if self.text.len() > idx {
                                new_cursor_x += self.uic.get_character_w(
                                    self.font_size, self.text.as_slice().char_at(idx)
                                );
                                new_idx += 1u;
                            }
                        },
                        Return => if self.text.len() > 0u {
                            let TextBoxContext { // borrowck
                                ref mut maybe_callback,
                                ref mut uic,
                                ref font_size,
                                ref mut text,
                                ..
                            } = *self;
                            match *maybe_callback {
                                Some(ref mut callback) => {
                                    (*callback)(*text);

                                    new_idx = cmp::min(new_idx, text.len());
                                    let text = &*text;
                                    new_cursor_x = text.chars()
                                                       // Add text_pos.x for padding
                                                       .fold(text_pos[0], |acc, c| {
                                        acc + uic.get_character_w(*font_size, c)
                                    });
                                },
                                None => (),
                            }
                        },
                        _ => (),
                    }
                }

                State(w_state, Capturing::Captured(new_idx, new_cursor_x))
            },
        }};

        set_state(self.uic, self.ui_id, new_state, self.pos, self.dim);

    }
}

<|endoftext|>


<commit_before>extern crate serde_json;

pub mod learning;

use input::util;
use na::{DMatrix, DVector, IterableMut};
use rand;
use rand::distributions::normal::StandardNormal;
use rand::Rng;
use std::fs::File;
use std::io::{self, BufReader, BufWriter};
use std::str;
use structs::serialnet::SerializableNet;

/// Artificial Neural Network
///
/// This struct represents a simple Artificial Neural Network (ANN) using
/// feedforward and backpropagation. It uses Stochastic Gradient Descent(SGD)
/// and a sigmoid activation function.
///
/// [Source](http://neuralnetworksanddeeplearning.com/chap1.html)
///
/// # Example
///
/// ```rust
/// // This will create a new ANN with the following topology:
/// // 3 "neurons" in the input layer
/// // 5 "neurons" in the first hidden layer
/// // 3 "neurons" in the second hidden layer
/// // 2 "neurons" in the output layer
/// let nnet = Network::new(vec![3, 5, 2]);
/// ```
#[derive(Debug, Clone)]
pub struct Network {
    /// a Vec outlining the topology of the ANN
    /// the first entry corresponds to the inputlayer,
    /// the intermediate entries correspond to the hidden layers
    /// and the last entry corresponds to the outputlayer.
    layers: Vec<u8>,
    /// a Vec that contains the weights of the respective layer
    weights: Vec<DMatrix<f32>>,
    /// a Vec cointaining the biases of the respective layer
    biases: Vec<DVector<f32>>,
}

impl Network {
    /// build a new Network with a topology Vector
    pub fn new(sizes: &[u8]) -> Result<Network, &'static str> {
        assert!(sizes.len() >= 3, "at least three layers required");

        // Store the weights and biases in lists
        // We will not need weights or biases for input layer, so ignore that (hence -1)
        let mut weights = Vec::with_capacity(sizes.len() - 1);
        let mut biases = Vec::with_capacity(sizes.len() - 1);

        let mut rng = rand::thread_rng();

        // we use the standard normal distribution to initialize weights and biases - why?
        for (i, layer) in sizes.iter().enumerate().skip(1) {
            // initialize weight matrices
            weights.push(DMatrix::from_fn(*layer as usize, sizes[i - 1] as usize, |_, _| {
                let StandardNormal(x) = rng.gen();
                x as f32
            }));

            // initialize biases
            biases.push(DVector::from_fn(*layer as usize, |_| {
                let StandardNormal(x) = rng.gen();
                x as f32
            }));
        }

        Ok(Network {
            layers: sizes.to_vec(),
            weights: weights,
            biases: biases,
        })
    }

    /// Feed input through network, return output layer activation level
    pub fn feedforward(&self, a: &DVector<f32>) -> DVector<f32> {
        let mut act = a.clone();
        for (weight, bias) in self.weights.iter().zip(self.biases.clone().into_iter()) {
            act = sigmoid(&(weight * act + bias));
        }
        act
    }

    /// return the layers used to initialize the ANN
    pub fn get_layers(&self) -> &[u8] {
        &self.layers
    }

    /// return a vector of the weight matrices of the ANN
    pub fn get_weights(&self) -> &[DMatrix<f32>] {
        &self.weights
    }

    /// return a mutable vector of the weight matrices of the ANN
    pub fn get_weights_mut(&mut self) -> &mut Vec<DMatrix<f32>> {
        &mut self.weights
    }

    /// return a vector of the bias matrices of the ANN
    pub fn get_biases(&self) -> &[DVector<f32>] {
        &self.biases
    }

    // TODO: remove allow dead_code

    /// Saves a network state to the given filename and returns a result
    ///
    /// # Examples
    ///
    /// ```
    /// let mut nn = nn::Network::new(vec![4, 5, 3]).unwrap();
    /// let state_file_name = "state1.json";
    /// nn.save_to_file(state_file_name).unwrap();
    /// ```
    #[allow(dead_code)]
    pub fn save_to_file(self, filename: &str) -> Result<(), serde_json::Error> {
        // wrap it in a SerializableNet
        let serializable_net: SerializableNet = self.into();
        // create the file
        let f = File::create(util::get_root_dir().join("data/").join(filename)).unwrap();
        // create a writer
        let mut writer = BufWriter::new(f);
        // serialize the network and return the result
        serde_json::to_writer(&mut writer, &serializable_net)
    }

    /// Loads a network state from the given file
    ///
    /// Returns a result with the file or an io::Error if the specified file could
    /// not be opened
    ///
    /// # Examples
    ///
    /// ```
    /// let loaded_nn = Network::from_file("state1.json");
    /// ```
    pub fn from_file(filename: &str) -> Result<Self, io::Error> {
        // attempt to open the file
        let f = File::open(util::get_root_dir().join("data/").join(filename))?;
        let reader = BufReader::new(f);
        // read the SerializableNet from the file
        // we use unwrap here b/c if the file exists then we want the program to panic
        // if we cannot read from it
        let my_net: SerializableNet = serde_json::from_reader(reader)
            .expect("Could not parse Network from File");
        // convert into a Network and return it
        Ok(my_net.into())
    }

    /// return a vector of the bias matrices of the ANN
    pub fn get_biases_mut(&mut self) -> &mut Vec<DVector<f32>> {
        &mut self.biases
    }
}

/// calculate elementwise sigmoid function of the `input` vector.
pub fn sigmoid(input: &DVector<f32>) -> DVector<f32> {
    let mut sig = input.clone();
    for elem in sig.iter_mut() {
        *elem = 1.0 / (1.0 + (-1.0f32 * *elem).exp());
    }
    sig
}

impl From<SerializableNet> for Network {
    fn from(ser_net: SerializableNet) -> Self {

        let mut weights: Vec<DMatrix<f32>> = Vec::new();
        for v in ser_net.weights {
            let (nrows, ncols) = (v.0, v.1);
            weights.push(DMatrix::from_column_vector(nrows, ncols, &v.2))
        }

        let mut biases: Vec<DVector<f32>> = Vec::new();
        for v in ser_net.biases {
            biases.push(DVector::from_slice(v.len(), &v))
        }

        Network {
            layers: ser_net.layers,
            weights: weights,
            biases: biases,
        }
    }
}

#[test]
fn test_sigmoid() {
    let mut arr_orig = DVector::from_element(3, 1.0f32);
    arr_orig[2] = 2.4137;
    let arr = sigmoid(&arr_orig);
    assert_eq!(arr[0], arr[1]);
    assert_eq!(arr[0], 0.73105857863f32);
    assert_eq!(arr[2], 0.91786604895f32);
}
<commit_msg>Removed unnecessary ignore-dead-code<commit_after>extern crate serde_json;

pub mod learning;

use input::util;
use na::{DMatrix, DVector, IterableMut};
use rand;
use rand::distributions::normal::StandardNormal;
use rand::Rng;
use std::fs::File;
use std::io::{self, BufReader, BufWriter};
use std::str;
use structs::serialnet::SerializableNet;

/// Artificial Neural Network
///
/// This struct represents a simple Artificial Neural Network (ANN) using
/// feedforward and backpropagation. It uses Stochastic Gradient Descent(SGD)
/// and a sigmoid activation function.
///
/// [Source](http://neuralnetworksanddeeplearning.com/chap1.html)
///
/// # Example
///
/// ```rust
/// // This will create a new ANN with the following topology:
/// // 3 "neurons" in the input layer
/// // 5 "neurons" in the first hidden layer
/// // 3 "neurons" in the second hidden layer
/// // 2 "neurons" in the output layer
/// let nnet = Network::new(vec![3, 5, 2]);
/// ```
#[derive(Debug, Clone)]
pub struct Network {
    /// a Vec outlining the topology of the ANN
    /// the first entry corresponds to the inputlayer,
    /// the intermediate entries correspond to the hidden layers
    /// and the last entry corresponds to the outputlayer.
    layers: Vec<u8>,
    /// a Vec that contains the weights of the respective layer
    weights: Vec<DMatrix<f32>>,
    /// a Vec cointaining the biases of the respective layer
    biases: Vec<DVector<f32>>,
}

impl Network {
    /// build a new Network with a topology Vector
    pub fn new(sizes: &[u8]) -> Result<Network, &'static str> {
        assert!(sizes.len() >= 3, "at least three layers required");

        // Store the weights and biases in lists
        // We will not need weights or biases for input layer, so ignore that (hence -1)
        let mut weights = Vec::with_capacity(sizes.len() - 1);
        let mut biases = Vec::with_capacity(sizes.len() - 1);

        let mut rng = rand::thread_rng();

        // we use the standard normal distribution to initialize weights and biases - why?
        for (i, layer) in sizes.iter().enumerate().skip(1) {
            // initialize weight matrices
            weights.push(DMatrix::from_fn(*layer as usize, sizes[i - 1] as usize, |_, _| {
                let StandardNormal(x) = rng.gen();
                x as f32
            }));

            // initialize biases
            biases.push(DVector::from_fn(*layer as usize, |_| {
                let StandardNormal(x) = rng.gen();
                x as f32
            }));
        }

        Ok(Network {
            layers: sizes.to_vec(),
            weights: weights,
            biases: biases,
        })
    }

    /// Feed input through network, return output layer activation level
    pub fn feedforward(&self, a: &DVector<f32>) -> DVector<f32> {
        let mut act = a.clone();
        for (weight, bias) in self.weights.iter().zip(self.biases.clone().into_iter()) {
            act = sigmoid(&(weight * act + bias));
        }
        act
    }

    /// return the layers used to initialize the ANN
    pub fn get_layers(&self) -> &[u8] {
        &self.layers
    }

    /// return a vector of the weight matrices of the ANN
    pub fn get_weights(&self) -> &[DMatrix<f32>] {
        &self.weights
    }

    /// return a mutable vector of the weight matrices of the ANN
    pub fn get_weights_mut(&mut self) -> &mut Vec<DMatrix<f32>> {
        &mut self.weights
    }

    /// return a vector of the bias matrices of the ANN
    pub fn get_biases(&self) -> &[DVector<f32>] {
        &self.biases
    }

    /// Saves a network state to the given filename and returns a result
    ///
    /// # Examples
    ///
    /// ```
    /// let mut nn = nn::Network::new(vec![4, 5, 3]).unwrap();
    /// let state_file_name = "state1.json";
    /// nn.save_to_file(state_file_name).unwrap();
    /// ```
    pub fn save_to_file(self, filename: &str) -> Result<(), serde_json::Error> {
        // wrap it in a SerializableNet
        let serializable_net: SerializableNet = self.into();
        // create the file
        let f = File::create(util::get_root_dir().join("data/").join(filename)).unwrap();
        // create a writer
        let mut writer = BufWriter::new(f);
        // serialize the network and return the result
        serde_json::to_writer(&mut writer, &serializable_net)
    }

    /// Loads a network state from the given file
    ///
    /// Returns a result with the file or an io::Error if the specified file could
    /// not be opened
    ///
    /// # Examples
    ///
    /// ```
    /// let loaded_nn = Network::from_file("state1.json");
    /// ```
    pub fn from_file(filename: &str) -> Result<Self, io::Error> {
        // attempt to open the file
        let f = File::open(util::get_root_dir().join("data/").join(filename))?;
        let reader = BufReader::new(f);
        // read the SerializableNet from the file
        // we use unwrap here b/c if the file exists then we want the program to panic
        // if we cannot read from it
        let my_net: SerializableNet = serde_json::from_reader(reader)
            .expect("Could not parse Network from File");
        // convert into a Network and return it
        Ok(my_net.into())
    }

    /// return a vector of the bias matrices of the ANN
    pub fn get_biases_mut(&mut self) -> &mut Vec<DVector<f32>> {
        &mut self.biases
    }
}

/// calculate elementwise sigmoid function of the `input` vector.
pub fn sigmoid(input: &DVector<f32>) -> DVector<f32> {
    let mut sig = input.clone();
    for elem in sig.iter_mut() {
        *elem = 1.0 / (1.0 + (-1.0f32 * *elem).exp());
    }
    sig
}

impl From<SerializableNet> for Network {
    fn from(ser_net: SerializableNet) -> Self {

        let mut weights: Vec<DMatrix<f32>> = Vec::new();
        for v in ser_net.weights {
            let (nrows, ncols) = (v.0, v.1);
            weights.push(DMatrix::from_column_vector(nrows, ncols, &v.2))
        }

        let mut biases: Vec<DVector<f32>> = Vec::new();
        for v in ser_net.biases {
            biases.push(DVector::from_slice(v.len(), &v))
        }

        Network {
            layers: ser_net.layers,
            weights: weights,
            biases: biases,
        }
    }
}

#[test]
fn test_sigmoid() {
    let mut arr_orig = DVector::from_element(3, 1.0f32);
    arr_orig[2] = 2.4137;
    let arr = sigmoid(&arr_orig);
    assert_eq!(arr[0], arr[1]);
    assert_eq!(arr[0], 0.73105857863f32);
    assert_eq!(arr[2], 0.91786604895f32);
}
<|endoftext|>