<commit_before>use std::default::Default;

use ast::Expr;
use ast::ExprType::*;
use ast::Function;
use ast::Statement;
use ast::StatementType::*;
use ast::visit::Visitor;
use ast::visit::walk_expr;

use error::ErrorCode;
use error::ParseError;

use lexer::position::Position;
use self::leave::{Leave, ReturnState};
use self::init::InitVars;

mod init;
mod leave;

pub struct ReturnCheck<'a> {
    errors: Vec<ParseError>,

    initialized_vars: InitVars<usize>,
    fct: Option<&'a Function>,
}

impl<'a> ReturnCheck<'a> {
    pub fn new() -> ReturnCheck<'a> {
        ReturnCheck {
            errors: Vec::new(),
            initialized_vars: InitVars::new(),
            fct: None,
        }
    }

    pub fn errors(self) -> Vec<ParseError> {
        self.errors
    }

    fn reset_fct(&mut self, fct: &Function) {
        // reset initialized vars with each function
        self.initialized_vars.reset();

        // parameters are always initialized
        for i in &fct.params {
            self.initialized_vars.insert(*i);
        }
    }

    fn check_block(&mut self, stmts: &Vec<Box<Statement>>) -> ReturnState {
        let mut leave = ReturnState::new();

        if stmts.len() == 0 {
            return leave;
        }

        for stmt in stmts {
            if leave.stops {
                self.errors.push(ParseError {
                    position: stmt.position,
                    code: ErrorCode::UnreachableCode,
                    message: format!("statement unreachable")
                });

                return leave;
            }

            leave.seq(self.visit_stmt(stmt));
        }

        leave
    }
}

fn end_position(s: &Statement) -> Position {
    match s.stmt {
        Block(ref stmts) if stmts.len() > 0 => {
            stmts[stmts.len()-1].position
        }

        _ => s.position
    }
}

impl<'a> Visitor<'a> for ReturnCheck<'a> {
    type Returns = ReturnState;

    fn visit_fct(&mut self, fct: &'a Function) -> ReturnState {
        self.fct = Some(fct);

        // reset initialized variables for each function
        self.reset_fct(fct);

        let leave = self.visit_stmt(&fct.block);

        if !fct.return_type.is_unit() && leave.returns != Leave::Fix {
            self.errors.push(ParseError {
                position: end_position(&fct.block),
                code: ErrorCode::NoReturnValue,
                message: format!("function `{}` does not return a value in all code paths", fct.name)
            })
        }

        leave
    }

    fn visit_stmt(&mut self, s: &Statement) -> ReturnState {
        match s.stmt {
            Var(varind, _, ref expr) => {
                if let Some(expr) = expr.as_ref() {
                    self.visit_expr(expr);
                    self.initialized_vars.insert(varind);
                }

                ReturnState::new()
            }

            If(ref cond, ref tblock, ref eblock) => {
                self.visit_expr(cond);

                self.initialized_vars.push();
                let tblock = self.visit_stmt(tblock);
                let added_then = self.initialized_vars.pop();

                self.initialized_vars.push();
                let eblock = if let Some(eblock) = eblock.as_ref() {
                    self.visit_stmt(eblock)
                } else {
                    ReturnState::new()
                };
                let added_else = self.initialized_vars.pop();

                let union = added_then.intersection(&added_else).cloned().collect();
                self.initialized_vars.push_hash(union);
                tblock.merge(eblock)
            }

            Block(ref stmts) => {
                self.check_block(stmts)
            }

            While(ref cond, ref block) => {
                self.visit_expr(cond);

                self.initialized_vars.push();
                let ret = self.visit_stmt(block);
                self.initialized_vars.pop();

                ReturnState::for_while(ret)
            }

            Loop(ref block) => {
                ReturnState::for_loop(self.visit_stmt(block))
            }

            Return(ref expr) => {
                if let Some(expr) = expr.as_ref() {
                    self.visit_expr(expr);
                }

                ReturnState::returns()
            }

            ExprStmt(ref expr) => {
                self.visit_expr(expr);

                ReturnState::new()
            }

            Break => ReturnState::breaks(),
            Continue => ReturnState::continues(),

            _ => ReturnState::new()
        }
    }

    fn visit_expr(&mut self, e: &Expr) -> ReturnState {
        match e.expr {
            Assign(ref var, ref expr) => {
                self.visit_expr(expr);

                match var.expr {
                    Ident(varind) => {
                        self.initialized_vars.insert(varind);
                    }

                    _ => unreachable!()
                }

                Default::default()
            }

            Ident(varind) => {
                if !self.initialized_vars.contains(&varind) {
                    let fct = self.fct.unwrap();
                    let var = &fct.vars[varind];

                    self.errors.push(ParseError {
                        position: e.position,
                        code: ErrorCode::UninitializedVar,
                        message: format!("variable `{}` might not be initialized", var.name)
                    });
                }

                Default::default()
            }

            _ => walk_expr(self, e)
        }
    }
}

#[cfg(test)]
mod tests {
    use ast::Function;

    use error::ErrorCode;
    use parser::Parser;

    fn parse(code: &'static str) -> Function {
        let mut prog = match Parser::from_str(code).parse() {
            Ok(prog) => prog,
            Err(err) => panic!("`{}` throws `{}` but no error expected", code, err),
        };

        prog.functions.swap_remove(0)
    }

    fn err(code: &'static str, error_code: ErrorCode, line: u32, col: u32) {
        let err = match Parser::from_str(code).parse() {
            Ok(_) => panic!("no error found in `{}`, expected {:?} at {}:{}",
                            code, error_code, line, col),
            Err(err) => err,
        };

        assert_eq!(error_code, err.code);
        assert_eq!(line, err.position.line);
        assert_eq!(col, err.position.column);
    }

    #[test]
    fn check_initialized() {
        parse("fn f(a: int) { a; }");
        parse("fn f { var a = 3; a; }");
        parse("fn f { var a : int; a = 3; a; }");

        err("fn f { var a : int; a; }", ErrorCode::UninitializedVar, 1, 21);
        err("fn f -> int { var a : int; return a; }", ErrorCode::UninitializedVar, 1, 35);

        parse("fn f { var a : int; if true { a = 1; } else { a = 2; } a; }");
        err("fn f { var a : int; if true {} else { a = 2; } a; }", ErrorCode::UninitializedVar, 1, 48);
        err("fn f { var a : int; if true { a = 1; } else {} a; }", ErrorCode::UninitializedVar, 1, 48);

        err("fn f { var a : bool; while a {} }", ErrorCode::UninitializedVar, 1, 28);
        err("fn f { var a : int; while true { a = 1; } a; }", ErrorCode::UninitializedVar, 1, 43);
    }

    #[test]
    fn check_return() {
        err("fn f -> int { 1; }", ErrorCode::NoReturnValue, 1, 15);
        err("fn f -> int {}", ErrorCode::NoReturnValue, 1, 13);
        err("fn f -> int { return 1; 1; }", ErrorCode::UnreachableCode, 1, 25);
        err("fn f { return; 1; }", ErrorCode::UnreachableCode, 1, 16);

        parse("fn f -> int { return 1; }");
        parse("fn f { return; }");
        parse("fn f { 1; }");
        parse("fn f {}");

        parse("fn f -> int { while true { return 1; } }");
        err("fn f -> int { while true { return 1; } return 1; }", ErrorCode::UnreachableCode, 1, 40);

        parse("fn f { while true { break; } return; }");
        parse("fn f { while true { continue; } return; }");

        parse("fn f->int {\
               if true { return 1; }\
               else { return 2; } }");
        err("fn f->int {\
             if true { return 1; } }", ErrorCode::NoReturnValue, 1, 12);
        err("fn f->int {\
             if true { return 1; } else { } }", ErrorCode::NoReturnValue, 1, 12);
        err("fn f->int {\
             if true { return 1; } else { return 2; }\
             return 3; }",
           ErrorCode::UnreachableCode, 1, 52);
    }

    #[test]
    fn check_break() {
        parse("fn x { while true { break; } return; }");
        parse("fn x { loop { break; } return; }");

        parse("fn x { loop { loop { break; } break; } }");
        parse("fn x { while true { while true { break; } break; } }");

        parse("fn x { loop { if true { break; } break; } }");
        parse("fn x { while true { if true { break; } break; } }");

        err("fn x { loop { if true { break; } else { break; } break; } }",
            ErrorCode::UnreachableCode, 1, 50);
        err("fn x { while true { if true { break; } else { break; } break; } }",
            ErrorCode::UnreachableCode, 1, 56);

        err("fn x { while true { break; return; } }", ErrorCode::UnreachableCode, 1, 28);
        err("fn x { loop { break; return; } }", ErrorCode::UnreachableCode, 1, 22);

        err("fn x { break; }", ErrorCode::MisplacedBreak, 1, 8);
        err("fn x { if true { break; } }", ErrorCode::MisplacedBreak, 1, 18);
        err("fn x { loop { if true { break; } else { return; } break; } }",
            ErrorCode::UnreachableCode, 1, 51);
    }

