<commit_before>use std::fmt::Debug;
use std::marker::PhantomData;
use super::{Alphabet, DualAlphabet};
use expression::{Expression, Condition, ExpressionError};
use std::collections::BTreeMap;

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

pub trait ParametricSymbol: Clone + PartialEq + Debug
{
    type Sym: Alphabet;
    type Param: Clone + Debug + PartialEq;

    fn symbol(&self) -> &Self::Sym;
    fn symbol_mut(&mut self) -> &mut Self::Sym;

    fn params(&self) -> &[Self::Param];
    fn params_mut(&mut self) -> &mut [Self::Param];

    /// Construct a new ParametricSymbol. If the iterator contains a wrong
    /// number of parameters, return None.
    fn new_from_result_iter<I, E>(symbol: Self::Sym, iter: I) -> Option<Result<Self, E>>
        where I: Iterator<Item = Result<Self::Param, E>>;

    fn new_from_iter<I>(symbol: Self::Sym, iter: I) -> Option<Self>
        where I: Iterator<Item = Self::Param>
    {
        match Self::new_from_result_iter::<_, ()>(symbol, iter.map(|i| Ok(i))) {
            Some(Ok(res)) => Some(res),
            Some(Err(())) => panic!(),
            None => None,
        }
    }

    fn new_from_vec(symbol: Self::Sym, vec: Vec<Self::Param>) -> Option<Self> {
        Self::new_from_iter(symbol, vec.into_iter())
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct PSym<Sym: Alphabet, Param: Clone + Debug + PartialEq> {
    symbol: Sym,
    params: Vec<Param>,
}

impl<Sym: Alphabet, Param: Clone + Debug + PartialEq> ParametricSymbol for PSym<Sym, Param> {
    type Sym = Sym;
    type Param = Param;

    fn symbol(&self) -> &Self::Sym {
        &self.symbol
    }
    fn symbol_mut(&mut self) -> &mut Self::Sym {
        &mut self.symbol
    }
    fn params(&self) -> &[Self::Param] {
        &self.params
    }
    fn params_mut(&mut self) -> &mut [Self::Param] {
        &mut self.params
    }

    fn new_from_result_iter<I, E>(symbol: Self::Sym, iter: I) -> Option<Result<Self, E>>
        where I: Iterator<Item = Result<Self::Param, E>>
    {
        let mut params = Vec::with_capacity(iter.size_hint().0);
        for p in iter {
            match p {
                Ok(p) => params.push(p),
                Err(e) => return Some(Err(e)),
            }
        }
        Some(Ok(PSym {
            symbol: symbol,
            params: params,
        }))
    }
}

#[derive(Debug, PartialEq)]
pub struct PSym1<Sym: Alphabet, Param: Clone + Debug + PartialEq> {
    symbol: Sym,
    params: [Param; 1],
}

impl<Sym: Alphabet, Param: Clone + Debug + PartialEq> Clone for PSym1<Sym, Param> {
    fn clone(&self) -> Self {
        PSym1 {
            symbol: self.symbol.clone(),
            params: [self.params[0].clone()],
        }
    }
}

impl<Sym: Alphabet, Param: Clone + Debug + PartialEq> ParametricSymbol for PSym1<Sym, Param> {
    type Sym = Sym;
    type Param = Param;

    fn symbol(&self) -> &Self::Sym {
        &self.symbol
    }
    fn symbol_mut(&mut self) -> &mut Self::Sym {
        &mut self.symbol
    }
    fn params(&self) -> &[Self::Param] {
        &self.params
    }
    fn params_mut(&mut self) -> &mut [Self::Param] {
        &mut self.params
    }

    fn new_from_result_iter<I, E>(symbol: Self::Sym, mut iter: I) -> Option<Result<Self, E>>
        where I: Iterator<Item = Result<Self::Param, E>>
    {
        let p1 = match iter.next() {
            Some(Ok(p)) => p,
            Some(Err(e)) => return Some(Err(e)),
            None => return None,
        };
        if let Some(_) = iter.next() {
            return None;
        }

        Some(Ok(PSym1 {
            symbol: symbol,
            params: [p1],
        }))
    }
}

#[derive(Debug, PartialEq)]
pub struct PSym2<Sym: Alphabet, Param: Clone + Debug + PartialEq> {
    symbol: Sym,
    params: [Param; 2],
}

impl<Sym: Alphabet, Param: Clone + Debug + PartialEq> Clone for PSym2<Sym, Param> {
    fn clone(&self) -> Self {
        PSym2 {
            symbol: self.symbol.clone(),
            params: [self.params[0].clone(), self.params[1].clone()],
        }
    }
}

impl<Sym: Alphabet, Param: Clone + Debug + PartialEq> ParametricSymbol for PSym2<Sym, Param> {
    type Sym = Sym;
    type Param = Param;

    fn symbol(&self) -> &Self::Sym {
        &self.symbol
    }
    fn symbol_mut(&mut self) -> &mut Self::Sym {
        &mut self.symbol
    }
    fn params(&self) -> &[Self::Param] {
        &self.params
    }
    fn params_mut(&mut self) -> &mut [Self::Param] {
        &mut self.params
    }

    fn new_from_result_iter<I, E>(symbol: Self::Sym, mut iter: I) -> Option<Result<Self, E>>
        where I: Iterator<Item = Result<Self::Param, E>>
    {
        let p1 = match iter.next() {
            Some(Ok(p)) => p,
            Some(Err(e)) => return Some(Err(e)),
            None => return None,
        };
        let p2 = match iter.next() {
            Some(Ok(p)) => p,
            Some(Err(e)) => return Some(Err(e)),
            None => return None,
        };
        if let Some(_) = iter.next() {
            return None;
        }

        Some(Ok(PSym2 {
            symbol: symbol,
            params: [p1, p2],
        }))
    }
}

pub trait ParametricRule: Clone + Debug
{
    type InSym: ParametricSymbol;
    type OutSym: ParametricSymbol;

    fn apply(&self, psym: &Self::OutSym) -> Result<Vec<Self::OutSym>, RuleError>;

    fn symbol(&self) -> &<Self::InSym as ParametricSymbol>::Sym;
}

#[derive(Debug, Clone)]
pub struct PRule<Sym, PS, PS2, C>
    where Sym: Alphabet,
          PS: ParametricSymbol<Sym = Sym, Param = C::Expr>,
          PS2: ParametricSymbol<Sym = Sym, Param = <C::Expr as Expression>::Element>,
          C: Condition
{
    pub symbol: Sym,
    pub condition: C,
    pub production: Vec<PS>,
    pub arity: usize,
    _marker: PhantomData<PS2>,
}

impl<Sym, PS, PS2, C> PRule<Sym, PS, PS2, C>
    where Sym: Alphabet,
          PS: ParametricSymbol<Sym = Sym, Param = C::Expr>,
          PS2: ParametricSymbol<Sym = Sym, Param = <C::Expr as Expression>::Element>,
          C: Condition
{
    pub fn new(sym: Sym, cond: C, prod: Vec<PS>, arity: usize) -> PRule<Sym, PS, PS2, C> {
        PRule {
            symbol: sym,
            condition: cond,
            production: prod,
            arity: arity,
            _marker: PhantomData,
        }
    }
}

impl<Sym, PS, PS2, C> ParametricRule for PRule<Sym, PS, PS2, C>
    where Sym: Alphabet,
          PS: ParametricSymbol<Sym = Sym, Param = C::Expr>,
          PS2: ParametricSymbol<Sym = Sym, Param = <C::Expr as Expression>::Element>,
          C: Condition
{
    type InSym = PS;
    type OutSym = PS2;

    /// Tries to apply the rule and if applicable, produces a successor.
    fn apply(&self, psym: &PS2) -> Result<Vec<PS2>, RuleError> {
        if self.arity != psym.params().len() {
            Err(RuleError::RuleArityMismatch)
        } else if self.symbol.eq(psym.symbol()) {
            match self.condition.evaluate(psym.params()) {
                Ok(true) => {
                    let mut new_symbol_string = Vec::with_capacity(self.production.len());

                    // evaluate all parameters of all symbols in the production
                    for prod_sym in self.production.iter() {
                        match PS2::new_from_result_iter(prod_sym.symbol().clone(),
                                                        prod_sym.params().iter().map(|expr| {
                                                            expr.evaluate(psym.params())
                                                        })) {
                            Some(Ok(new_sym)) => {
                                new_symbol_string.push(new_sym);
                            }
                            Some(Err(e)) => {
                                return Err(RuleError::ExprFailed(e));
                            }
                            None => {
                                return Err(RuleError::ArityMismatch);
                            }
                        }
                    }

                    Ok(new_symbol_string)
                }
                Ok(false) => Err(RuleError::ConditionFalse),
                _ => Err(RuleError::ConditionFailed),
            }
        } else {
            Err(RuleError::SymbolMismatch)
        }
    }

    fn symbol(&self) -> &<Self::InSym as ParametricSymbol>::Sym {
        &self.symbol
    }
}

#[test]
fn test_rule_apply() {
    use expression_num::NumExpr;
    use expression::cond::Cond;
    let expr_s = PSym::new_from_vec('P', vec![NumExpr::Const(123u32)]).unwrap();

    let rule = PRule::<_, PSym<_, NumExpr<u32>>, PSym<_, u32>, _>::new('A',
                                                                       Cond::True,
                                                                       vec![expr_s.clone()],
                                                                       1);

    let param_s = PSym::new_from_vec('P', vec![123u32]).unwrap();
    assert_eq!(Err(RuleError::SymbolMismatch), rule.apply(&param_s));

    let param_s = PSym::new_from_vec('A', vec![123u32]).unwrap();
    let result_s = PSym::new_from_vec('P', vec![123u32]).unwrap();
    assert_eq!(Ok(vec![result_s]), rule.apply(&param_s));

    let rule = PRule::<_, PSym<_, NumExpr<u32>>, PSym<_, u32>, _>::new('A',
                                                                       Cond::False,
                                                                       vec![expr_s.clone()],
                                                                       1);
    assert_eq!(Err(RuleError::ConditionFalse), rule.apply(&param_s));
}

pub trait ParametricSystem {
    type Rule: ParametricRule;

    fn apply_first_rule(&self, sym: &<Self::Rule as ParametricRule>::OutSym) -> Option<Vec<<Self::Rule as ParametricRule>::OutSym>>;

    /// 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: &Vec<<Self::Rule as ParametricRule>::OutSym>) -> (Vec<<Self::Rule as ParametricRule>::OutSym>, usize) {
        let mut expanded = Vec::new();
        let mut rule_applications = 0;

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

                None => {
                    expanded.push(sym.clone());
                }
            }
        }