    #[test]
    fn check_continue() {
        parse("fn x { while true { continue; } return; }");
        err("fn x { loop { continue; } return; }",
           ErrorCode::UnreachableCode, 1, 27);

        parse("fn x { while true { while true { continue; } continue; } }");
        err("fn x { loop { loop { continue; } continue; } }",
           ErrorCode::UnreachableCode, 1, 34);

        parse("fn x { while true { if true { continue; } continue; } }");
        parse("fn x { loop { if true { continue; } continue; } }");

        err("fn x { loop { if true { continue; } else { continue; } continue; } }",
            ErrorCode::UnreachableCode, 1, 56);
        err("fn x { while true { if true { continue; } else { continue; } continue; } }",
            ErrorCode::UnreachableCode, 1, 62);

        err("fn x { while true { continue; return; } }", ErrorCode::UnreachableCode, 1, 31);
        err("fn x { loop { continue; return; } }", ErrorCode::UnreachableCode, 1, 25);

        err("fn x { continue; }", ErrorCode::MisplacedContinue, 1, 8);
        err("fn x { if true { continue; } }", ErrorCode::MisplacedContinue, 1, 18);
        err("fn x { loop { if true { continue; } else { return; } continue; } }",
            ErrorCode::UnreachableCode, 1, 54);
    }
}
<commit_msg>renamed added_then to vars_then<commit_after>use std::default::Default;

use ast::Expr;
use ast::ExprType::*;
use ast::Function;
use ast::Statement;
use ast::StatementType::*;
use ast::visit::Visitor;
use ast::visit::walk_expr;

use error::ErrorCode;
use error::ParseError;

use lexer::position::Position;
use self::leave::{Leave, ReturnState};
use self::init::InitVars;

mod init;
mod leave;

pub struct ReturnCheck<'a> {
    errors: Vec<ParseError>,

    initialized_vars: InitVars<usize>,
    fct: Option<&'a Function>,
}

impl<'a> ReturnCheck<'a> {
    pub fn new() -> ReturnCheck<'a> {
        ReturnCheck {
            errors: Vec::new(),
            initialized_vars: InitVars::new(),
            fct: None,
        }
    }

    pub fn errors(self) -> Vec<ParseError> {
        self.errors
    }

    fn reset_fct(&mut self, fct: &Function) {
        // reset initialized vars with each function
        self.initialized_vars.reset();

        // parameters are always initialized
        for i in &fct.params {
            self.initialized_vars.insert(*i);
        }
    }

    fn check_block(&mut self, stmts: &Vec<Box<Statement>>) -> ReturnState {
        let mut leave = ReturnState::new();

        if stmts.len() == 0 {
            return leave;
        }

        for stmt in stmts {
            if leave.stops {
                self.errors.push(ParseError {
                    position: stmt.position,
                    code: ErrorCode::UnreachableCode,
                    message: format!("statement unreachable")
                });

                return leave;
            }

            leave.seq(self.visit_stmt(stmt));
        }

        leave
    }
}

fn end_position(s: &Statement) -> Position {
    match s.stmt {
        Block(ref stmts) if stmts.len() > 0 => {
            stmts[stmts.len()-1].position
        }

        _ => s.position
    }
}

impl<'a> Visitor<'a> for ReturnCheck<'a> {
    type Returns = ReturnState;

    fn visit_fct(&mut self, fct: &'a Function) -> ReturnState {
        self.fct = Some(fct);

        // reset initialized variables for each function
        self.reset_fct(fct);

        let leave = self.visit_stmt(&fct.block);

        if !fct.return_type.is_unit() && leave.returns != Leave::Fix {
            self.errors.push(ParseError {
                position: end_position(&fct.block),
                code: ErrorCode::NoReturnValue,
                message: format!("function `{}` does not return a value in all code paths", fct.name)
            })
        }

        leave
    }

    fn visit_stmt(&mut self, s: &Statement) -> ReturnState {
        match s.stmt {
            Var(varind, _, ref expr) => {
                if let Some(expr) = expr.as_ref() {
                    self.visit_expr(expr);
                    self.initialized_vars.insert(varind);
                }

                ReturnState::new()
            }

            If(ref cond, ref tblock, ref eblock) => {
                self.visit_expr(cond);

                self.initialized_vars.push();
                let tblock = self.visit_stmt(tblock);
                let vars_then = self.initialized_vars.pop();

                self.initialized_vars.push();
                let eblock = if let Some(eblock) = eblock.as_ref() {
                    self.visit_stmt(eblock)
                } else {
                    ReturnState::new()
                };
                let vars_else = self.initialized_vars.pop();

                let union = vars_then.intersection(&vars_else).cloned().collect();
                self.initialized_vars.push_hash(union);
                tblock.merge(eblock)
            }

            Block(ref stmts) => {
                self.check_block(stmts)
            }

            While(ref cond, ref block) => {
                self.visit_expr(cond);

                self.initialized_vars.push();
                let ret = self.visit_stmt(block);
                self.initialized_vars.pop();

                ReturnState::for_while(ret)
            }

            Loop(ref block) => {
                ReturnState::for_loop(self.visit_stmt(block))
            }

            Return(ref expr) => {
                if let Some(expr) = expr.as_ref() {
                    self.visit_expr(expr);
                }

                ReturnState::returns()
            }

            ExprStmt(ref expr) => {
                self.visit_expr(expr);

                ReturnState::new()
            }

            Break => ReturnState::breaks(),
            Continue => ReturnState::continues(),

            _ => ReturnState::new()
        }
    }

    fn visit_expr(&mut self, e: &Expr) -> ReturnState {
        match e.expr {
            Assign(ref var, ref expr) => {
                self.visit_expr(expr);

                match var.expr {
                    Ident(varind) => {
                        self.initialized_vars.insert(varind);
                    }

                    _ => unreachable!()
                }

                Default::default()
            }

            Ident(varind) => {
                if !self.initialized_vars.contains(&varind) {
                    let fct = self.fct.unwrap();
                    let var = &fct.vars[varind];

                    self.errors.push(ParseError {
                        position: e.position,
                        code: ErrorCode::UninitializedVar,
                        message: format!("variable `{}` might not be initialized", var.name)
                    });
                }

                Default::default()
            }

            _ => walk_expr(self, e)
        }
    }
}

#[cfg(test)]
mod tests {
    use ast::Function;

    use error::ErrorCode;
    use parser::Parser;

    fn parse(code: &'static str) -> Function {
        let mut prog = match Parser::from_str(code).parse() {
            Ok(prog) => prog,
            Err(err) => panic!("`{}` throws `{}` but no error expected", code, err),
        };

        prog.functions.swap_remove(0)
    }

    fn err(code: &'static str, error_code: ErrorCode, line: u32, col: u32) {
        let err = match Parser::from_str(code).parse() {
            Ok(_) => panic!("no error found in `{}`, expected {:?} at {}:{}",
                            code, error_code, line, col),
            Err(err) => err,
        };

        assert_eq!(error_code, err.code);
        assert_eq!(line, err.position.line);
        assert_eq!(col, err.position.column);
    }

    #[test]
    fn check_initialized() {
        parse("fn f(a: int) { a; }");
        parse("fn f { var a = 3; a; }");
        parse("fn f { var a : int; a = 3; a; }");

        err("fn f { var a : int; a; }", ErrorCode::UninitializedVar, 1, 21);
        err("fn f -> int { var a : int; return a; }", ErrorCode::UninitializedVar, 1, 35);

        parse("fn f { var a : int; if true { a = 1; } else { a = 2; } a; }");
        err("fn f { var a : int; if true {} else { a = 2; } a; }", ErrorCode::UninitializedVar, 1, 48);
        err("fn f { var a : int; if true { a = 1; } else {} a; }", ErrorCode::UninitializedVar, 1, 48);

        err("fn f { var a : bool; while a {} }", ErrorCode::UninitializedVar, 1, 28);
        err("fn f { var a : int; while true { a = 1; } a; }", ErrorCode::UninitializedVar, 1, 43);
    }

    #[test]
    fn check_return() {
        err("fn f -> int { 1; }", ErrorCode::NoReturnValue, 1, 15);
        err("fn f -> int {}", ErrorCode::NoReturnValue, 1, 13);
        err("fn f -> int { return 1; 1; }", ErrorCode::UnreachableCode, 1, 25);
        err("fn f { return; 1; }", ErrorCode::UnreachableCode, 1, 16);

        parse("fn f -> int { return 1; }");
        parse("fn f { return; }");
        parse("fn f { 1; }");
        parse("fn f {}");

        parse("fn f -> int { while true { return 1; } }");
        err("fn f -> int { while true { return 1; } return 1; }", ErrorCode::UnreachableCode, 1, 40);

        parse("fn f { while true { break; } return; }");
        parse("fn f { while true { continue; } return; }");

        parse("fn f->int {\
               if true { return 1; }\
               else { return 2; } }");
        err("fn f->int {\
             if true { return 1; } }", ErrorCode::NoReturnValue, 1, 12);
        err("fn f->int {\
             if true { return 1; } else { } }", ErrorCode::NoReturnValue, 1, 12);
        err("fn f->int {\
             if true { return 1; } else { return 2; }\
             return 3; }",
           ErrorCode::UnreachableCode, 1, 52);
    }

    #[test]
    fn check_break() {
        parse("fn x { while true { break; } return; }");
        parse("fn x { loop { break; } return; }");

        parse("fn x { loop { loop { break; } break; } }");
        parse("fn x { while true { while true { break; } break; } }");

        parse("fn x { loop { if true { break; } break; } }");
        parse("fn x { while true { if true { break; } break; } }");

        err("fn x { loop { if true { break; } else { break; } break; } }",
            ErrorCode::UnreachableCode, 1, 50);
        err("fn x { while true { if true { break; } else { break; } break; } }",
            ErrorCode::UnreachableCode, 1, 56);

        err("fn x { while true { break; return; } }", ErrorCode::UnreachableCode, 1, 28);
        err("fn x { loop { break; return; } }", ErrorCode::UnreachableCode, 1, 22);

        err("fn x { break; }", ErrorCode::MisplacedBreak, 1, 8);
        err("fn x { if true { break; } }", ErrorCode::MisplacedBreak, 1, 18);
        err("fn x { loop { if true { break; } else { return; } break; } }",
            ErrorCode::UnreachableCode, 1, 51);
    }