        (expanded, rule_applications)
    }

    /// Develop the system starting with `axiom` up to `max_iterations`. Return iteration count.
    fn develop(&self,
               axiom: Vec<<Self::Rule as ParametricRule>::OutSym>,
               max_iterations: usize)
               -> (Vec<<Self::Rule as ParametricRule>::OutSym>, 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);
    }
}

/// Apply first matching rule and return expanded successor.
pub fn apply_first_rule<R>(rules: &[R],
                           sym: &<R as ParametricRule>::OutSym)
                           -> Option<Vec<<R as ParametricRule>::OutSym>>
    where R: ParametricRule
{
    for rule in rules {
        if let Ok(successor) = rule.apply(sym) {
            return Some(successor);
        }
    }
    return None;
}

#[derive(Debug, Clone)]
pub struct PSystem<R>
    where R: ParametricRule
{
    rules: Vec<R>,
}

impl<R> PSystem<R> where R: ParametricRule
{
    pub fn new() -> PSystem<R> {
        PSystem { rules: vec![] }
    }

    pub fn add_rule(&mut self, rule: R) {
        self.rules.push(rule);
    }
}

impl<R> ParametricSystem for PSystem<R> where R: ParametricRule
{
    type Rule = R;

    /// Apply first matching rule and return expanded successor.
    fn apply_first_rule(&self, sym: &<Self::Rule as ParametricRule>::OutSym) -> Option<Vec<<Self::Rule as ParametricRule>::OutSym>> {
        apply_first_rule(&self.rules, sym)
    }
}

/// Distinguishes between terminal symbols and non-terminals.  Rules are only allowed on
/// non-terminals.
#[derive(Debug, Clone)]
pub struct PDualMapSystem<A, R>
    where
          A: DualAlphabet,
          R: ParametricRule,
          <R as ParametricRule>::InSym: ParametricSymbol<Sym=A>,
          <R as ParametricRule>::OutSym: ParametricSymbol<Sym=A>,
{
    rules: BTreeMap<A::NonTerminal, Vec<R>>,
}

impl<A, R>  PDualMapSystem<A, R>
    where
          A: DualAlphabet,
          R: ParametricRule,
          <R as ParametricRule>::InSym: ParametricSymbol<Sym=A>,
          <R as ParametricRule>::OutSym: ParametricSymbol<Sym=A>,
{
    pub fn new() -> PDualMapSystem<A,R> {
        PDualMapSystem {
            rules: BTreeMap::new()
        }
    }

    pub fn add_rule(&mut self, rule: R) {
        assert!(rule.symbol().nonterminal().is_some());
    }
}

impl<A, R> ParametricSystem for PDualMapSystem<A, R>
    where
          A: DualAlphabet,
          R: ParametricRule,
          <R as ParametricRule>::InSym: ParametricSymbol<Sym=A>,
          <R as ParametricRule>::OutSym: ParametricSymbol<Sym=A>,
{
    type Rule = R;

    fn apply_first_rule(&self, sym: &<Self::Rule as ParametricRule>::OutSym) -> Option<Vec<<Self::Rule as ParametricRule>::OutSym>> {
        match sym.symbol().nonterminal()
        {
            // We don't store rules for terminal symbols.
            None => None,

            // Only apply rules for non-terminals
            Some(id) => {
                self.rules.get(&id).and_then(|rules| apply_first_rule(&rules[..], sym))
            }
        }
    }
}
<commit_msg>rustfmt<commit_after>use std::fmt::Debug;
use std::marker::PhantomData;
use super::{Alphabet, DualAlphabet};
use expression::{Expression, Condition, ExpressionError};
use std::collections::BTreeMap;

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

pub trait ParametricSymbol: Clone + PartialEq + Debug
{
    type Sym: Alphabet;
    type Param: Clone + Debug + PartialEq;

    fn symbol(&self) -> &Self::Sym;
    fn symbol_mut(&mut self) -> &mut Self::Sym;

    fn params(&self) -> &[Self::Param];
    fn params_mut(&mut self) -> &mut [Self::Param];

    /// Construct a new ParametricSymbol. If the iterator contains a wrong
    /// number of parameters, return None.
    fn new_from_result_iter<I, E>(symbol: Self::Sym, iter: I) -> Option<Result<Self, E>>
        where I: Iterator<Item = Result<Self::Param, E>>;

    fn new_from_iter<I>(symbol: Self::Sym, iter: I) -> Option<Self>
        where I: Iterator<Item = Self::Param>
    {
        match Self::new_from_result_iter::<_, ()>(symbol, iter.map(|i| Ok(i))) {
            Some(Ok(res)) => Some(res),
            Some(Err(())) => panic!(),
            None => None,
        }
    }

    fn new_from_vec(symbol: Self::Sym, vec: Vec<Self::Param>) -> Option<Self> {
        Self::new_from_iter(symbol, vec.into_iter())
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct PSym<Sym: Alphabet, Param: Clone + Debug + PartialEq> {
    symbol: Sym,
    params: Vec<Param>,
}

impl<Sym: Alphabet, Param: Clone + Debug + PartialEq> ParametricSymbol for PSym<Sym, Param> {
    type Sym = Sym;
    type Param = Param;

    fn symbol(&self) -> &Self::Sym {
        &self.symbol
    }
    fn symbol_mut(&mut self) -> &mut Self::Sym {
        &mut self.symbol
    }
    fn params(&self) -> &[Self::Param] {
        &self.params
    }
    fn params_mut(&mut self) -> &mut [Self::Param] {
        &mut self.params
    }

    fn new_from_result_iter<I, E>(symbol: Self::Sym, iter: I) -> Option<Result<Self, E>>
        where I: Iterator<Item = Result<Self::Param, E>>
    {
        let mut params = Vec::with_capacity(iter.size_hint().0);
        for p in iter {
            match p {
                Ok(p) => params.push(p),
                Err(e) => return Some(Err(e)),
            }
        }
        Some(Ok(PSym {
            symbol: symbol,
            params: params,
        }))
    }
}

#[derive(Debug, PartialEq)]
pub struct PSym1<Sym: Alphabet, Param: Clone + Debug + PartialEq> {
    symbol: Sym,
    params: [Param; 1],
}

impl<Sym: Alphabet, Param: Clone + Debug + PartialEq> Clone for PSym1<Sym, Param> {
    fn clone(&self) -> Self {
        PSym1 {
            symbol: self.symbol.clone(),
            params: [self.params[0].clone()],
        }
    }
}

impl<Sym: Alphabet, Param: Clone + Debug + PartialEq> ParametricSymbol for PSym1<Sym, Param> {
    type Sym = Sym;
    type Param = Param;

    fn symbol(&self) -> &Self::Sym {
        &self.symbol
    }
    fn symbol_mut(&mut self) -> &mut Self::Sym {
        &mut self.symbol
    }
    fn params(&self) -> &[Self::Param] {
        &self.params
    }
    fn params_mut(&mut self) -> &mut [Self::Param] {
        &mut self.params
    }

    fn new_from_result_iter<I, E>(symbol: Self::Sym, mut iter: I) -> Option<Result<Self, E>>
        where I: Iterator<Item = Result<Self::Param, E>>
    {
        let p1 = match iter.next() {
            Some(Ok(p)) => p,
            Some(Err(e)) => return Some(Err(e)),
            None => return None,
        };
        if let Some(_) = iter.next() {
            return None;
        }

        Some(Ok(PSym1 {
            symbol: symbol,
            params: [p1],
        }))
    }
}

#[derive(Debug, PartialEq)]
pub struct PSym2<Sym: Alphabet, Param: Clone + Debug + PartialEq> {
    symbol: Sym,
    params: [Param; 2],
}

impl<Sym: Alphabet, Param: Clone + Debug + PartialEq> Clone for PSym2<Sym, Param> {
    fn clone(&self) -> Self {
        PSym2 {
            symbol: self.symbol.clone(),
            params: [self.params[0].clone(), self.params[1].clone()],
        }
    }
}

impl<Sym: Alphabet, Param: Clone + Debug + PartialEq> ParametricSymbol for PSym2<Sym, Param> {
    type Sym = Sym;
    type Param = Param;

    fn symbol(&self) -> &Self::Sym {
        &self.symbol
    }
    fn symbol_mut(&mut self) -> &mut Self::Sym {
        &mut self.symbol
    }
    fn params(&self) -> &[Self::Param] {
        &self.params
    }
    fn params_mut(&mut self) -> &mut [Self::Param] {
        &mut self.params
    }

    fn new_from_result_iter<I, E>(symbol: Self::Sym, mut iter: I) -> Option<Result<Self, E>>
        where I: Iterator<Item = Result<Self::Param, E>>
    {
        let p1 = match iter.next() {
            Some(Ok(p)) => p,
            Some(Err(e)) => return Some(Err(e)),
            None => return None,
        };
        let p2 = match iter.next() {
            Some(Ok(p)) => p,
            Some(Err(e)) => return Some(Err(e)),
            None => return None,
        };
        if let Some(_) = iter.next() {
            return None;
        }

        Some(Ok(PSym2 {
            symbol: symbol,
            params: [p1, p2],
        }))
    }
}

pub trait ParametricRule: Clone + Debug
{
    type InSym: ParametricSymbol;
    type OutSym: ParametricSymbol;

    fn apply(&self, psym: &Self::OutSym) -> Result<Vec<Self::OutSym>, RuleError>;

    fn symbol(&self) -> &<Self::InSym as ParametricSymbol>::Sym;
}

#[derive(Debug, Clone)]
pub struct PRule<Sym, PS, PS2, C>
    where Sym: Alphabet,
          PS: ParametricSymbol<Sym = Sym, Param = C::Expr>,
          PS2: ParametricSymbol<Sym = Sym, Param = <C::Expr as Expression>::Element>,
          C: Condition
{
    pub symbol: Sym,
    pub condition: C,
    pub production: Vec<PS>,
    pub arity: usize,
    _marker: PhantomData<PS2>,
}

impl<Sym, PS, PS2, C> PRule<Sym, PS, PS2, C>
    where Sym: Alphabet,
          PS: ParametricSymbol<Sym = Sym, Param = C::Expr>,
          PS2: ParametricSymbol<Sym = Sym, Param = <C::Expr as Expression>::Element>,
          C: Condition
{
    pub fn new(sym: Sym, cond: C, prod: Vec<PS>, arity: usize) -> PRule<Sym, PS, PS2, C> {
        PRule {
            symbol: sym,
            condition: cond,
            production: prod,
            arity: arity,
            _marker: PhantomData,
        }
    }
}

impl<Sym, PS, PS2, C> ParametricRule for PRule<Sym, PS, PS2, C>
    where Sym: Alphabet,
          PS: ParametricSymbol<Sym = Sym, Param = C::Expr>,
          PS2: ParametricSymbol<Sym = Sym, Param = <C::Expr as Expression>::Element>,
          C: Condition
{
    type InSym = PS;
    type OutSym = PS2;

    /// Tries to apply the rule and if applicable, produces a successor.
    fn apply(&self, psym: &PS2) -> Result<Vec<PS2>, RuleError> {
        if self.arity != psym.params().len() {
            Err(RuleError::RuleArityMismatch)
        } else if self.symbol.eq(psym.symbol()) {
            match self.condition.evaluate(psym.params()) {
                Ok(true) => {
                    let mut new_symbol_string = Vec::with_capacity(self.production.len());

                    // evaluate all parameters of all symbols in the production
                    for prod_sym in self.production.iter() {
                        match PS2::new_from_result_iter(prod_sym.symbol().clone(),
                                                        prod_sym.params().iter().map(|expr| {
                                                            expr.evaluate(psym.params())
                                                        })) {
                            Some(Ok(new_sym)) => {
                                new_symbol_string.push(new_sym);
                            }
                            Some(Err(e)) => {
                                return Err(RuleError::ExprFailed(e));
                            }
                            None => {
                                return Err(RuleError::ArityMismatch);
                            }
                        }
                    }

                    Ok(new_symbol_string)
                }
                Ok(false) => Err(RuleError::ConditionFalse),
                _ => Err(RuleError::ConditionFailed),
            }
        } else {
            Err(RuleError::SymbolMismatch)
        }
    }

    fn symbol(&self) -> &<Self::InSym as ParametricSymbol>::Sym {
        &self.symbol
    }
}

#[test]
fn test_rule_apply() {
    use expression_num::NumExpr;
    use expression::cond::Cond;
    let expr_s = PSym::new_from_vec('P', vec![NumExpr::Const(123u32)]).unwrap();

    let rule = PRule::<_, PSym<_, NumExpr<u32>>, PSym<_, u32>, _>::new('A',
                                                                       Cond::True,
                                                                       vec![expr_s.clone()],
                                                                       1);

    let param_s = PSym::new_from_vec('P', vec![123u32]).unwrap();
    assert_eq!(Err(RuleError::SymbolMismatch), rule.apply(&param_s));

    let param_s = PSym::new_from_vec('A', vec![123u32]).unwrap();
    let result_s = PSym::new_from_vec('P', vec![123u32]).unwrap();
    assert_eq!(Ok(vec![result_s]), rule.apply(&param_s));

    let rule = PRule::<_, PSym<_, NumExpr<u32>>, PSym<_, u32>, _>::new('A',
                                                                       Cond::False,
                                                                       vec![expr_s.clone()],
                                                                       1);
    assert_eq!(Err(RuleError::ConditionFalse), rule.apply(&param_s));
}

pub trait ParametricSystem {
    type Rule: ParametricRule;

    fn apply_first_rule(&self, sym: &<Self::Rule as ParametricRule>::OutSym) -> Option<Vec<<Self::Rule as ParametricRule>::OutSym>>;

    /// 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: &Vec<<Self::Rule as ParametricRule>::OutSym>) -> (Vec<<Self::Rule as ParametricRule>::OutSym>, usize) {
        let mut expanded = Vec::new();
        let mut rule_applications = 0;

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

                None => {
                    expanded.push(sym.clone());
                }
            }
        }

        (expanded, rule_applications)
    }

    /// Develop the system starting with `axiom` up to `max_iterations`. Return iteration count.
    fn develop(&self,
               axiom: Vec<<Self::Rule as ParametricRule>::OutSym>,
               max_iterations: usize)
               -> (Vec<<Self::Rule as ParametricRule>::OutSym>, 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);
    }
}

/// Apply first matching rule and return expanded successor.
pub fn apply_first_rule<R>(rules: &[R],
                           sym: &<R as ParametricRule>::OutSym)
                           -> Option<Vec<<R as ParametricRule>::OutSym>>
    where R: ParametricRule
{
    for rule in rules {
        if let Ok(successor) = rule.apply(sym) {
            return Some(successor);
        }
    }
    return None;
}

#[derive(Debug, Clone)]
pub struct PSystem<R>
    where R: ParametricRule
{
    rules: Vec<R>,
}

impl<R> PSystem<R> where R: ParametricRule
{
    pub fn new() -> PSystem<R> {
        PSystem { rules: vec![] }
    }

    pub fn add_rule(&mut self, rule: R) {
        self.rules.push(rule);
    }
}

impl<R> ParametricSystem for PSystem<R> where R: ParametricRule
{
    type Rule = R;

    /// Apply first matching rule and return expanded successor.
    fn apply_first_rule(&self, sym: &<Self::Rule as ParametricRule>::OutSym) -> Option<Vec<<Self::Rule as ParametricRule>::OutSym>> {
        apply_first_rule(&self.rules, sym)
    }
}

/// Distinguishes between terminal symbols and non-terminals.  Rules are only allowed on
/// non-terminals.
#[derive(Debug, Clone)]
pub struct PDualMapSystem<A, R>
    where A: DualAlphabet,
          R: ParametricRule,
          <R as ParametricRule>::InSym: ParametricSymbol<Sym = A>,
          <R as ParametricRule>::OutSym: ParametricSymbol<Sym = A>
{
    rules: BTreeMap<A::NonTerminal, Vec<R>>,
}

impl<A, R> PDualMapSystem<A, R>
    where A: DualAlphabet,
          R: ParametricRule,
          <R as ParametricRule>::InSym: ParametricSymbol<Sym = A>,
          <R as ParametricRule>::OutSym: ParametricSymbol<Sym = A>
{
    pub fn new() -> PDualMapSystem<A, R> {
        PDualMapSystem { rules: BTreeMap::new() }
    }

    pub fn add_rule(&mut self, rule: R) {
        assert!(rule.symbol().nonterminal().is_some());
    }
}