    #[test]
    fn check_continue() {
        parse("fn x { while true { continue; } return; }");
        err("fn x { loop { continue; } return; }",
           ErrorCode::UnreachableCode, 1, 27);

        parse("fn x { while true { while true { continue; } continue; } }");
        err("fn x { loop { loop { continue; } continue; } }",
           ErrorCode::UnreachableCode, 1, 34);

        parse("fn x { while true { if true { continue; } continue; } }");
        parse("fn x { loop { if true { continue; } continue; } }");

        err("fn x { loop { if true { continue; } else { continue; } continue; } }",
            ErrorCode::UnreachableCode, 1, 56);
        err("fn x { while true { if true { continue; } else { continue; } continue; } }",
            ErrorCode::UnreachableCode, 1, 62);

        err("fn x { while true { continue; return; } }", ErrorCode::UnreachableCode, 1, 31);
        err("fn x { loop { continue; return; } }", ErrorCode::UnreachableCode, 1, 25);

        err("fn x { continue; }", ErrorCode::MisplacedContinue, 1, 8);
        err("fn x { if true { continue; } }", ErrorCode::MisplacedContinue, 1, 18);
        err("fn x { loop { if true { continue; } else { return; } continue; } }",
            ErrorCode::UnreachableCode, 1, 54);
    }
}
<|endoftext|>


<commit_before>//! [Church booleans](https://en.wikipedia.org/wiki/Church_encoding#Church_Booleans)

use term::{Term, abs};
use term::Term::*;

/// A Church-encoded boolean `true`.
///
/// TRUE := λab.a = λ λ 2
pub fn tru() -> Term { abs!(2, Var(2)) }

/// A Church-encoded boolean `false`.
///
/// FALSE := λab.b = λ λ 1
pub fn fls() -> Term { abs!(2, Var(1)) }

/// Applied to two Church booleans it returns their Church-encoded conjunction.
///
/// AND := λpq.p q p = λ λ 2 1 2
///
/// # Examples
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::church::booleans::{and, tru, fls};
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(and(), tru(), tru()), NOR, 0, false), tru());
/// assert_eq!(beta(app!(and(), tru(), fls()), NOR, 0, false), fls());
/// assert_eq!(beta(app!(and(), fls(), tru()), NOR, 0, false), fls());
/// assert_eq!(beta(app!(and(), fls(), fls()), NOR, 0, false), fls());
/// # }
/// ```
pub fn and() -> Term {
    abs!(2, app!(Var(2), Var(1), Var(2)))
}

/// Applied to two Church booleans it returns their Church-encoded disjunction.
///
/// OR := λpq.p p q = λ λ 2 2 1
///
/// # Examples
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::church::booleans::{or, tru, fls};
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(or(), tru(), tru()), NOR, 0, false), tru());
/// assert_eq!(beta(app!(or(), tru(), fls()), NOR, 0, false), tru());
/// assert_eq!(beta(app!(or(), fls(), tru()), NOR, 0, false), tru());
/// assert_eq!(beta(app!(or(), fls(), fls()), NOR, 0, false), fls());
/// # }
/// ```
pub fn or() -> Term {
    abs!(2, app!(Var(2), Var(2), Var(1)))
}

/// Applied to a Church boolean it returns its Church-encoded negation.
///
/// NOT := λp.p FALSE TRUE = λ 1 FALSE TRUE
///
/// # Examples
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::church::booleans::{not, tru, fls};
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(not(), tru()), NOR, 0, false), fls());
/// assert_eq!(beta(app!(not(), fls()), NOR, 0, false), tru());
/// # }
/// ```
pub fn not() -> Term {
    abs(app!(Var(1), fls(), tru()))
}

/// Applied to two Church booleans it returns their Church-encoded exclusive disjunction.
///
/// XOR := λpq.p (NOT q) q = λ λ 2 (NOT 1) 1
///
/// # Examples
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::church::booleans::{xor, tru, fls};
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(xor(), tru(), tru()), NOR, 0, false), fls());
/// assert_eq!(beta(app!(xor(), tru(), fls()), NOR, 0, false), tru());
/// assert_eq!(beta(app!(xor(), fls(), tru()), NOR, 0, false), tru());
/// assert_eq!(beta(app!(xor(), fls(), fls()), NOR, 0, false), fls());
/// # }
/// ```
pub fn xor() -> Term {
    abs!(2,
        app!(
            Var(2),
            app!(
                Var(1),
                abs!(2, Var(1)),
                abs!(2, Var(2))
            ),
            Var(1)
        )
    )
}

/// Applied to two Church booleans it returns their Church-encoded joint denial.
///
/// NOR := λpq.NOT (OR p q) = λ λ NOT (OR 2 1)
///
/// # Examples
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::church::booleans::{nor, tru, fls};
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(nor(), tru(), tru()), NOR, 0, false), fls());
/// assert_eq!(beta(app!(nor(), tru(), fls()), NOR, 0, false), fls());
/// assert_eq!(beta(app!(nor(), fls(), tru()), NOR, 0, false), fls());
/// assert_eq!(beta(app!(nor(), fls(), fls()), NOR, 0, false), tru());
/// # }
/// ```
pub fn nor() -> Term {
    abs!(2,
        app!(
            Var(2),
            Var(2),
            Var(1),
            abs!(2, Var(1)),
            abs!(2, Var(2))
        )
    )
}

/// Applied to two Church booleans it returns their Church-encoded alternative denial.
///
/// NAND := λpq.NOT (AND p q) = λ λ NOT (AND 2 1)
///
/// # Examples
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::church::booleans::{nand, tru, fls};
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(nand(), tru(), tru()), NOR, 0, false), fls());
/// assert_eq!(beta(app!(nand(), tru(), fls()), NOR, 0, false), tru());
/// assert_eq!(beta(app!(nand(), fls(), tru()), NOR, 0, false), tru());
/// assert_eq!(beta(app!(nand(), fls(), fls()), NOR, 0, false), tru());
/// # }
/// ```
pub fn nand() -> Term {
    abs!(2,
        app!(
            Var(2),
            Var(1),
            Var(2),
            abs!(2, Var(1)),
            abs!(2, Var(2))
        )
    )
}

/// Applied to a Church-encoded predicate and two terms it returns the first one if the predicate
/// is true or the second one if the predicate is false.
///
/// IF_ELSE := λpab.p a b = λ λ λ 3 2 1
///
/// # Examples
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::church::booleans::{if_else, tru, fls};
/// use lambda_calculus::church::numerals::{zero, one};
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(if_else(), tru(), one(), zero()), NOR, 0, false),  one());
/// assert_eq!(beta(app!(if_else(), fls(), one(), zero()), NOR, 0, false), zero());
/// # }
/// ```
pub fn if_else() -> Term {
    abs!(3, app!(Var(3), Var(2), Var(1)))
}

impl From<bool> for Term {
    fn from(b: bool) -> Self {
        if b { tru() } else { fls() }
    }
}
<commit_msg>simplify some doctest imports in booleans.rs<commit_after>//! [Church booleans](https://en.wikipedia.org/wiki/Church_encoding#Church_Booleans)

use term::{Term, abs};
use term::Term::*;

/// A Church-encoded boolean `true`.
///
/// TRUE := λab.a = λ λ 2
pub fn tru() -> Term { abs!(2, Var(2)) }

/// A Church-encoded boolean `false`.
///
/// FALSE := λab.b = λ λ 1
pub fn fls() -> Term { abs!(2, Var(1)) }

/// Applied to two Church booleans it returns their Church-encoded conjunction.
///
/// AND := λpq.p q p = λ λ 2 1 2
///
/// # Examples
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::church::booleans::{and, tru, fls};
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app!(and(), tru(), tru()), NOR, 0, false), tru());
/// assert_eq!(beta(app!(and(), tru(), fls()), NOR, 0, false), fls());
/// assert_eq!(beta(app!(and(), fls(), tru()), NOR, 0, false), fls());
/// assert_eq!(beta(app!(and(), fls(), fls()), NOR, 0, false), fls());
/// # }
/// ```
pub fn and() -> Term {
    abs!(2, app!(Var(2), Var(1), Var(2)))
}

/// Applied to two Church booleans it returns their Church-encoded disjunction.
///
/// OR := λpq.p p q = λ λ 2 2 1
///
/// # Examples
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::church::booleans::{or, tru, fls};
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app!(or(), tru(), tru()), NOR, 0, false), tru());
/// assert_eq!(beta(app!(or(), tru(), fls()), NOR, 0, false), tru());
/// assert_eq!(beta(app!(or(), fls(), tru()), NOR, 0, false), tru());
/// assert_eq!(beta(app!(or(), fls(), fls()), NOR, 0, false), fls());
/// # }
/// ```
pub fn or() -> Term {
    abs!(2, app!(Var(2), Var(2), Var(1)))
}

/// Applied to a Church boolean it returns its Church-encoded negation.
///
/// NOT := λp.p FALSE TRUE = λ 1 FALSE TRUE
///
/// # Examples
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::church::booleans::{not, tru, fls};
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app!(not(), tru()), NOR, 0, false), fls());
/// assert_eq!(beta(app!(not(), fls()), NOR, 0, false), tru());
/// # }
/// ```
pub fn not() -> Term {
    abs(app!(Var(1), fls(), tru()))
}

/// Applied to two Church booleans it returns their Church-encoded exclusive disjunction.
///
/// XOR := λpq.p (NOT q) q = λ λ 2 (NOT 1) 1
///
/// # Examples
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::church::booleans::{xor, tru, fls};
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app!(xor(), tru(), tru()), NOR, 0, false), fls());
/// assert_eq!(beta(app!(xor(), tru(), fls()), NOR, 0, false), tru());
/// assert_eq!(beta(app!(xor(), fls(), tru()), NOR, 0, false), tru());
/// assert_eq!(beta(app!(xor(), fls(), fls()), NOR, 0, false), fls());
/// # }
/// ```
pub fn xor() -> Term {
    abs!(2,
        app!(
            Var(2),
            app!(
                Var(1),
                abs!(2, Var(1)),
                abs!(2, Var(2))
            ),
            Var(1)
        )
    )
}