impl<A, R> ParametricSystem for PDualMapSystem<A, R>
    where A: DualAlphabet,
          R: ParametricRule,
          <R as ParametricRule>::InSym: ParametricSymbol<Sym = A>,
          <R as ParametricRule>::OutSym: ParametricSymbol<Sym = A>
{
    type Rule = R;

    fn apply_first_rule(&self, sym: &<Self::Rule as ParametricRule>::OutSym) -> Option<Vec<<Self::Rule as ParametricRule>::OutSym>> {
        match sym.symbol().nonterminal() {
            // We don't store rules for terminal symbols.
            None => None,

            // Only apply rules for non-terminals
            Some(id) => self.rules.get(&id).and_then(|rules| apply_first_rule(&rules[..], sym)),
        }
    }
}
<|endoftext|>


<commit_before>#[cfg(target_arch = "wasm32")]
compile_error!("This module should not be included when compiling to wasm");

use std::sync::mpsc::{self, TryRecvError};
use std::thread;
use std::path;

use piston_window::{clear, context, line, polygon, AdvancedWindow, Event as PistonEvent, G2d,
    Input, PistonWindow, WindowSettings};

use svg;
use svg::node::element::{Line as SvgLine, Polygon as SvgPolygon, Rectangle as SvgRect};

use crate::app::TurtleApp;
use crate::event::from_piston_event;
use crate::extensions::ConvertScreenCoordinates;
use crate::query::DrawingCommand;
use crate::state::{DrawingState, Path, Pen, Polygon, TurtleState};
use crate::{color, Color, Event, Point};

fn update_window(window: &mut PistonWindow, current: DrawingState, next: DrawingState) -> DrawingState {
    if next.title != current.title {
        window.set_title(next.title.clone());
    }
    if next.width != current.width || next.height != current.height {
        window.set_size((next.width, next.height));
    }
    if next.maximized != current.maximized {
        window.window.window.set_maximized(next.maximized);
    }
    if next.fullscreen != current.fullscreen {
        if next.fullscreen {
            window
                .window
                .window
                .set_fullscreen(Some(window.window.window.get_current_monitor()));
        } else {
            window.window.window.set_fullscreen(None);
        }
    }
    next
}

#[derive(Debug)]
pub enum Drawing {
    Path(Path),
    Polygon(Polygon),
}

pub struct Renderer {
    app: TurtleApp,
    drawings: Vec<Drawing>,
    /// Polygon that is currently in the process of being filled
    /// Removed when EndFill is sent
    fill_polygon: Option<(Vec<Path>, Polygon)>,
}

impl Renderer {
    pub fn new(app: TurtleApp) -> Renderer {
        Self {
            app,
            drawings: Vec::new(),
            fill_polygon: None,
        }
    }

    pub fn run(&mut self, drawing_rx: mpsc::Receiver<DrawingCommand>, events_tx: mpsc::Sender<Event>) {
        let state = self.app.read_only();

        // This check isn't foolproof. Someone can always create a thread named "main".
        if thread::current().name().unwrap_or("") != "main" {
            // In order to maintain compatibility with MacOS, we need to make sure that windows are
            // only created on the main thread. We do this check on all platforms so that no one
            // can accidentally make a change that creates the window off of the main thread.
            unreachable!("bug: windows can only be created on the main thread");
        }

        let mut window: PistonWindow = WindowSettings::new(
            &*state.drawing().title,
            (state.drawing().width, state.drawing().height)
        ).exit_on_esc(true).build().expect("bug: could not build window");

        // We keep a copy of the DrawingState so that we can tell when it is updated and we need
        // to change something on the window
        let mut current_drawing = DrawingState::default();

        let mut center = state.drawing().center;

        'renderloop: while let Some(event) = window.next() {
            match event {
                PistonEvent::Input(Input::Resize(width, height)) => {
                    let width = width as u32;
                    let height = height as u32;
                    if width != current_drawing.width || height != current_drawing.height {
                        let mut drawing = self.app.drawing_mut();
                        drawing.width = width;
                        drawing.height = height;
                    }
                }
                _ => {}
            }

            if let Some(event) = from_piston_event(&event, |pt| pt.to_local_coords(center)) {
                match events_tx.send(event) {
                    Ok(_) => {}
                    // Quit - the server thread must have quit
                    Err(_) => break,
                }
            }

            // Need to handle all of the queries we receive at once so that any lag caused by
            // how long rendering takes doesn't cause any problems
            loop {
                match drawing_rx.try_recv() {
                    Ok(cmd) => self.handle_drawing_command(cmd),
                    Err(TryRecvError::Empty) => break,                    // Do nothing
                    Err(TryRecvError::Disconnected) => break 'renderloop, // Quit
                }
            }

            // Update the window based on any changes in the DrawingState
            current_drawing = update_window(&mut window, current_drawing, state.drawing().clone());

            window.draw_2d(&event, |c, g| {
                let view = c.get_view_size();
                let width = view[0] as f64;
                let height = view[1] as f64;
                center = state.drawing().center.to_screen_coords(Point {
                    x: width * 0.5,
                    y: height * 0.5,
                });

                // We clone the relevant state before rendering so that the rendering thread
                // doesn't need to keep locking, waiting or making the main thread wait
                let drawing = state.drawing().clone();
                let temporary_path = state.temporary_path().clone();
                let turtle = state.turtle().clone();

                self.render(c, g, center, &drawing, &temporary_path, &turtle);
            });
        }
    }

    /// Handles a drawing command sent from the main thread
    fn handle_drawing_command(&mut self, command: DrawingCommand) {
        //NOTE: Do not pass the ReadOnly state to this function. By the time a DrawingCommand is
        // handled, that state may be completely out of date
        use DrawingCommand::*;
        match command {
            StorePath(path) => {
                if self.fill_polygon.is_some() {
                    let &mut (ref mut border, ref mut poly) = self.fill_polygon.as_mut().unwrap();
                    border.push(path.clone());

                    let Path { start, end, .. } = path;
                    if poly.vertices.last().map_or(true, |&v| v != start) {
                        poly.vertices.push(start);
                    }
                    poly.vertices.push(end);
                } else if path.pen.enabled {
                    self.drawings.push(Drawing::Path(path));
                }
            },
            BeginFill(fill_color) => {
                // Calling begin_fill multiple times is okay, it just won't do anything until
                // end_fill is called
                self.fill_polygon = self.fill_polygon.take().or_else(|| {
                    Some((
                        Vec::new(),
                        Polygon {
                            vertices: Vec::new(),
                            fill_color,
                        },
                    ))
                });
            },
            // Calling end_fill multiple times is not a problem
            EndFill => if let Some((border, poly)) = self.fill_polygon.take() {
                // Always add the border over the filled polygon so the border is drawn on top
                self.drawings.push(Drawing::Polygon(poly));
                self.drawings.extend(
                    border
                        .into_iter()
                        .filter_map(|p| if p.pen.enabled { Some(Drawing::Path(p)) } else { None }),
                );
            },
            Clear => {
                self.drawings.clear();
                // Because clear doesn't actually shorten the capacity of the vector
                // We don't want to leak memory by leaving this Vec at whatever its size was before
                self.drawings.shrink_to_fit();
                self.fill_polygon.take();
            },
            SaveSVG(path_buf) => self.save_svg(path_buf),
        }
    }

    /// The main rendering route. Dispatches to other functions as needed.
    fn render(
        &self,
        c: context::Context,
        g: &mut G2d<'_>,
        center: Point,
        drawing: &DrawingState,
        temporary_path: &Option<Path>,
        turtle: &TurtleState,
    ) {
        let background = drawing.background;
        clear(background.into(), g);

        for drawing in &self.drawings {
            match *drawing {
                Drawing::Path(ref path) => self.render_path(c, g, center, path),
                Drawing::Polygon(ref poly) => self.render_polygon(c, g, center, poly.fill_color, poly.vertices.iter()),
            }
        }

        if let Some(&(ref border, ref poly)) = self.fill_polygon.as_ref() {
            // If the temporary_path is not None, we need to add it to the polygon being
            // filled or else the polygon will fall one edge behind in the animation
            let extra = temporary_path.as_ref().map_or(Vec::new(), |&Path { start, end, .. }| {
                if poly.vertices.last().map_or(true, |&v| v != start) {
                    vec![start, end]
                } else {
                    vec![end]
                }
            });
            self.render_polygon(c, g, center, poly.fill_color, poly.vertices.iter().chain(extra.iter()));

            for path in border {
                if path.pen.enabled {
                    self.render_path(c, g, center, path);
                }
            }
        }

        if let Some(ref path) = *temporary_path {
            if path.pen.enabled {
                self.render_path(c, g, center, path);
            }
        }

        self.render_shell(c, g, center, turtle);
    }

    /// Render a path assuming that its pen is enabled
    fn render_path(&self, c: context::Context, g: &mut G2d<'_>, center: Point, path: &Path) {
        let &Path { start, end, ref pen } = path;
        let &Pen { thickness, color, enabled } = pen;
        debug_assert!(enabled, "bug: attempt to render path when pen was not enabled");

        let start = start.to_screen_coords(center);
        let end = end.to_screen_coords(center);

        line(color.into(), thickness, [start.x, start.y, end.x, end.y], c.transform, g);
    }

    /// Render a polygon given its vertices
    fn render_polygon<'a, T: Iterator<Item = &'a Point>>(
        &self,
        c: context::Context,
        g: &mut G2d<'_>,
        center: Point,
        fill_color: Color,
        verts: T,
    ) {
        // Performance note: Why make this function generic instead of just taking Polygon?
        // Answer: render_polygon is called multiple times. It's called repeatedly in a loop, and
        // it is also called when drawing the current fill_polygon. Rather than moving the
        // code to *maybe* add the temporary_path to the rendered polygon into this method, we
        // avoid branching unnecessarily by allowing the repeated caller to do what is fast, then
        // doing the slow thing (checking if the path is None) only once when it is needed.
        //
        // We pass in the points as an Iterator so that they do not need to be collected into any
        // struct. This avoids an allocation that really isn't needed since these are all temporary
        // anyway. Everything is going to get copied anyway on the next line. No need to do it
        // twice.
        //
        // See the commit before this comment was added for the approach that would have required
        // branching in every iteration of the loop where render_polygon is called over and over
        // again.
        let verts = verts.map(|p| p.to_screen_coords(center).into()).collect::<Vec<_>>();
        polygon(fill_color.into(), &verts, c.transform, g);
    }

    /// Draw the turtle's shell
    fn render_shell(
        &self,
        c: context::Context,
        g: &mut G2d<'_>,
        center: Point,
        &TurtleState {
            position,
            heading,
            visible,
            ..
        }: &TurtleState,
    ) {
        // Calculate all the points on the shell by rotating the shell shape by the turtle's
        // heading and moving it to the turtle's position
        if !visible {
            return;
        }

        let cos = heading.cos();
        let sin = heading.sin();
        let turtle_x = position.x;
        let turtle_y = position.y;
        let shell: Vec<_> = [[0., 15.], [10., 0.], [0., -15.]]
            .into_iter()
            .map(|pt| {
                // Rotate each point by the heading and add the current turtle position
                let x = cos * pt[0] - sin * pt[1] + turtle_x;
                let y = sin * pt[0] + cos * pt[1] + turtle_y;
                Point { x, y }.to_screen_coords(center).into()
            })
            .collect();

        // Draw the turtle shell with its background first, then its border
        polygon(color::WHITE.into(), &shell, c.transform, g);
        for i in 0..shell.len() {
            let start = shell[i];
            let end = shell[(i + 1) % shell.len()];

            line(color::BLACK.into(), 1., [start[0], start[1], end[0], end[1]], c.transform, g);
        }
    }

    /// Save the drawings to SVG
    fn save_svg<P: AsRef<path::Path>>(&mut self, path: P) {
        let drawing_state = self.app.drawing();
        let mut document = svg::Document::new()
            .set("viewBox", (0, 0, drawing_state.width, drawing_state.height));

        // set background color - https://stackoverflow.com/a/11293812/9276882
        let bg_color = drawing_state.background;
        let background = SvgRect::new()
            .set("width", "100%")
            .set("height", "100%")
            .set("fill", format!("rgba({},{},{},{})", bg_color.red, bg_color.green, bg_color.blue, bg_color.alpha));

        document = document.add(background);

        let center = Point {x: drawing_state.width as f64 * 0.5, y: drawing_state.height as f64 * 0.5};

        for drawing in &self.drawings {
            match *drawing {
                Drawing::Path(ref path) => {
                    let &Path { start, end, ref pen } = path;
                    let &Pen { thickness, color, enabled: _ } = pen;

                    let start = start.to_screen_coords(center);
                    let end = end.to_screen_coords(center);

                    let line = SvgLine::new()
                        .set("x1", start.x)
                        .set("y1", start.y)
                        .set("x2", end.x)
                        .set("y2", end.y)
                        .set("stroke", format!("rgba({},{},{},{})", color.red, color.green, color.blue, color.alpha))
                        .set("stroke-width", format!("{}px", thickness * 2.0));

                    // Note that in above code `stroke-width` is twice the `thickness`.
                    // As per https://docs.piston.rs/piston_window/piston_window/fn.line.html,
                    // second param of piston_window::line is radius.
                    // So radius (thickness) = 1 takes 2 pixels on screen.
                    // Hence, stroke-width of svg element is double the thickness.

                    document = document.add(line);
                },
                Drawing::Polygon(ref poly) => {
                    let points = poly.vertices.iter()
                        .map(|p| {
                            let point = p.to_screen_coords(center);
                            format!("{},{} ", point.x, point.y)
                        })
                        .fold("".to_string(), |acc, x| acc + &x);

                    let color = poly.fill_color;
                    let polygon = SvgPolygon::new()
                        .set("fill", format!("rgba({},{},{},{})", color.red, color.green, color.blue, color.alpha))
                        .set("points", points);

                    document = document.add(polygon);
                },
            }
        }

        let export_to_svg = svg::save(path, &document);
        match export_to_svg {
            Ok(()) => (),
            Err(error) => eprintln!("Error saving SVG file : {:#?}", error),
        }
    }
}
<commit_msg>Remove rgba_string() from Color, add it as inner function in Renderer::save_svg<commit_after>#[cfg(target_arch = "wasm32")]
compile_error!("This module should not be included when compiling to wasm");

use std::sync::mpsc::{self, TryRecvError};
use std::thread;
use std::path;

use piston_window::{clear, context, line, polygon, AdvancedWindow, Event as PistonEvent, G2d,
    Input, PistonWindow, WindowSettings};

use svg;
use svg::node::element::{Line as SvgLine, Polygon as SvgPolygon, Rectangle as SvgRect};

use crate::app::TurtleApp;
use crate::event::from_piston_event;
use crate::extensions::ConvertScreenCoordinates;
use crate::query::DrawingCommand;
use crate::state::{DrawingState, Path, Pen, Polygon, TurtleState};
use crate::{color, Color, Event, Point};

fn update_window(window: &mut PistonWindow, current: DrawingState, next: DrawingState) -> DrawingState {
    if next.title != current.title {
        window.set_title(next.title.clone());
    }
    if next.width != current.width || next.height != current.height {
        window.set_size((next.width, next.height));
    }
    if next.maximized != current.maximized {
        window.window.window.set_maximized(next.maximized);
    }
    if next.fullscreen != current.fullscreen {
        if next.fullscreen {
            window
                .window
                .window
                .set_fullscreen(Some(window.window.window.get_current_monitor()));
        } else {
            window.window.window.set_fullscreen(None);
        }
    }
    next
}

#[derive(Debug)]
pub enum Drawing {
    Path(Path),
    Polygon(Polygon),
}

pub struct Renderer {
    app: TurtleApp,
    drawings: Vec<Drawing>,
    /// Polygon that is currently in the process of being filled
    /// Removed when EndFill is sent
    fill_polygon: Option<(Vec<Path>, Polygon)>,
}

impl Renderer {
    pub fn new(app: TurtleApp) -> Renderer {
        Self {
            app,
            drawings: Vec::new(),
            fill_polygon: None,
        }
    }