/// Applied to two Church booleans it returns their Church-encoded joint denial.
///
/// NOR := λpq.NOT (OR p q) = λ λ NOT (OR 2 1)
///
/// # Examples
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::church::booleans::{nor, tru, fls};
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app!(nor(), tru(), tru()), NOR, 0, false), fls());
/// assert_eq!(beta(app!(nor(), tru(), fls()), NOR, 0, false), fls());
/// assert_eq!(beta(app!(nor(), fls(), tru()), NOR, 0, false), fls());
/// assert_eq!(beta(app!(nor(), fls(), fls()), NOR, 0, false), tru());
/// # }
/// ```
pub fn nor() -> Term {
    abs!(2,
        app!(
            Var(2),
            Var(2),
            Var(1),
            abs!(2, Var(1)),
            abs!(2, Var(2))
        )
    )
}

/// Applied to two Church booleans it returns their Church-encoded alternative denial.
///
/// NAND := λpq.NOT (AND p q) = λ λ NOT (AND 2 1)
///
/// # Examples
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::church::booleans::{nand, tru, fls};
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app!(nand(), tru(), tru()), NOR, 0, false), fls());
/// assert_eq!(beta(app!(nand(), tru(), fls()), NOR, 0, false), tru());
/// assert_eq!(beta(app!(nand(), fls(), tru()), NOR, 0, false), tru());
/// assert_eq!(beta(app!(nand(), fls(), fls()), NOR, 0, false), tru());
/// # }
/// ```
pub fn nand() -> Term {
    abs!(2,
        app!(
            Var(2),
            Var(1),
            Var(2),
            abs!(2, Var(1)),
            abs!(2, Var(2))
        )
    )
}

/// Applied to a Church-encoded predicate and two terms it returns the first one if the predicate
/// is true or the second one if the predicate is false.
///
/// IF_ELSE := λpab.p a b = λ λ λ 3 2 1
///
/// # Examples
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::church::booleans::{if_else, tru, fls};
/// use lambda_calculus::church::numerals::{zero, one};
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app!(if_else(), tru(), one(), zero()), NOR, 0, false),  one());
/// assert_eq!(beta(app!(if_else(), fls(), one(), zero()), NOR, 0, false), zero());
/// # }
/// ```
pub fn if_else() -> Term {
    abs!(3, app!(Var(3), Var(2), Var(1)))
}

impl From<bool> for Term {
    fn from(b: bool) -> Self {
        if b { tru() } else { fls() }
    }
}
<|endoftext|>


<commit_before>use pe::error::*;
use scroll;

#[repr(C)]
#[derive(Debug, PartialEq, Copy, Clone, Default)]
pub struct SectionTable {
    pub name: [u8; 8],
    pub virtual_size: u32,
    pub virtual_address: u32,
    pub size_of_raw_data: u32,
    pub pointer_to_raw_data: u32,
    pub pointer_to_relocations: u32,
    pub pointer_to_linenumbers: u32,
    pub number_of_relocations: u16,
    pub number_of_linenumbers: u16,
    pub characteristics: u32,
}

pub const SIZEOF_SECTION_TABLE: usize = 8 * 5;

impl SectionTable {
    pub fn parse<B: scroll::Gread> (bytes: &B, offset: &mut usize) -> Result<Self> {
        let mut table = SectionTable::default();
        let mut name = [0u8; 8];
        for i in 0..8 {
            name[i] = bytes.gread(offset, scroll::LE)?;
        }
        table.name = name;
        table.virtual_size = bytes.gread(offset, scroll::LE)?;
        table.virtual_address = bytes.gread(offset, scroll::LE)?;
        table.size_of_raw_data = bytes.gread(offset, scroll::LE)?;
        table.pointer_to_raw_data = bytes.gread(offset, scroll::LE)?;
        table.pointer_to_relocations = bytes.gread(offset, scroll::LE)?;
        table.pointer_to_linenumbers = bytes.gread(offset, scroll::LE)?;
        table.number_of_relocations = bytes.gread(offset, scroll::LE)?;
        table.number_of_linenumbers = bytes.gread(offset, scroll::LE)?;
        table.characteristics = bytes.gread(offset, scroll::LE)?;
        Ok(table)
    }
}

/*
let get binary (header:PEHeader.t) =
  let offset =
    header.dos_header.pe_pointer + PEHeader.sizeof_coff_header
    + header.coff_header.size_of_optional_header
  in
  let nsections = header.coff_header.number_of_sections in
  let rec loop acc count =
    if (count >= nsections) then
      List.rev acc
    else
      let o = offset + (count * sizeof_section_table) in
      let st = get_section_table binary o in
      loop (st::acc) (count+1)
  in loop [] 0
*/
<commit_msg>pe.section_table: remove commented code<commit_after>use pe::error::*;
use scroll;

#[repr(C)]
#[derive(Debug, PartialEq, Copy, Clone, Default)]
pub struct SectionTable {
    pub name: [u8; 8],
    pub virtual_size: u32,
    pub virtual_address: u32,
    pub size_of_raw_data: u32,
    pub pointer_to_raw_data: u32,
    pub pointer_to_relocations: u32,
    pub pointer_to_linenumbers: u32,
    pub number_of_relocations: u16,
    pub number_of_linenumbers: u16,
    pub characteristics: u32,
}

pub const SIZEOF_SECTION_TABLE: usize = 8 * 5;

impl SectionTable {
    pub fn parse<B: scroll::Gread> (bytes: &B, offset: &mut usize) -> Result<Self> {
        let mut table = SectionTable::default();
        let mut name = [0u8; 8];
        for i in 0..8 {
            name[i] = bytes.gread(offset, scroll::LE)?;
        }
        table.name = name;
        table.virtual_size = bytes.gread(offset, scroll::LE)?;
        table.virtual_address = bytes.gread(offset, scroll::LE)?;
        table.size_of_raw_data = bytes.gread(offset, scroll::LE)?;
        table.pointer_to_raw_data = bytes.gread(offset, scroll::LE)?;
        table.pointer_to_relocations = bytes.gread(offset, scroll::LE)?;
        table.pointer_to_linenumbers = bytes.gread(offset, scroll::LE)?;
        table.number_of_relocations = bytes.gread(offset, scroll::LE)?;
        table.number_of_linenumbers = bytes.gread(offset, scroll::LE)?;
        table.characteristics = bytes.gread(offset, scroll::LE)?;
        Ok(table)
    }
}
<|endoftext|>


<commit_before>//! Container types

use rustwlc::handle::{WlcView, WlcOutput};
use rustwlc::{Geometry, Point, Size, ResizeEdge};

/// A handle to either a view or output
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Handle {
    View(WlcView),
    Output(WlcOutput)
}

/// Types of containers
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ContainerType {
    /// Root container, only one exists
    Root,
    /// WlcOutput/Monitor
    Output,
    /// A workspace
    Workspace,
    /// A Container, houses views and other containers
    Container,
    /// A view (window)
    View
}

impl ContainerType {
    /// Whether this container can be used as the parent of another
    pub fn can_have_child(self, other: ContainerType) -> bool {
        use self::ContainerType::*;
        match self {
            Root => other == Output,
            Output => other == Workspace,
            Workspace => other == Container,
            Container => other == Container || other == View,
            View => false
        }
    }

    /// Whether this container can have a parent of type other
    #[allow(dead_code)]
    pub fn can_have_parent(self, other: ContainerType) -> bool {
        other.can_have_child(self)
    }
}

/// Layout mode for a container
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(dead_code)]
pub enum Layout {
    Horizontal,
    Vertical,
    Stacked,
    Tabbed,
    Floating
}

/// Represents an item in the container tree.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Container {
    /// Root node of the container
    Root,
    /// Output
    Output {
        /// Handle to the wlc
        handle: WlcOutput,
        /// Whether the output is focused
        focused: bool
    },
    /// Workspace
    Workspace {
        /// Name of the workspace
        name: String,
        /// Whether the workspace is focused
        ///
        /// Multiple workspaces can be focused
        focused: bool,
        /// The size of the workspace on the screen.
        /// Might be different if there is e.g a bar present
        size: Size,
    },
    /// Container
    Container {
        /// How the container is layed out
        layout: Layout,
        /// Whether the container is visible
        visible: bool,
        /// If the container is focused
        focused: bool,
        /// If the container is floating
        floating: bool,
        /// The geometry of the container, relative to the parent container
        geometry: Geometry,
    },
    /// View or window
    View {
        /// The wlc handle to the view
        handle: WlcView,
        /// Whether this view is visible
        visible: bool,
        /// Whether this view is focused
        focused: bool,
        /// Whether this view is floating
        floating: bool,
    }
}

impl Container {
    /// Creates a new output container with the given output
    pub fn new_output(handle: WlcOutput) -> Container {
        Container::Output {
            handle: handle,
            focused: false
        }
    }

    /// Creates a new workspace container with the given name and size.
    /// Usually the size is the same as the output it resides on,
    /// unless there is a bar or something.
    pub fn new_workspace(name: String, size: Size) -> Container {
        Container::Workspace {
            name: name, focused: false, size: size
        }
    }

    /// Creates a new container
    pub fn new_container(geometry: Geometry) -> Container {
        Container::Container {
            layout: Layout::Horizontal,
            visible: false,
            focused: false,
            floating: false,
            geometry: geometry
        }
    }