    pub fn run(&mut self, drawing_rx: mpsc::Receiver<DrawingCommand>, events_tx: mpsc::Sender<Event>) {
        let state = self.app.read_only();

        // This check isn't foolproof. Someone can always create a thread named "main".
        if thread::current().name().unwrap_or("") != "main" {
            // In order to maintain compatibility with MacOS, we need to make sure that windows are
            // only created on the main thread. We do this check on all platforms so that no one
            // can accidentally make a change that creates the window off of the main thread.
            unreachable!("bug: windows can only be created on the main thread");
        }

        let mut window: PistonWindow = WindowSettings::new(
            &*state.drawing().title,
            (state.drawing().width, state.drawing().height)
        ).exit_on_esc(true).build().expect("bug: could not build window");

        // We keep a copy of the DrawingState so that we can tell when it is updated and we need
        // to change something on the window
        let mut current_drawing = DrawingState::default();

        let mut center = state.drawing().center;

        'renderloop: while let Some(event) = window.next() {
            match event {
                PistonEvent::Input(Input::Resize(width, height)) => {
                    let width = width as u32;
                    let height = height as u32;
                    if width != current_drawing.width || height != current_drawing.height {
                        let mut drawing = self.app.drawing_mut();
                        drawing.width = width;
                        drawing.height = height;
                    }
                }
                _ => {}
            }

            if let Some(event) = from_piston_event(&event, |pt| pt.to_local_coords(center)) {
                match events_tx.send(event) {
                    Ok(_) => {}
                    // Quit - the server thread must have quit
                    Err(_) => break,
                }
            }

            // Need to handle all of the queries we receive at once so that any lag caused by
            // how long rendering takes doesn't cause any problems
            loop {
                match drawing_rx.try_recv() {
                    Ok(cmd) => self.handle_drawing_command(cmd),
                    Err(TryRecvError::Empty) => break,                    // Do nothing
                    Err(TryRecvError::Disconnected) => break 'renderloop, // Quit
                }
            }

            // Update the window based on any changes in the DrawingState
            current_drawing = update_window(&mut window, current_drawing, state.drawing().clone());

            window.draw_2d(&event, |c, g| {
                let view = c.get_view_size();
                let width = view[0] as f64;
                let height = view[1] as f64;
                center = state.drawing().center.to_screen_coords(Point {
                    x: width * 0.5,
                    y: height * 0.5,
                });

                // We clone the relevant state before rendering so that the rendering thread
                // doesn't need to keep locking, waiting or making the main thread wait
                let drawing = state.drawing().clone();
                let temporary_path = state.temporary_path().clone();
                let turtle = state.turtle().clone();

                self.render(c, g, center, &drawing, &temporary_path, &turtle);
            });
        }
    }

    /// Handles a drawing command sent from the main thread
    fn handle_drawing_command(&mut self, command: DrawingCommand) {
        //NOTE: Do not pass the ReadOnly state to this function. By the time a DrawingCommand is
        // handled, that state may be completely out of date
        use DrawingCommand::*;
        match command {
            StorePath(path) => {
                if self.fill_polygon.is_some() {
                    let &mut (ref mut border, ref mut poly) = self.fill_polygon.as_mut().unwrap();
                    border.push(path.clone());

                    let Path { start, end, .. } = path;
                    if poly.vertices.last().map_or(true, |&v| v != start) {
                        poly.vertices.push(start);
                    }
                    poly.vertices.push(end);
                } else if path.pen.enabled {
                    self.drawings.push(Drawing::Path(path));
                }
            },
            BeginFill(fill_color) => {
                // Calling begin_fill multiple times is okay, it just won't do anything until
                // end_fill is called
                self.fill_polygon = self.fill_polygon.take().or_else(|| {
                    Some((
                        Vec::new(),
                        Polygon {
                            vertices: Vec::new(),
                            fill_color,
                        },
                    ))
                });
            },
            // Calling end_fill multiple times is not a problem
            EndFill => if let Some((border, poly)) = self.fill_polygon.take() {
                // Always add the border over the filled polygon so the border is drawn on top
                self.drawings.push(Drawing::Polygon(poly));
                self.drawings.extend(
                    border
                        .into_iter()
                        .filter_map(|p| if p.pen.enabled { Some(Drawing::Path(p)) } else { None }),
                );
            },
            Clear => {
                self.drawings.clear();
                // Because clear doesn't actually shorten the capacity of the vector
                // We don't want to leak memory by leaving this Vec at whatever its size was before
                self.drawings.shrink_to_fit();
                self.fill_polygon.take();
            },
            SaveSVG(path_buf) => self.save_svg(path_buf),
        }
    }

    /// The main rendering route. Dispatches to other functions as needed.
    fn render(
        &self,
        c: context::Context,
        g: &mut G2d<'_>,
        center: Point,
        drawing: &DrawingState,
        temporary_path: &Option<Path>,
        turtle: &TurtleState,
    ) {
        let background = drawing.background;
        clear(background.into(), g);

        for drawing in &self.drawings {
            match *drawing {
                Drawing::Path(ref path) => self.render_path(c, g, center, path),
                Drawing::Polygon(ref poly) => self.render_polygon(c, g, center, poly.fill_color, poly.vertices.iter()),
            }
        }

        if let Some(&(ref border, ref poly)) = self.fill_polygon.as_ref() {
            // If the temporary_path is not None, we need to add it to the polygon being
            // filled or else the polygon will fall one edge behind in the animation
            let extra = temporary_path.as_ref().map_or(Vec::new(), |&Path { start, end, .. }| {
                if poly.vertices.last().map_or(true, |&v| v != start) {
                    vec![start, end]
                } else {
                    vec![end]
                }
            });
            self.render_polygon(c, g, center, poly.fill_color, poly.vertices.iter().chain(extra.iter()));

            for path in border {
                if path.pen.enabled {
                    self.render_path(c, g, center, path);
                }
            }
        }

        if let Some(ref path) = *temporary_path {
            if path.pen.enabled {
                self.render_path(c, g, center, path);
            }
        }

        self.render_shell(c, g, center, turtle);
    }

    /// Render a path assuming that its pen is enabled
    fn render_path(&self, c: context::Context, g: &mut G2d<'_>, center: Point, path: &Path) {
        let &Path { start, end, ref pen } = path;
        let &Pen { thickness, color, enabled } = pen;
        debug_assert!(enabled, "bug: attempt to render path when pen was not enabled");

        let start = start.to_screen_coords(center);
        let end = end.to_screen_coords(center);

        line(color.into(), thickness, [start.x, start.y, end.x, end.y], c.transform, g);
    }

    /// Render a polygon given its vertices
    fn render_polygon<'a, T: Iterator<Item = &'a Point>>(
        &self,
        c: context::Context,
        g: &mut G2d<'_>,
        center: Point,
        fill_color: Color,
        verts: T,
    ) {
        // Performance note: Why make this function generic instead of just taking Polygon?
        // Answer: render_polygon is called multiple times. It's called repeatedly in a loop, and
        // it is also called when drawing the current fill_polygon. Rather than moving the
        // code to *maybe* add the temporary_path to the rendered polygon into this method, we
        // avoid branching unnecessarily by allowing the repeated caller to do what is fast, then
        // doing the slow thing (checking if the path is None) only once when it is needed.
        //
        // We pass in the points as an Iterator so that they do not need to be collected into any
        // struct. This avoids an allocation that really isn't needed since these are all temporary
        // anyway. Everything is going to get copied anyway on the next line. No need to do it
        // twice.
        //
        // See the commit before this comment was added for the approach that would have required
        // branching in every iteration of the loop where render_polygon is called over and over
        // again.
        let verts = verts.map(|p| p.to_screen_coords(center).into()).collect::<Vec<_>>();
        polygon(fill_color.into(), &verts, c.transform, g);
    }

    /// Draw the turtle's shell
    fn render_shell(
        &self,
        c: context::Context,
        g: &mut G2d<'_>,
        center: Point,
        &TurtleState {
            position,
            heading,
            visible,
            ..
        }: &TurtleState,
    ) {
        // Calculate all the points on the shell by rotating the shell shape by the turtle's
        // heading and moving it to the turtle's position
        if !visible {
            return;
        }

        let cos = heading.cos();
        let sin = heading.sin();
        let turtle_x = position.x;
        let turtle_y = position.y;
        let shell: Vec<_> = [[0., 15.], [10., 0.], [0., -15.]]
            .into_iter()
            .map(|pt| {
                // Rotate each point by the heading and add the current turtle position
                let x = cos * pt[0] - sin * pt[1] + turtle_x;
                let y = sin * pt[0] + cos * pt[1] + turtle_y;
                Point { x, y }.to_screen_coords(center).into()
            })
            .collect();

        // Draw the turtle shell with its background first, then its border
        polygon(color::WHITE.into(), &shell, c.transform, g);
        for i in 0..shell.len() {
            let start = shell[i];
            let end = shell[(i + 1) % shell.len()];

            line(color::BLACK.into(), 1., [start[0], start[1], end[0], end[1]], c.transform, g);
        }
    }

    /// Save the drawings to SVG
    fn save_svg(&mut self, path: &path::Path) {
        // Returns rgba string of Color in CSS functional syntax
        fn rgba_string(color: Color) -> String {
            format!("rgba({}, {}, {}, {})", color.red as u8, color.green as u8, color.blue as u8, color.alpha)
        }

        let drawing_state = self.app.drawing();
        let mut document = svg::Document::new()
            .set("viewBox", (0, 0, drawing_state.width, drawing_state.height));

        // set background color - https://stackoverflow.com/a/11293812/9276882
        let bg_color = drawing_state.background;
        let background = SvgRect::new()
            .set("width", "100%")
            .set("height", "100%")
            .set("fill", rgba_string(bg_color));

        document = document.add(background);

        let center = drawing_state.center.to_screen_coords(Point {
            x: drawing_state.width as f64 * 0.5,
            y: drawing_state.height as f64 * 0.5,
        });

        for drawing in &self.drawings {
            match *drawing {
                Drawing::Path(ref path) => {
                    let &Path { start, end, ref pen } = path;
                    let &Pen { thickness, color, enabled: _ } = pen;

                    let start = start.to_screen_coords(center);
                    let end = end.to_screen_coords(center);

                    let line = SvgLine::new()
                        .set("x1", start.x)
                        .set("y1", start.y)
                        .set("x2", end.x)
                        .set("y2", end.y)
                        .set("stroke", rgba_string(*color))
                        .set("stroke-width", format!("{}px", thickness * 2.0));

                    // Note that in above code `stroke-width` is twice the `thickness`.
                    // As per https://docs.piston.rs/piston_window/piston_window/fn.line.html,
                    // second param of piston_window::line is radius.
                    // So radius (thickness) = 1 takes 2 pixels on screen.
                    // Hence, stroke-width of svg element is double the thickness.

                    document = document.add(line);
                },
                Drawing::Polygon(ref poly) => {
                    let points = poly.vertices.iter()
                        .map(|p| {
                            let point = p.to_screen_coords(center);
                            format!("{},{} ", point.x, point.y)
                        })
                        .fold("".to_string(), |acc, x| acc + &x);

                    let color = poly.fill_color;
                    let polygon = SvgPolygon::new()
                        .set("fill", rgba_string(poly.fill_color))
                        .set("points", points);

                    document = document.add(polygon);
                },
            }
        }

        let export_to_svg = svg::save(path, &document);
        match export_to_svg {
            Ok(()) => (),
            Err(error) => eprintln!("Error saving SVG file : {:#?}", error),
        }
    }
}
<|endoftext|>


<commit_before>use std::io::Read;
use std::convert::From;
use std::str;
use hyper;
use hyper::header::{Headers, ContentLength, ContentType};

pub use hyper::status::StatusCode;
pub type Codes = StatusCode;
pub type HyperResponse = hyper::client::Response;

#[derive(Debug)]
pub struct Response {
    content: Vec<u8>,
    hr: HyperResponse,
}

impl From<HyperResponse> for Response {
    fn from(mut raw: HyperResponse) -> Self {
        let mut content = match raw.headers.get::<ContentLength>() {
            Some(&ContentLength(length)) => Vec::with_capacity(length as usize),
            None => Vec::new(),
        };

        if raw.read_to_end(&mut content).is_err() {
            content = Vec::new()
        }

        Response {
            content: content,
            hr: raw,
        }
    }
}

impl<'a> Response {
    pub fn url(&self) -> &str {
        self.hr.url.as_str()
    }

    pub fn status_code(&self) -> Codes {
        self.hr.status
    }

    pub fn reason(&self) -> &str {
        self.hr.status.canonical_reason().unwrap_or("UNAVAILABLE")
    }

    pub fn ok(&self) -> bool {
        self.hr.status == StatusCode::Ok
    }

    pub fn text(&'a self) -> Option<&'a str> {
        str::from_utf8(&self.content).ok()
    }

    pub fn content(&'a self) -> &'a Vec<u8> {
        &self.content
    }

    pub fn is_json(&self) -> bool {
        self.hr.headers.get::<ContentType>() == Some(&ContentType::json())
    }

    pub fn headers(&self) -> &Headers {
        &self.hr.headers
    }
}
<commit_msg>Rename Response field (hr -> inner)<commit_after>use std::io::Read;
use std::convert::From;
use std::str;
use hyper;
use hyper::header::{Headers, ContentLength, ContentType};

pub use hyper::status::StatusCode;
pub type Codes = StatusCode;
pub type HyperResponse = hyper::client::Response;

#[derive(Debug)]
pub struct Response {
    content: Vec<u8>,
    inner: HyperResponse,
}

impl From<HyperResponse> for Response {
    fn from(mut raw: HyperResponse) -> Self {
        let mut content = match raw.headers.get::<ContentLength>() {
            Some(&ContentLength(length)) => Vec::with_capacity(length as usize),
            None => Vec::new(),
        };

        if raw.read_to_end(&mut content).is_err() {
            content = Vec::new()
        }

        Response {
            content: content,
            inner: raw,
        }
    }
}

impl<'a> Response {
    pub fn url(&self) -> &str {
        self.inner.url.as_str()
    }

    pub fn status_code(&self) -> Codes {
        self.inner.status
    }

    pub fn reason(&self) -> &str {
        self.inner.status.canonical_reason().unwrap_or("UNAVAILABLE")
    }

    pub fn ok(&self) -> bool {
        self.inner.status == StatusCode::Ok
    }

    pub fn text(&'a self) -> Option<&'a str> {
        str::from_utf8(&self.content).ok()
    }

    pub fn content(&'a self) -> &'a Vec<u8> {
        &self.content
    }

    pub fn is_json(&self) -> bool {
        self.inner.headers.get::<ContentType>() == Some(&ContentType::json())
    }

    pub fn headers(&self) -> &Headers {
        &self.inner.headers
    }
}
<|endoftext|>


<commit_before>//Copyright (c) 2016, Ruslan Baratov, Alex Frappier Lachapelle
//All rights reserved.

use std::collections::BTreeMap;
use std::fmt;
use std::sync::{Arc, Mutex};

use config;
use webhooks;

include!("logger_macros.rs");

////////////////////////////////////////////////////////////
//                         Command                        //
////////////////////////////////////////////////////////////

//                            Config,                             Raw webhook,            Arguments
pub type CommandCallback = fn(&Arc<Mutex<config::ConfigHandler>>, webhooks::WebhookEvent, Vec<&str>) -> Result<String, String>;

pub struct Command {
    pub requires_please: bool,
    pub whitelist_only:  bool,
    pub callback:        CommandCallback
}

impl Command {
    pub fn new(requires_please: bool, whitelist_only: bool, callback: CommandCallback) -> Command {
        Command{
            requires_please: requires_please,
            whitelist_only:  whitelist_only,
            callback:        callback
        }
    }
}

impl fmt::Debug for Command {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Command {{requires_please: {}, whitelist_only: {}, callback: fn(&Arc<Mutex<config::ConfigHandler>>, webhooks::WebhookEvent, Vec<&str>) -> Result<String, String>}}", self.requires_please, self.whitelist_only)
    }
}

////////////////////////////////////////////////////////////
//                     CommandHandler                     //
////////////////////////////////////////////////////////////

#[derive(Debug)]
pub struct CommandHandler {
    config:   Arc<Mutex<config::ConfigHandler>>,
    commands: BTreeMap<String, Command>
}

impl CommandHandler {

    pub fn new(tsconfig: &Arc<Mutex<config::ConfigHandler>>) -> CommandHandler {

        thread_trace!("commands.rs: CommandHandler::new(tsconfig)");

        //Register commands
        let mut commands: BTreeMap<String, Command> = BTreeMap::new();
        commands.insert(String::from("ping"), Command::new(false, false, ping));

        CommandHandler {
            config:   tsconfig.clone(),
            commands: commands
        }
    }

    pub fn parse_command(&self, webhook: webhooks::WebhookEvent) {

        thread_trace!("commands.rs: CommandHandler::parse_command(&self, webhook)");

        let mut tokens: Vec<&str>   = webhook.command.split_whitespace().collect();
        let mut is_please_provided  = false;
        let mut is_user_whitelisted = false;
        let mut next_token_index    = 0;
        let mut bot_name            = String::new();

        thread_debug!("Command tokens: {:?}", tokens);

        //Check if please was said
        if tokens[0].to_lowercase() == "please" {
            is_please_provided = true;
            next_token_index   = 1;
        }
        thread_debug!("Please was said: {}", is_please_provided);

        //Check if user is whitelisted for restricted commands
        //  Restricted scope, we are using the config here but
        //  the callback can also use it so we force the mutex
        //  to unlock before letting the callback lock it
        //  given that locking twice will induce a panic.
        {
            let mut config      = self.config.lock().unwrap();
            is_user_whitelisted = config.whitelist_validate_user(webhook.clone().user);
            bot_name            = try!(config.get_string("config", "github_bot_name"));
        }

        //Ignore commands/responses from the bot
        thread_trace!("Check if command is from bot.");
        if bot_name == webhook.user {
            thread_trace!("Command is from bot, return.");
            return;
        }

        //Find command among registered commands
        thread_trace!("Check if command exists.");
        thread_debug!("Looking for command: {}", tokens[next_token_index]);
        let command = match self.commands.get(tokens[next_token_index]) {
            Some(command) => {
                thread_trace!("Command exists.");
                command
            },
            None          => {
                thread_trace!("Command does not exists, send response.");
                respond(&self.config, webhook.clone(), String::from("Sorry the command was not found."));
                return;
            }
        };

        //Check if please and whitelist is required
        let mut run_cmd         = false;
        let mut response_prefix = String::new();

        thread_trace!("Check for whitelist and please.");
        thread_debug!("is_please_provided:  {}", is_please_provided);
        thread_debug!("is_user_whitelisted: {}", is_user_whitelisted);

        if !(command.whitelist_only && !is_user_whitelisted) {
            if (command.requires_please && is_please_provided) || (!command.requires_please && !is_please_provided) {
                run_cmd = true;
            } else if !command.requires_please && is_please_provided {
                run_cmd         = true;
                response_prefix = String::from("You didn't need to say please but thanks anyways :smiley: \\r\\n\\r\\nOhh and: \\r\\n");
            } else if command.requires_please && !is_please_provided {
                //TODO: keep please state
                respond(&self.config, webhook.clone(), String::from("Whats the magic word?"));
            }
        } else {
            respond(&self.config, webhook.clone(), String::from("Sorry! That command if for whitelisted people only!"));
        }

        thread_debug!("run_cmd: {}", run_cmd);

        if run_cmd {
            match (command.callback)(&self.config, webhook.clone(), tokens.split_off(next_token_index)) {
                Ok(msg)  => {
                    respond(&self.config, webhook.clone(), format!("{}{}", response_prefix, msg));
                }
                Err(msg) => {
                    respond(&self.config, webhook.clone(), format!("An error occurred while executing the command: {}", msg));
                }
            }
        }
    }
}

////////////////////////////////////////////////////////////
//                        Callbacks                       //
////////////////////////////////////////////////////////////

#[allow(unused_variables)]
pub fn ping(tsconfig: &Arc<Mutex<config::ConfigHandler>>, raw_event: webhooks::WebhookEvent, args: Vec<&str>) -> Result<String, String> {
    return Ok(String::from("Pong"))
}

////////////////////////////////////////////////////////////
//                          Utils                         //
////////////////////////////////////////////////////////////

pub fn respond(tsconfig: &Arc<Mutex<config::ConfigHandler>>, raw_event: webhooks::WebhookEvent, msg: String) {

    thread_trace!("commands.rs: respond(tsconfig, raw_event, msg)");

    //TODO: Don't forget to change this when refactoring config
    //Get repo were following
    let github_follow_repo: String;
    let github_owner_token: String;
    {
        let mut config = tsconfig.lock().unwrap();
        match config.get_string("config", "github_follow_repo") {
            Ok(_github_follow_repo) => github_follow_repo = _github_follow_repo,
            Err(err)                => {
                thread_error!("Failed to acquire \"github_follow_repo\": {}", err);
                panic!("Failed to acquire \"github_follow_repo\": {}", err);
            }
        }

        //Get owner api token
        match config.get_string("config", "github_bot_token") {
            Ok(_github_owner_token) => github_owner_token = _github_owner_token,
            Err(err)                => {
                thread_error!("Error getting  the \"github_owner_token\" value from config: {}", err);
                panic!("Error getting the \"github_owner_token\" value from config: {}", err);
            }
        }
    }

    let endpoint = format!("repos/{}/issues/{}/comments?access_token={}", github_follow_repo, raw_event.number, github_owner_token);
    let message  = format!("{{\"body\": \"@{} {}\"}}", raw_event.user, msg);
    match webhooks::github_post_request(endpoint, message) {
        Ok(())   => (),
        Err(err) => {thread_error!("{}", err);}
    }
}
<commit_msg>Fixed compile failure<commit_after>//Copyright (c) 2016, Ruslan Baratov, Alex Frappier Lachapelle
//All rights reserved.

use std::collections::BTreeMap;
use std::fmt;
use std::sync::{Arc, Mutex};

use config;
use webhooks;

include!("logger_macros.rs");

////////////////////////////////////////////////////////////
//                         Command                        //
////////////////////////////////////////////////////////////

//                            Config,                             Raw webhook,            Arguments
pub type CommandCallback = fn(&Arc<Mutex<config::ConfigHandler>>, webhooks::WebhookEvent, Vec<&str>) -> Result<String, String>;

pub struct Command {
    pub requires_please: bool,
    pub whitelist_only:  bool,
    pub callback:        CommandCallback
}

impl Command {
    pub fn new(requires_please: bool, whitelist_only: bool, callback: CommandCallback) -> Command {
        Command{
            requires_please: requires_please,
            whitelist_only:  whitelist_only,
            callback:        callback
        }
    }
}

impl fmt::Debug for Command {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Command {{requires_please: {}, whitelist_only: {}, callback: fn(&Arc<Mutex<config::ConfigHandler>>, webhooks::WebhookEvent, Vec<&str>) -> Result<String, String>}}", self.requires_please, self.whitelist_only)
    }
}