    /// Creates a new view container with the given handle
    pub fn new_view(handle: WlcView) -> Container {
        Container::View {
            handle: handle,
            visible: false,
            focused: false,
            floating: false
        }
    }

    /// Sets the visibility of this container
    pub fn set_visibility(&mut self, visibility: bool) {
        match *self {
            Container::View { ref mut visible, .. } => *visible = visibility,
            Container::Container { ref mut visible, .. } => *visible = visibility,
            _ => {return},
        }
        let mask = if visibility { 1 } else { 0 };
        if let Some(handle) = self.get_handle() {
            match handle {
                Handle::View(view) => {
                    view.set_mask(mask)
                },
                _ => {},
            }
        }
    }

    /// Gets the visibility flag of this container
    #[allow(dead_code)]
    pub fn get_visibility(&mut self) -> Option<bool> {
        match *self {
            Container::View { visible, .. } => Some(visible),
            Container::Container { visible, .. } => Some(visible),
            _ => None
        }
    }

    /// Gets the type of this container
    pub fn get_type(&self) -> ContainerType {
        match *self {
            Container::Root => ContainerType::Root,
            Container::Output { .. } => ContainerType::Output,
            Container::Workspace { .. } => ContainerType::Workspace,
            Container::Container { .. } => ContainerType::Container,
            Container::View { .. } => ContainerType::View
        }
    }

    /// Gets the view handle of the view container, if this is a view container
    pub fn get_handle(&self) -> Option<Handle> {
        match *self {
            Container::View { ref handle, ..} => Some(Handle::View(handle.clone())),
            Container::Output { ref handle, .. } => Some(Handle::Output(handle.clone())),
            _ => None
        }
    }

    /// Gets the name of the workspace, if this container is a workspace.
    pub fn get_name(&self) -> Option<&str> {
        match *self {
            Container::Workspace { ref name, ..} => Some(name),
            _ => None
        }
    }

    /// Determines if the container is focused or not
    #[allow(dead_code)]
    pub fn is_focused(&self) -> bool {
        match *self {
            Container::Output { ref focused, .. } => focused.clone(),
            Container::Workspace { ref focused, .. } => focused.clone(),
            Container::View { ref focused, .. } => focused.clone(),
            _ => false
        }
    }

    /// Gets the geometry of the container, if the container has one.
    /// Root: Returns None
    /// Workspace/Output: Size is the size of the screen, origin is just 0,0
    /// Container/View: Size is the size of the container,
    /// origin is the coordinates relative to the parent container.
    pub fn get_geometry(&self) -> Option<Geometry> {
        match *self {
            Container::Root { .. } => None,
            Container::Output { ref handle, .. } => Some(Geometry {
                origin: Point { x: 0, y: 0 },
                size: handle.get_resolution().clone(),
            }),
            Container::Workspace { ref size, .. } => Some(Geometry {
                origin: Point { x: 0, y: 0},
                size: size.clone()
            }),
            Container::Container { ref geometry, .. } => Some(geometry.clone()),
            Container::View { ref handle, ..} => {
                match handle.get_geometry() {
                    Some(geometry) => Some(geometry.clone()),
                    _ => None
                }
            },
        }
    }

    /// Sets the geometry of the container, if it supports that operation.
    /// Only Views, Containers, and Workspaces support this operation,
    /// all others will return an Err with an appropriate error message.
    ///
    /// If setting a workspace, only the size of the geometry is set.
    #[allow(dead_code)]
    pub fn set_geometry(&mut self, new_geometry: Geometry) -> Result<(), String> {
        match *self {
            Container::Workspace { ref mut size, .. } => *size = new_geometry.size,
            Container::Container { ref mut geometry, .. } => *geometry = new_geometry,
            Container::View { ref handle, .. } =>
                handle.set_geometry(ResizeEdge::empty(), &new_geometry),
            _ => { return Err(format!("Could not set geometry on {:?}", self))}
        };
        return Ok(())
    }

    pub fn set_layout(&mut self, new_layout: Layout) -> Result<(), String>{
        match *self {
            Container::Container { ref mut layout, .. } => *layout = new_layout,
            ref other => return Err(
                format!("Can only set the layout of a container, not {:?}",
                        other))
        }
        Ok(())
    }
}

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

    #[test]
    fn can_have_child() {
        let root = ContainerType::Root;
        let output = ContainerType::Output;
        let workspace = ContainerType::Workspace;
        let container = ContainerType::Container;
        let view = ContainerType::View;

        assert!(root.can_have_child(output),         "Root      > output");
        assert!(output.can_have_child(workspace),    "Output    > workspace");
        assert!(workspace.can_have_child(container), "Workspace > container");
        assert!(container.can_have_child(container), "Container > container");
        assert!(container.can_have_child(view),      "Container > view");

        assert!(!root.can_have_child(root),      "! Root > root");
        assert!(!root.can_have_child(workspace), "! Root > workspace");
        assert!(!root.can_have_child(container), "! Root > container");
        assert!(!root.can_have_child(view),      "! Root > view");

        assert!(!output.can_have_child(root),      "! Output > root");
        assert!(!output.can_have_child(output),    "! Output > output");
        assert!(!output.can_have_child(container), "! Output > container");
        assert!(!output.can_have_child(view),      "! Output > view");

        assert!(!workspace.can_have_child(root),      "! Workspace > root");
        assert!(!workspace.can_have_child(output),    "! Workspace > output");
        assert!(!workspace.can_have_child(workspace), "! Workspace > worksp");
        assert!(!workspace.can_have_child(view),      "! Workspace > view");

        assert!(!container.can_have_child(root),      "! Container > root");
        assert!(!container.can_have_child(workspace), "! Container > worksp");
        assert!(!container.can_have_child(output),    "! Container > contanr");

        assert!(!view.can_have_child(root),      "! View > root");
        assert!(!view.can_have_child(output),    "! View > output");
        assert!(!view.can_have_child(workspace), "! View > workspace");
        assert!(!view.can_have_child(container), "! View > container");
        assert!(!view.can_have_child(view),      "! View > view");
    }

    #[test]
    /// Tests set and get geometry
    fn geometry_test() {
        use rustwlc::*;
        let test_geometry1 = Geometry {
            origin: Point { x: 800, y: 600 },
            size: Size { w: 500, h: 500}
        };
        let test_geometry2 = Geometry {
            origin: Point { x: 1024, y: 2048},
            size: Size { w: 500, h: 700}
        };
        let mut root = Container::Root;
        assert!(root.get_geometry().is_none());
        assert!(root.set_geometry(test_geometry1.clone()).is_err());

        let mut output = Container::new_output(WlcView::root().as_output());
        // NOTE Segfaults, because tries to get the geometry from dummy Wlc output
        //assert!(output.get_geometry().is_none());
        assert!(output.set_geometry(test_geometry1.clone()).is_err());

        let mut workspace = Container::new_workspace("1".to_string(),
                                                     Size { w: 500, h: 500 });
        assert_eq!(workspace.get_geometry(), Some(Geometry {
            size: Size { w: 500, h: 500},
            origin: Point { x: 0, y: 0}
        }));
        workspace.set_geometry(test_geometry1.clone())
            .expect("Can't set geometry on workspace");
        // Workspace only grabs the Size, so point will be 0 0.
        let workspace_geometry = Geometry {
            size: test_geometry1.size.clone(),
            origin: Point { x: 0, y: 0}
        };
        assert_eq!(workspace.get_geometry(), Some(workspace_geometry.clone()));

        let mut container = Container::new_container(test_geometry1.clone());
        assert_eq!(container.get_geometry(), Some(test_geometry1.clone()));
        container.set_geometry(test_geometry2.clone())
            .expect("Could not set geometry on container");
        assert_eq!(container.get_geometry(), Some(test_geometry2.clone()));

        // NOTE Can't test view, because that will just segfault as well
        //let mut view = Container::new_view(WlcView::root());
    }
}
<commit_msg>Removed useless visiblity flag<commit_after>//! Container types

use rustwlc::handle::{WlcView, WlcOutput};
use rustwlc::{Geometry, Point, Size, ResizeEdge};

/// A handle to either a view or output
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Handle {
    View(WlcView),
    Output(WlcOutput)
}

/// Types of containers
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ContainerType {
    /// Root container, only one exists
    Root,
    /// WlcOutput/Monitor
    Output,
    /// A workspace
    Workspace,
    /// A Container, houses views and other containers
    Container,
    /// A view (window)
    View
}

impl ContainerType {
    /// Whether this container can be used as the parent of another
    pub fn can_have_child(self, other: ContainerType) -> bool {
        use self::ContainerType::*;
        match self {
            Root => other == Output,
            Output => other == Workspace,
            Workspace => other == Container,
            Container => other == Container || other == View,
            View => false
        }
    }

    /// Whether this container can have a parent of type other
    #[allow(dead_code)]
    pub fn can_have_parent(self, other: ContainerType) -> bool {
        other.can_have_child(self)
    }
}

/// Layout mode for a container
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(dead_code)]
pub enum Layout {
    Horizontal,
    Vertical,
    Stacked,
    Tabbed,
    Floating
}

/// Represents an item in the container tree.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Container {
    /// Root node of the container
    Root,
    /// Output
    Output {
        /// Handle to the wlc
        handle: WlcOutput,
        /// Whether the output is focused
        focused: bool
    },
    /// Workspace
    Workspace {
        /// Name of the workspace
        name: String,
        /// Whether the workspace is focused
        ///
        /// Multiple workspaces can be focused
        focused: bool,
        /// The size of the workspace on the screen.
        /// Might be different if there is e.g a bar present
        size: Size,
    },
    /// Container
    Container {
        /// How the container is layed out
        layout: Layout,
        /// If the container is focused
        focused: bool,
        /// If the container is floating
        floating: bool,
        /// The geometry of the container, relative to the parent container
        geometry: Geometry,
    },
    /// View or window
    View {
        /// The wlc handle to the view
        handle: WlcView,
        /// Whether this view is focused
        focused: bool,
        /// Whether this view is floating
        floating: bool,
    }
}

impl Container {
    /// Creates a new output container with the given output
    pub fn new_output(handle: WlcOutput) -> Container {
        Container::Output {
            handle: handle,
            focused: false
        }
    }

    /// Creates a new workspace container with the given name and size.
    /// Usually the size is the same as the output it resides on,
    /// unless there is a bar or something.
    pub fn new_workspace(name: String, size: Size) -> Container {
        Container::Workspace {
            name: name, focused: false, size: size
        }
    }

    /// Creates a new container
    pub fn new_container(geometry: Geometry) -> Container {
        Container::Container {
            layout: Layout::Horizontal,
            focused: false,
            floating: false,
            geometry: geometry
        }
    }

    /// Creates a new view container with the given handle
    pub fn new_view(handle: WlcView) -> Container {
        Container::View {
            handle: handle,
            focused: false,
            floating: false
        }
    }

    /// Sets the visibility of this container
    pub fn set_visibility(&mut self, visibility: bool) {
        let mask = if visibility { 1 } else { 0 };
        if let Some(handle) = self.get_handle() {
            match handle {
                Handle::View(view) => {
                    view.set_mask(mask)
                },
                _ => {},
            }
        }
    }

    /// Gets the type of this container
    pub fn get_type(&self) -> ContainerType {
        match *self {
            Container::Root => ContainerType::Root,
            Container::Output { .. } => ContainerType::Output,
            Container::Workspace { .. } => ContainerType::Workspace,
            Container::Container { .. } => ContainerType::Container,
            Container::View { .. } => ContainerType::View
        }
    }

    /// Gets the view handle of the view container, if this is a view container
    pub fn get_handle(&self) -> Option<Handle> {
        match *self {
            Container::View { ref handle, ..} => Some(Handle::View(handle.clone())),
            Container::Output { ref handle, .. } => Some(Handle::Output(handle.clone())),
            _ => None
        }
    }

    /// Gets the name of the workspace, if this container is a workspace.
    pub fn get_name(&self) -> Option<&str> {
        match *self {
            Container::Workspace { ref name, ..} => Some(name),
            _ => None
        }
    }

    /// Determines if the container is focused or not
    #[allow(dead_code)]
    pub fn is_focused(&self) -> bool {
        match *self {
            Container::Output { ref focused, .. } => focused.clone(),
            Container::Workspace { ref focused, .. } => focused.clone(),
            Container::View { ref focused, .. } => focused.clone(),
            _ => false
        }
    }

    /// Gets the geometry of the container, if the container has one.
    /// Root: Returns None
    /// Workspace/Output: Size is the size of the screen, origin is just 0,0
    /// Container/View: Size is the size of the container,
    /// origin is the coordinates relative to the parent container.
    pub fn get_geometry(&self) -> Option<Geometry> {
        match *self {
            Container::Root { .. } => None,
            Container::Output { ref handle, .. } => Some(Geometry {
                origin: Point { x: 0, y: 0 },
                size: handle.get_resolution().clone(),
            }),
            Container::Workspace { ref size, .. } => Some(Geometry {
                origin: Point { x: 0, y: 0},
                size: size.clone()
            }),
            Container::Container { ref geometry, .. } => Some(geometry.clone()),
            Container::View { ref handle, ..} => {
                match handle.get_geometry() {
                    Some(geometry) => Some(geometry.clone()),
                    _ => None
                }
            },
        }
    }

    /// Sets the geometry of the container, if it supports that operation.
    /// Only Views, Containers, and Workspaces support this operation,
    /// all others will return an Err with an appropriate error message.
    ///
    /// If setting a workspace, only the size of the geometry is set.
    #[allow(dead_code)]
    pub fn set_geometry(&mut self, new_geometry: Geometry) -> Result<(), String> {
        match *self {
            Container::Workspace { ref mut size, .. } => *size = new_geometry.size,
            Container::Container { ref mut geometry, .. } => *geometry = new_geometry,
            Container::View { ref handle, .. } =>
                handle.set_geometry(ResizeEdge::empty(), &new_geometry),
            _ => { return Err(format!("Could not set geometry on {:?}", self))}
        };
        return Ok(())
    }

    pub fn set_layout(&mut self, new_layout: Layout) -> Result<(), String>{
        match *self {
            Container::Container { ref mut layout, .. } => *layout = new_layout,
            ref other => return Err(
                format!("Can only set the layout of a container, not {:?}",
                        other))
        }
        Ok(())
    }
}

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

    #[test]
    fn can_have_child() {
        let root = ContainerType::Root;
        let output = ContainerType::Output;
        let workspace = ContainerType::Workspace;
        let container = ContainerType::Container;
        let view = ContainerType::View;

        assert!(root.can_have_child(output),         "Root      > output");
        assert!(output.can_have_child(workspace),    "Output    > workspace");
        assert!(workspace.can_have_child(container), "Workspace > container");
        assert!(container.can_have_child(container), "Container > container");
        assert!(container.can_have_child(view),      "Container > view");

        assert!(!root.can_have_child(root),      "! Root > root");
        assert!(!root.can_have_child(workspace), "! Root > workspace");
        assert!(!root.can_have_child(container), "! Root > container");
        assert!(!root.can_have_child(view),      "! Root > view");

        assert!(!output.can_have_child(root),      "! Output > root");
        assert!(!output.can_have_child(output),    "! Output > output");
        assert!(!output.can_have_child(container), "! Output > container");
        assert!(!output.can_have_child(view),      "! Output > view");

        assert!(!workspace.can_have_child(root),      "! Workspace > root");
        assert!(!workspace.can_have_child(output),    "! Workspace > output");
        assert!(!workspace.can_have_child(workspace), "! Workspace > worksp");
        assert!(!workspace.can_have_child(view),      "! Workspace > view");

        assert!(!container.can_have_child(root),      "! Container > root");
        assert!(!container.can_have_child(workspace), "! Container > worksp");
        assert!(!container.can_have_child(output),    "! Container > contanr");

        assert!(!view.can_have_child(root),      "! View > root");
        assert!(!view.can_have_child(output),    "! View > output");
        assert!(!view.can_have_child(workspace), "! View > workspace");
        assert!(!view.can_have_child(container), "! View > container");
        assert!(!view.can_have_child(view),      "! View > view");
    }

    #[test]
    /// Tests set and get geometry
    fn geometry_test() {
        use rustwlc::*;
        let test_geometry1 = Geometry {
            origin: Point { x: 800, y: 600 },
            size: Size { w: 500, h: 500}
        };
        let test_geometry2 = Geometry {
            origin: Point { x: 1024, y: 2048},
            size: Size { w: 500, h: 700}
        };
        let mut root = Container::Root;
        assert!(root.get_geometry().is_none());
        assert!(root.set_geometry(test_geometry1.clone()).is_err());

        let mut output = Container::new_output(WlcView::root().as_output());
        // NOTE Segfaults, because tries to get the geometry from dummy Wlc output
        //assert!(output.get_geometry().is_none());
        assert!(output.set_geometry(test_geometry1.clone()).is_err());

        let mut workspace = Container::new_workspace("1".to_string(),
                                                     Size { w: 500, h: 500 });
        assert_eq!(workspace.get_geometry(), Some(Geometry {
            size: Size { w: 500, h: 500},
            origin: Point { x: 0, y: 0}
        }));
        workspace.set_geometry(test_geometry1.clone())
            .expect("Can't set geometry on workspace");
        // Workspace only grabs the Size, so point will be 0 0.
        let workspace_geometry = Geometry {
            size: test_geometry1.size.clone(),
            origin: Point { x: 0, y: 0}
        };
        assert_eq!(workspace.get_geometry(), Some(workspace_geometry.clone()));

        let mut container = Container::new_container(test_geometry1.clone());
        assert_eq!(container.get_geometry(), Some(test_geometry1.clone()));
        container.set_geometry(test_geometry2.clone())
            .expect("Could not set geometry on container");
        assert_eq!(container.get_geometry(), Some(test_geometry2.clone()));

        // NOTE Can't test view, because that will just segfault as well
        //let mut view = Container::new_view(WlcView::root());
    }
}
<|endoftext|>


<commit_before>#[no_mangle]
pub unsafe extern "C" fn memset(ptr: *mut u8, val: i32, num: usize) -> *mut u8 {
    let mut i = 0;

    while i < num {
        *ptr.offset(i as isize) = val as u8;

        i += 1;
    }

    ptr
}
<commit_msg>libbot: Add memmove and memcpy<commit_after>#[no_mangle]
pub unsafe extern "C" fn memset(ptr: *mut u8, val: i32, num: usize) -> *mut u8 {
    let mut i = 0;

    while i < num {
        *ptr.offset(i as isize) = val as u8;

        i += 1;
    }

    ptr
}

#[no_mangle]
pub unsafe extern fn memcpy(dest: *mut u8, src: *const u8,
                            n: usize) -> *mut u8 {
    let mut i = 0;

    while i < n {
        *dest.offset(i as isize) = *src.offset(i as isize);
        i += 1;
    }

    dest
}

#[no_mangle]
pub unsafe extern fn memmove(dest: *mut u8, src: *const u8,
                             n: usize) -> *mut u8 {
    if dest as *const u8 <= src {
        return memcpy(dest, src, n);
    }

    let mut i = n;
    while i != 0 {
        i -= 1;
        *dest.offset(i as isize) = *src.offset(i as isize);
    }

    dest
}
<|endoftext|>