////////////////////////////////////////////////////////////
//                     CommandHandler                     //
////////////////////////////////////////////////////////////

#[derive(Debug)]
pub struct CommandHandler {
    config:   Arc<Mutex<config::ConfigHandler>>,
    commands: BTreeMap<String, Command>
}

impl CommandHandler {

    pub fn new(tsconfig: &Arc<Mutex<config::ConfigHandler>>) -> CommandHandler {

        thread_trace!("commands.rs: CommandHandler::new(tsconfig)");

        //Register commands
        let mut commands: BTreeMap<String, Command> = BTreeMap::new();
        commands.insert(String::from("ping"), Command::new(false, false, ping));

        CommandHandler {
            config:   tsconfig.clone(),
            commands: commands
        }
    }

    pub fn parse_command(&self, webhook: webhooks::WebhookEvent) {

        thread_trace!("commands.rs: CommandHandler::parse_command(&self, webhook)");

        let mut tokens: Vec<&str>   = webhook.command.split_whitespace().collect();
        let mut is_please_provided  = false;
        let mut is_user_whitelisted = false;
        let mut next_token_index    = 0;
        let mut bot_name            = String::new();

        thread_debug!("Command tokens: {:?}", tokens);

        //Check if please was said
        if tokens[0].to_lowercase() == "please" {
            is_please_provided = true;
            next_token_index   = 1;
        }
        thread_debug!("Please was said: {}", is_please_provided);

        //Check if user is whitelisted for restricted commands
        //  Restricted scope, we are using the config here but
        //  the callback can also use it so we force the mutex
        //  to unlock before letting the callback lock it
        //  given that locking twice will induce a panic.
        {
            let mut config      = self.config.lock().unwrap();
            is_user_whitelisted = config.whitelist_validate_user(webhook.clone().user);
            bot_name            = match config.get_string("config", "github_bot_name") {
                Ok(name) => name,
                Err(err) => {
                    thread_error!("Failed to acquire \"github_bot_name\": {}", err);
                    panic!("Failed to acquire \"github_bot_name\": {}", err);
                }
            }
        }

        //Ignore commands/responses from the bot
        thread_trace!("Check if command is from bot.");
        if bot_name == webhook.user {
            thread_trace!("Command is from bot, return.");
            return;
        }

        //Find command among registered commands
        thread_trace!("Check if command exists.");
        thread_debug!("Looking for command: {}", tokens[next_token_index]);
        let command = match self.commands.get(tokens[next_token_index]) {
            Some(command) => {
                thread_trace!("Command exists.");
                command
            },
            None          => {
                thread_trace!("Command does not exists, send response.");
                respond(&self.config, webhook.clone(), String::from("Sorry the command was not found."));
                return;
            }
        };

        //Check if please and whitelist is required
        let mut run_cmd         = false;
        let mut response_prefix = String::new();

        thread_trace!("Check for whitelist and please.");
        thread_debug!("is_please_provided:  {}", is_please_provided);
        thread_debug!("is_user_whitelisted: {}", is_user_whitelisted);

        if !(command.whitelist_only && !is_user_whitelisted) {
            if (command.requires_please && is_please_provided) || (!command.requires_please && !is_please_provided) {
                run_cmd = true;
            } else if !command.requires_please && is_please_provided {
                run_cmd         = true;
                response_prefix = String::from("You didn't need to say please but thanks anyways :smiley: \\r\\n\\r\\nOhh and: \\r\\n");
            } else if command.requires_please && !is_please_provided {
                //TODO: keep please state
                respond(&self.config, webhook.clone(), String::from("Whats the magic word?"));
            }
        } else {
            respond(&self.config, webhook.clone(), String::from("Sorry! That command if for whitelisted people only!"));
        }

        thread_debug!("run_cmd: {}", run_cmd);

        if run_cmd {
            match (command.callback)(&self.config, webhook.clone(), tokens.split_off(next_token_index)) {
                Ok(msg)  => {
                    respond(&self.config, webhook.clone(), format!("{}{}", response_prefix, msg));
                }
                Err(msg) => {
                    respond(&self.config, webhook.clone(), format!("An error occurred while executing the command: {}", msg));
                }
            }
        }
    }
}

////////////////////////////////////////////////////////////
//                        Callbacks                       //
////////////////////////////////////////////////////////////

#[allow(unused_variables)]
pub fn ping(tsconfig: &Arc<Mutex<config::ConfigHandler>>, raw_event: webhooks::WebhookEvent, args: Vec<&str>) -> Result<String, String> {
    return Ok(String::from("Pong"))
}

////////////////////////////////////////////////////////////
//                          Utils                         //
////////////////////////////////////////////////////////////

pub fn respond(tsconfig: &Arc<Mutex<config::ConfigHandler>>, raw_event: webhooks::WebhookEvent, msg: String) {

    thread_trace!("commands.rs: respond(tsconfig, raw_event, msg)");

    //TODO: Don't forget to change this when refactoring config
    //Get repo were following
    let github_follow_repo: String;
    let github_owner_token: String;
    {
        let mut config = tsconfig.lock().unwrap();
        match config.get_string("config", "github_follow_repo") {
            Ok(_github_follow_repo) => github_follow_repo = _github_follow_repo,
            Err(err)                => {
                thread_error!("Failed to acquire \"github_follow_repo\": {}", err);
                panic!("Failed to acquire \"github_follow_repo\": {}", err);
            }
        }

        //Get owner api token
        match config.get_string("config", "github_bot_token") {
            Ok(_github_owner_token) => github_owner_token = _github_owner_token,
            Err(err)                => {
                thread_error!("Error getting  the \"github_owner_token\" value from config: {}", err);
                panic!("Error getting the \"github_owner_token\" value from config: {}", err);
            }
        }
    }

    let endpoint = format!("repos/{}/issues/{}/comments?access_token={}", github_follow_repo, raw_event.number, github_owner_token);
    let message  = format!("{{\"body\": \"@{} {}\"}}", raw_event.user, msg);
    match webhooks::github_post_request(endpoint, message) {
        Ok(())   => (),
        Err(err) => {thread_error!("{}", err);}
    }
}
<|endoftext|>