<commit_before>// Copyright 2013-2015, The Rust-GNOME Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! Animations — Animated images.

use std::mem;
use std::ptr;
use glib::{Error, GlibContainer, TimeVal};
use glib::translate::*;
use glib::types::{StaticType, Type};
use object::{Object, Upcast};
use ffi;
use super::Pixbuf;

pub type PixbufAnimationIter = Object<ffi::C_GdkPixbufAnimationIter>;

impl StaticType for PixbufAnimationIter {
    fn static_type() -> Type { unsafe { from_glib(ffi::gdk_pixbuf_animation_iter_get_type()) } }
}

impl PixbufAnimationIter {
    pub fn advance(&self, start_time: &TimeVal) -> bool {
        unsafe {
            from_glib(ffi::gdk_pixbuf_animation_iter_advance(self.to_glib_none().0,
                mem::transmute(start_time)))
        }
    }

    pub fn get_pixbuf(&self) -> Pixbuf {
        unsafe { from_glib_none(ffi::gdk_pixbuf_animation_iter_get_pixbuf(self.to_glib_none().0)) }
    }

    pub fn get_delay_time(&self) -> i32 {
        unsafe { ffi::gdk_pixbuf_animation_iter_get_delay_time(self.to_glib_none().0) }
    }

    pub fn on_currently_loading_frame(&self) -> bool {
        unsafe {
            from_glib(
                ffi::gdk_pixbuf_animation_iter_on_currently_loading_frame(self.to_glib_none().0))
        }
    }
}

pub type PixbufAnimation = Object<ffi::C_GdkPixbufAnimation>;

impl StaticType for PixbufAnimation {
    fn static_type() -> Type { unsafe { from_glib(ffi::gdk_pixbuf_animation_get_type()) } }
}

impl PixbufAnimation {
    pub fn new_from_file(file: &str) -> Result<PixbufAnimation, Error> {
        unsafe {
            let mut error = ptr::null_mut();
            let ptr = ffi::gdk_pixbuf_animation_new_from_file(file.to_glib_none().0, &mut error);
            if error.is_null() {
                Ok(from_glib_full(ptr))
            } else {
                Err(Error::wrap(error))
            }
        }
    }

    pub fn new_from_resource(resource_path: &str) -> Result<PixbufAnimation, Error> {
        unsafe {
            let mut error = ptr::null_mut();
            let ptr = ffi::gdk_pixbuf_animation_new_from_resource(resource_path.to_glib_none().0,
                                                                  &mut error);
            if error.is_null() {
                Ok(from_glib_full(ptr))
            } else {
                Err(Error::wrap(error))
            }
        }
    }
}

pub trait PixbufAnimationExt {
    fn get_width(&self) -> i32;
    fn get_height(&self) -> i32;
    fn get_iter(&self, start_time: &TimeVal) -> PixbufAnimationIter;
    fn is_static_image(&self) -> bool;
    fn get_static_image(&self) -> Option<Pixbuf>;
}

impl<T: Upcast<PixbufAnimation>> PixbufAnimationExt for T {
    fn get_width(&self) -> i32 {
        unsafe { ffi::gdk_pixbuf_animation_get_width(self.upcast().to_glib_none().0) }
    }

    fn get_height(&self) -> i32 {
        unsafe { ffi::gdk_pixbuf_animation_get_height(self.upcast().to_glib_none().0) }
    }

    fn get_iter(&self, start_time: &TimeVal) -> PixbufAnimationIter {
        unsafe {
            from_glib_full(
                ffi::gdk_pixbuf_animation_get_iter(self.upcast().to_glib_none().0,
                                                   mem::transmute(start_time)))
        }
    }

    fn is_static_image(&self) -> bool {
        unsafe {
            from_glib(ffi::gdk_pixbuf_animation_is_static_image(self.upcast().to_glib_none().0))
        }
    }

    fn get_static_image(&self) -> Option<Pixbuf> {
        unsafe {
            from_glib_none(ffi::gdk_pixbuf_animation_get_static_image(
                self.upcast().to_glib_none().0))
        }
    }
}

pub type PixbufSimpleAnim = Object<ffi::C_GdkPixbufSimpleAnim>;

impl StaticType for PixbufSimpleAnim {
    fn static_type() -> Type { unsafe { from_glib(ffi::gdk_pixbuf_simple_anim_get_type()) } }
}

unsafe impl Upcast<PixbufAnimation> for PixbufSimpleAnim { }

impl PixbufSimpleAnim {
    pub fn new(width: i32, height: i32, rate: f32) -> PixbufSimpleAnim {
        unsafe { from_glib_full(ffi::gdk_pixbuf_simple_anim_new(width, height, rate)) }
    }

    pub fn add_frame(&self, pixbuf: &Pixbuf) {
        unsafe {
            ffi::gdk_pixbuf_simple_anim_add_frame(self.to_glib_none().0, pixbuf.to_glib_none().0)
        }
    }

    pub fn set_loop(&self, loop_: bool) {
        unsafe { ffi::gdk_pixbuf_simple_anim_set_loop(self.to_glib_none().0, loop_.to_glib()) }
    }

    pub fn get_loop(&self) -> bool {
        unsafe { from_glib(ffi::gdk_pixbuf_simple_anim_get_loop(self.to_glib_none().0)) }
    }
}
<commit_msg>Gate PixbufAnimation::new_from_resource on GDK 3.8<commit_after>// Copyright 2013-2015, The Rust-GNOME Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! Animations — Animated images.

use std::mem;
use std::ptr;
use glib::{Error, GlibContainer, TimeVal};
use glib::translate::*;
use glib::types::{StaticType, Type};
use object::{Object, Upcast};
use ffi;
use super::Pixbuf;

pub type PixbufAnimationIter = Object<ffi::C_GdkPixbufAnimationIter>;

impl StaticType for PixbufAnimationIter {
    fn static_type() -> Type { unsafe { from_glib(ffi::gdk_pixbuf_animation_iter_get_type()) } }
}

impl PixbufAnimationIter {
    pub fn advance(&self, start_time: &TimeVal) -> bool {
        unsafe {
            from_glib(ffi::gdk_pixbuf_animation_iter_advance(self.to_glib_none().0,
                mem::transmute(start_time)))
        }
    }

    pub fn get_pixbuf(&self) -> Pixbuf {
        unsafe { from_glib_none(ffi::gdk_pixbuf_animation_iter_get_pixbuf(self.to_glib_none().0)) }
    }

    pub fn get_delay_time(&self) -> i32 {
        unsafe { ffi::gdk_pixbuf_animation_iter_get_delay_time(self.to_glib_none().0) }
    }

    pub fn on_currently_loading_frame(&self) -> bool {
        unsafe {
            from_glib(
                ffi::gdk_pixbuf_animation_iter_on_currently_loading_frame(self.to_glib_none().0))
        }
    }
}

pub type PixbufAnimation = Object<ffi::C_GdkPixbufAnimation>;

impl StaticType for PixbufAnimation {
    fn static_type() -> Type { unsafe { from_glib(ffi::gdk_pixbuf_animation_get_type()) } }
}

impl PixbufAnimation {
    pub fn new_from_file(file: &str) -> Result<PixbufAnimation, Error> {
        unsafe {
            let mut error = ptr::null_mut();
            let ptr = ffi::gdk_pixbuf_animation_new_from_file(file.to_glib_none().0, &mut error);
            if error.is_null() {
                Ok(from_glib_full(ptr))
            } else {
                Err(Error::wrap(error))
            }
        }
    }

    #[cfg(feature = "gdk_3_8")] // gdk-pixbuf 2.28
    pub fn new_from_resource(resource_path: &str) -> Result<PixbufAnimation, Error> {
        unsafe {
            let mut error = ptr::null_mut();
            let ptr = ffi::gdk_pixbuf_animation_new_from_resource(resource_path.to_glib_none().0,
                                                                  &mut error);
            if error.is_null() {
                Ok(from_glib_full(ptr))
            } else {
                Err(Error::wrap(error))
            }
        }
    }
}

pub trait PixbufAnimationExt {
    fn get_width(&self) -> i32;
    fn get_height(&self) -> i32;
    fn get_iter(&self, start_time: &TimeVal) -> PixbufAnimationIter;
    fn is_static_image(&self) -> bool;
    fn get_static_image(&self) -> Option<Pixbuf>;
}

impl<T: Upcast<PixbufAnimation>> PixbufAnimationExt for T {
    fn get_width(&self) -> i32 {
        unsafe { ffi::gdk_pixbuf_animation_get_width(self.upcast().to_glib_none().0) }
    }

    fn get_height(&self) -> i32 {
        unsafe { ffi::gdk_pixbuf_animation_get_height(self.upcast().to_glib_none().0) }
    }

    fn get_iter(&self, start_time: &TimeVal) -> PixbufAnimationIter {
        unsafe {
            from_glib_full(
                ffi::gdk_pixbuf_animation_get_iter(self.upcast().to_glib_none().0,
                                                   mem::transmute(start_time)))
        }
    }

    fn is_static_image(&self) -> bool {
        unsafe {
            from_glib(ffi::gdk_pixbuf_animation_is_static_image(self.upcast().to_glib_none().0))
        }
    }

    fn get_static_image(&self) -> Option<Pixbuf> {
        unsafe {
            from_glib_none(ffi::gdk_pixbuf_animation_get_static_image(
                self.upcast().to_glib_none().0))
        }
    }
}

pub type PixbufSimpleAnim = Object<ffi::C_GdkPixbufSimpleAnim>;

impl StaticType for PixbufSimpleAnim {
    fn static_type() -> Type { unsafe { from_glib(ffi::gdk_pixbuf_simple_anim_get_type()) } }
}

unsafe impl Upcast<PixbufAnimation> for PixbufSimpleAnim { }

impl PixbufSimpleAnim {
    pub fn new(width: i32, height: i32, rate: f32) -> PixbufSimpleAnim {
        unsafe { from_glib_full(ffi::gdk_pixbuf_simple_anim_new(width, height, rate)) }
    }

    pub fn add_frame(&self, pixbuf: &Pixbuf) {
        unsafe {
            ffi::gdk_pixbuf_simple_anim_add_frame(self.to_glib_none().0, pixbuf.to_glib_none().0)
        }
    }

    pub fn set_loop(&self, loop_: bool) {
        unsafe { ffi::gdk_pixbuf_simple_anim_set_loop(self.to_glib_none().0, loop_.to_glib()) }
    }

    pub fn get_loop(&self) -> bool {
        unsafe { from_glib(ffi::gdk_pixbuf_simple_anim_get_loop(self.to_glib_none().0)) }
    }
}
<|endoftext|>


<commit_before>extern crate reqwest;
extern crate serde;
extern crate serde_json;
extern crate regex;

use std::io::Read;
use irc::client::prelude::*;
use irc::error::Error as IrcError;
use self::regex::Regex;
use plugin::Plugin;
use self::reqwest::Client;
use self::reqwest::header::Connection;
use self::serde_json::Value;

register_plugin!(Currency);

lazy_static! {
    static ref RE: Regex = Regex::new(r"([0-9]+) ([A-Za-z]+) (?i)(to) ([A-Za-z]+)").unwrap();
}

struct ConvertionRequest<'a> {
    value: f64,
    source: &'a str,
    target: &'a str,
}

macro_rules! try_option {
    ($e:expr) => {
        match $e {
            Some(v) => v,
            None    => { return None; }
        }
    }
}

impl<'a> ConvertionRequest<'a> {
    fn send(&self) -> Option<f64> {

        let response = Client::new()
            .get("https://api.fixer.io/latest")
            .form(&[("base", self.source)])
            .header(Connection::close())
            .send();

        match response {
            Ok(mut response) => {
                let mut body = String::new();
                try_option!(response.read_to_string(&mut body).ok());

                let convertion_rates: Result<Value, _> = serde_json::from_str(&body);
                match convertion_rates {
                    Ok(convertion_rates) => {

                        let rates: &Value = try_option!(convertion_rates.get("rates"));
                        let target_rate: &Value =
                            try_option!(rates.get(self.target.to_uppercase()));
                        Some(self.value * try_option!(target_rate.as_f64()))
                    }
                    Err(_) => None,
                }
            }
            Err(_) => None,
        }
    }
}

impl Currency {
    fn grep_request<'a>(&self, msg: &'a str) -> Option<ConvertionRequest<'a>> {
        match RE.captures(msg) {
            Some(captures) => {
                Some(ConvertionRequest {
                         value: {
                             let capture = try_option!(captures.get(1)).as_str();
                             try_option!(capture.parse().ok())
                         },
                         source: try_option!(captures.get(2)).as_str(),
                         target: try_option!(captures.get(4)).as_str(), // 3 is to/TO
                     })
            }
            None => None,
        }
    }

    fn convert(&self,
               server: &IrcServer,
               _: &Message,
               target: &str,
               msg: &str)
               -> Result<(), IrcError> {
        let request = match self.grep_request(msg) {
            Some(request) => request,
            None => {
                return Ok(());
            }
        };

        match request.send() {
            Some(response) => {
                server.send_privmsg(target,
                                    &*format!("{} {} => {:.4} {}",
                                              request.value,
                                              request.source,
                                              response / 1.00000000,
                                              request.target))
            }
            None => server.send_privmsg(target, "Error while converting given currency"),
        }
    }
}

impl Plugin for Currency {
    fn is_allowed(&self, _: &IrcServer, message: &Message) -> bool {
        match message.command {
            Command::PRIVMSG(_, ref msg) => RE.is_match(msg),
            _ => false,
        }
    }

    fn execute(&mut self, server: &IrcServer, message: &Message) -> Result<(), IrcError> {
        match message.command {
            Command::PRIVMSG(ref target, ref msg) => self.convert(server, message, target, msg),
            _ => Ok(()),
        }
    }
}

#[cfg(test)]
mod tests {
    use tests::{make_server, get_server_value};

    use irc::client::prelude::*;

    use plugin::Plugin;
    use regex::Regex;
    use super::Currency;

    #[test]
    fn test_big_jpy_to_eur() {
        let server = make_server("PRIVMSG test :5000000 JPY to EUR\r\n");
        let mut plugin = Currency::new();

        for message in server.iter() {
            let message = message.unwrap();
            assert!(plugin.is_allowed(&server, &message));
            assert!(plugin.execute(&server, &message).is_ok());
        }

        let regex = Regex::new(r"=> ([0-9]{2})").unwrap();
        let msg = get_server_value(&server);
        let captures = regex.captures(&*msg).unwrap();
        assert!(captures.at(0).is_some());

        let result = captures
            .at(0)
            .unwrap()
            .split_whitespace()
            .last()
            .unwrap()
            .parse::<i32>();
        assert!(result.is_ok());

        let value = result.unwrap();
        assert!(value > 10 && value < 100);
    }
}
<commit_msg>Remove tests for from the currency plugin<commit_after>extern crate reqwest;
extern crate serde;
extern crate serde_json;
extern crate regex;

use std::io::Read;
use irc::client::prelude::*;
use irc::error::Error as IrcError;
use self::regex::Regex;
use plugin::Plugin;
use self::reqwest::Client;
use self::reqwest::header::Connection;
use self::serde_json::Value;

register_plugin!(Currency);

lazy_static! {
    static ref RE: Regex = Regex::new(r"([0-9]+) ([A-Za-z]+) (?i)(to) ([A-Za-z]+)").unwrap();
}

struct ConvertionRequest<'a> {
    value: f64,
    source: &'a str,
    target: &'a str,
}

macro_rules! try_option {
    ($e:expr) => {
        match $e {
            Some(v) => v,
            None    => { return None; }
        }
    }
}

impl<'a> ConvertionRequest<'a> {
    fn send(&self) -> Option<f64> {

        let response = Client::new()
            .get("https://api.fixer.io/latest")
            .form(&[("base", self.source)])
            .header(Connection::close())
            .send();

        match response {
            Ok(mut response) => {
                let mut body = String::new();
                try_option!(response.read_to_string(&mut body).ok());

                let convertion_rates: Result<Value, _> = serde_json::from_str(&body);
                match convertion_rates {
                    Ok(convertion_rates) => {

                        let rates: &Value = try_option!(convertion_rates.get("rates"));
                        let target_rate: &Value =
                            try_option!(rates.get(self.target.to_uppercase()));
                        Some(self.value * try_option!(target_rate.as_f64()))
                    }
                    Err(_) => None,
                }
            }
            Err(_) => None,
        }
    }
}

impl Currency {
    fn grep_request<'a>(&self, msg: &'a str) -> Option<ConvertionRequest<'a>> {
        match RE.captures(msg) {
            Some(captures) => {
                Some(ConvertionRequest {
                         value: {
                             let capture = try_option!(captures.get(1)).as_str();
                             try_option!(capture.parse().ok())
                         },
                         source: try_option!(captures.get(2)).as_str(),
                         target: try_option!(captures.get(4)).as_str(), // 3 is to/TO
                     })
            }
            None => None,
        }
    }

    fn convert(&self,
               server: &IrcServer,
               _: &Message,
               target: &str,
               msg: &str)
               -> Result<(), IrcError> {
        let request = match self.grep_request(msg) {
            Some(request) => request,
            None => {
                return Ok(());
            }
        };

        match request.send() {
            Some(response) => {
                server.send_privmsg(target,
                                    &*format!("{} {} => {:.4} {}",
                                              request.value,
                                              request.source,
                                              response / 1.00000000,
                                              request.target))
            }
            None => server.send_privmsg(target, "Error while converting given currency"),
        }
    }
}

impl Plugin for Currency {
    fn is_allowed(&self, _: &IrcServer, message: &Message) -> bool {
        match message.command {
            Command::PRIVMSG(_, ref msg) => RE.is_match(msg),
            _ => false,
        }
    }

    fn execute(&mut self, server: &IrcServer, message: &Message) -> Result<(), IrcError> {
        match message.command {
            Command::PRIVMSG(ref target, ref msg) => self.convert(server, message, target, msg),
            _ => Ok(()),
        }
    }
}

#[cfg(test)]
mod tests {
    //use tests::{make_server, get_server_value};

    //use irc::client::prelude::*;

    //use plugin::Plugin;
    //use regex::Regex;
    //use super::Currency;

    //#[test]
    //fn test_big_jpy_to_eur() {
    //    let server = make_server("PRIVMSG test :5000000 JPY to EUR\r\n");
    //    let mut plugin = Currency::new();

    //    for message in server.iter() {
    //        let message = message.unwrap();
    //        assert!(plugin.is_allowed(&server, &message));
    //        assert!(plugin.execute(&server, &message).is_ok());
    //    }

    //    let regex = Regex::new(r"=> ([0-9]{2})").unwrap();
    //    let msg = get_server_value(&server);
    //    let captures = regex.captures(&*msg).unwrap();
    //    assert!(captures.at(0).is_some());

    //    let result = captures
    //        .at(0)
    //        .unwrap()
    //        .split_whitespace()
    //        .last()
    //        .unwrap()
    //        .parse::<i32>();
    //    assert!(result.is_ok());

    //    let value = result.unwrap();
    //    assert!(value > 10 && value < 100);
    //}
}
<|endoftext|>