<commit_before>use oak_runtime::parse_state::*;
use oak_runtime::parse_state::ParseResult::*;

use std::io::prelude::*;
use std::fs::File;
use std::io::BufReader;

use ast::Stmt;

grammar! bailey {
    use ast::Ident;
    use ast::Literal;
    use ast::Expr;
    use ast::Stmt;
    use ast::Decl;
    use ast::BinOp;
    use ast::Block;
    use ast::BinOp::*;
    use ast::P;
    use std::str::FromStr;

    program
        = newlines (stmt terminator)*

    stmt
        = const_assign_stmt
        / assign_stmt
        / if_stmt
        / while_stmt
        / decl > decl_to_stmt
        / expr > expr_to_stmt

    assign_stmt
        = var_ident bind_op expr > assign_stmt

    const_assign_stmt
        = const_ident bind_op expr > const_assign_stmt

    if_stmt
        = if_kw expr block (else_kw block)? > if_stmt

    while_stmt
        = while_kw expr block > while_stmt

    decl
        = class_decl
        / method_decl

    class_decl
        = class_kw const_ident class_body > class_decl

    class_body
        = lbracket (newlines method_decl)* rbracket

    method_decl
        = def_kw meth_ident lparen param_list rparen block > method_decl

    block
        = newlines lbracket stmt_list rbracket spacing > block

    stmt_list
        = empty_stmt_list
        / stmt (terminator stmt)* > stmt_list

    function_call
        = newlines meth_ident lparen arg_list rparen

    method_call
        = callable_expr (dot function_call)+

    expr
        = newlines cond_expr

    var_expr
        = var_ident > var_expr

    const_expr
        = const_ident > const_expr

    cond_expr
        = add_expr (cond_expr_op add_expr)* > fold_left

    add_expr
        = mult_expr (add_expr_op mult_expr)* > fold_left

    mult_expr
        = primary_expr (mult_expr_op primary_expr)* > fold_left

    primary_expr
        = method_call > method_call
        / callable_expr

    callable_expr
        = function_call > function_call
        / literal > lit_to_exp
        / const_expr
        / var_expr
        / array
        / map
        / lparen expr rparen

    arg_list
        = empty_list
        / expr (comma expr)* > arg_list

    param_list
        = empty_param_list
        / var_ident (comma var_ident)* > param_list

    empty_list = &rparen > empty_list
    empty_param_list = &rparen > empty_param_list
    empty_stmt_list = &rbracket > empty_stmt_list

    digit = ["0-9"]
    upcase_ltr = ["A-Z"]
    lowcase_ltr = ["a-z_"]
    ident_char = (upcase_ltr / lowcase_ltr / digit)

    var_ident = !digit !keyword &lowcase_ltr ident_char+ spacing > var_ident
    meth_ident = !digit !keyword ident_char+ spacing > meth_ident
    const_ident = !keyword !digit &upcase_ltr ident_char+ spacing > const_ident

    literal
        = string_lit
        / float_lit
        / int_lit

    int_lit = digit+ spacing > int_lit
    float_lit = digit+ dot digit+ spacing > float_lit
    string_lit = (dbl_quot_string_lit / sng_quot_string_lit) spacing > string_lit

    array_elem = expr > array_elem
    array = lsqbracket array_elem (comma array_elem)* rsqbracket > array

    map_entry =  (expr colon expr) > map_entry
    map = lbracket map_entry (comma map_entry)* rbracket > map

    dbl_quot_string_lit = dbl_quot (spacing_char / !dbl_quot .)* dbl_quot
    sng_quot_string_lit = sng_quot (spacing_char / !sng_quot .)* sng_quot

    spacing_char = [" \r\t"]
    spacing = spacing_char* -> ()
    newline = "\n" spacing -> ()
    semicolon = ";" spacing -> ()
    newlines = newline* spacing -> ()
    terminator = (newline / semicolon) newlines -> ()

    class_kw = "class" spacing
    def_kw = "def" spacing
    else_kw = "else" spacing
    false_kw = "false" spacing
    if_kw = "if" spacing
    nil_kw = "nil" spacing
    true_kw = "true" spacing
    while_kw = "while" spacing

    keyword
        = def_kw
        / if_kw
        / else_kw
        / class_kw
        / true_kw
        / false_kw
        / nil_kw

    add_expr_op
        = add_op > add_bin_op
        / sub_op > sub_bin_op

    mult_expr_op
        = mul_op > mul_bin_op
        / div_op > div_bin_op

    cond_expr_op
        = lt_op > lt_bin_op /
        lte_op > lte_bin_op /
        gt_op > gt_bin_op /
        gte_op > gte_bin_op /
        ne_op > ne_bin_op /
        eq_op > eq_bin_op /
        andand_op > and_bin_op /
        oror_op > or_bin_op

    bind_op = "=" spacing
    add_op = "+" spacing
    sub_op = "-" spacing
    mul_op = "*" spacing
    div_op = "/" spacing
    lt_op = "<" spacing
    lte_op = "<=" spacing
    gt_op = ">" spacing
    gte_op = ">=" spacing
    ne_op = "!=" spacing
    eq_op = "==" spacing
    andand_op  = "&&" spacing
    oror_op = "||" spacing

    lparen = "(" newlines -> ()
    rparen = newlines ")" -> ()
    lbracket = "{" newlines -> ()
    rbracket = newlines "}" -> ()
    lsqbracket = "[" newlines
    rsqbracket = newlines "]"
    dbl_quot = "\"" spacing
    sng_quot = "'" spacing
    dot = "." spacing
    comma = "," spacing
    colon = ":" spacing

    fn decl_to_stmt(decl: Decl) -> Stmt {
        Stmt::Decl(P(decl))
    }

    fn expr_to_stmt(expr: Expr) -> Stmt {
        Stmt::Expr(P(expr))
    }

    fn lit_to_exp(literal: Literal) -> Expr {
        Expr::Literal(P(literal))
    }

    fn int_lit(raw_text: Vec<char>) -> Literal {
        Literal::Integer(to_number(raw_text))
    }

    fn float_lit(mut integer: Vec<char>, fractional: Vec<char>) -> Literal {
        integer.push('.');
        Literal::Float(to_float(combine(integer, fractional)))
    }

    fn string_lit(raw_text: Vec<char>) -> Literal {
        Literal::Str(to_string(raw_text))
    }

    fn array(first: P<Expr>, rest: Vec<P<Expr>>) -> Expr {
        Expr::Array(combine_one_with_many(first, rest))
    }

    fn array_elem(expr: Expr) -> P<Expr> {
        P(expr)
    }

    fn map(first: (P<Expr>, P<Expr>), rest: Vec<(P<Expr>, P<Expr>)>) -> Expr {
        Expr::Map(combine_one_with_many(first, rest))
    }

    fn map_entry(key: Expr, val: Expr) -> (P<Expr>, P<Expr>) {
        (P(key), P(val))
    }

    fn const_expr(ident: Ident) -> Expr {
        Expr::Const(P(ident))
    }

    fn const_ident(raw_text: Vec<char>) -> Ident {
        Ident::Const(to_string(raw_text))
    }

    fn var_expr(ident: Ident) -> Expr {
        Expr::Var(P(ident))
    }

    fn var_ident(raw_text: Vec<char>) -> Ident {
        Ident::Var(to_string(raw_text))
    }

    fn meth_ident(raw_text: Vec<char>) -> Ident {
        Ident::Meth(to_string(raw_text))
    }

    fn add_bin_op() -> BinOp { Add }
    fn sub_bin_op() -> BinOp { Sub }
    fn mul_bin_op() -> BinOp { Mul }
    fn div_bin_op() -> BinOp { Div }
    fn lt_bin_op() -> BinOp { Lt }
    fn lte_bin_op() -> BinOp { Lte }
    fn gt_bin_op() -> BinOp { Gt }
    fn gte_bin_op() -> BinOp { Gte }
    fn ne_bin_op() -> BinOp { Ne }
    fn eq_bin_op() -> BinOp { Eq }
    fn and_bin_op() -> BinOp { And }
    fn or_bin_op() -> BinOp { Or }

    fn function_call(func: Ident, args: Vec<Expr>) -> Expr {
        Expr::Message(None, P(func), args)
    }

    fn method_call(recv: Expr, call: Vec<(Ident, Vec<Expr>)>) -> Expr {
        call.into_iter().fold(recv, { |accu, (method, args)|
            Expr::Message(Some(P(accu)), P(method), args)
        })
    }

    fn assign_stmt(var: Ident, expr: Expr) -> Stmt {
        Stmt::VarAssign(P(var), P(expr))
    }

    fn const_assign_stmt(constant: Ident, expr: Expr) -> Stmt {
        Stmt::ConstAssign(P(constant), P(expr))
    }

    fn class_decl(class: Ident, methods: Vec<Decl>) -> Decl {
        Decl::Class(P(class), methods)
    }

    fn method_decl(meth: Ident, params: Vec<Ident>, block: Block) -> Decl {
        Decl::Method(P(meth), params, P(block))
    }

    fn block(stmts: Vec<Stmt>) -> Block {
        Block { stmts: stmts }
    }

    fn program(first: Stmt, mut rest: Vec<Stmt>) -> Vec<Stmt> {
        combine_one_with_many(first, rest)
    }

    fn if_stmt(cond: Expr, true_blk: Block, false_blk: Option<Block>) -> Stmt {
        let false_blk = match false_blk {
            Some(blk) => Some(P(blk)),
            None => None
        };

        Stmt::If(P(cond), P(true_blk), false_blk)
    }

    fn while_stmt(cond: Expr, blk: Block) -> Stmt {
        Stmt::While(P(cond), P(blk))
    }

    fn arg_list(first: Expr, mut rest: Vec<Expr>) -> Vec<Expr> {
        combine_one_with_many(first, rest)
    }

    fn param_list(first: Ident, mut rest: Vec<Ident>) -> Vec<Ident> {
        combine_one_with_many(first, rest)
    }

    fn empty_param_list() -> Vec<Ident> {
        vec![]
    }

    fn stmt_list(first: Stmt, mut rest: Vec<Stmt>) -> Vec<Stmt> {
        combine_one_with_many(first, rest)
    }

    fn empty_list() -> Vec<Expr> {
        vec![]
    }

    fn empty_stmt_list() -> Vec<Stmt> {
        vec![]
    }

    fn to_string(raw_text: Vec<char>) -> String {
        raw_text.into_iter().collect()
    }

    fn to_number(raw_text: Vec<char>) -> i64 {
        i64::from_str(&*to_string(raw_text)).unwrap()
    }

    fn to_float(raw_text: Vec<char>) -> f64 {
        f64::from_str(&*to_string(raw_text)).unwrap()
    }

    fn fold_left(head: Expr, rest: Vec<(BinOp, Expr)>) -> Expr {
        rest.into_iter().fold(head,
          |accu, (op, expr)| Expr::Binary(op, P(accu), P(expr)))
    }

    fn combine<T: Clone>(mut left: Vec<T>, right: Vec<T>) -> Vec<T> {
        left.extend(right.into_iter());
        left
    }

    fn combine_one_with_many<T: Clone>(first: T, rest: Vec<T>) -> Vec<T> {
        combine(vec![first], rest)
    }
}

pub struct Parser {
    pub ast: Option<Vec<Stmt>>,
}

impl Parser {
    pub fn new() -> Parser {
        Parser { ast: None }
    }

    pub fn parse_file(&mut self, file_path: String) -> Result<Vec<Stmt>, String> {
        match File::open(file_path) {
            Ok(file) => {
                let mut reader = BufReader::new(file);
                let mut code = String::new();
                let _ = reader.read_to_string(&mut code);
                self.parse(code)
            }
            Err(error) => Err(format!("Error: {}", error)),
        }
    }

    pub fn parse(&mut self, code: String) -> Result<Vec<Stmt>, String> {
        let state = bailey::parse_program(code.into_state());

        match state.into_result() {
            Success(data) => Ok(data.clone()),
            Partial(data, expectation) => {
                Err(format!("Partial match: {:?} because: {:?}", data, expectation))
            }
            Failure(expectation) => {
                Err(format!("Error: {:?}", expectation))
            }
        }
    }
}

<commit_msg>Added macros to build the AST during testing. First tests of the parser using the macros.<commit_after>use oak_runtime::parse_state::*;
use oak_runtime::parse_state::ParseResult::*;

use std::io::prelude::*;
use std::fs::File;
use std::io::BufReader;

use ast::Stmt;

grammar! bailey {
    use ast::Ident;
    use ast::Literal;
    use ast::Expr;
    use ast::Stmt;
    use ast::Decl;
    use ast::BinOp;
    use ast::Block;
    use ast::BinOp::*;
    use ast::P;
    use std::str::FromStr;

    program
        = newlines (stmt terminator)*

    stmt
        = const_assign_stmt
        / assign_stmt
        / if_stmt
        / while_stmt
        / decl > decl_to_stmt
        / expr > expr_to_stmt

    assign_stmt
        = var_ident bind_op expr > assign_stmt

    const_assign_stmt
        = const_ident bind_op expr > const_assign_stmt

    if_stmt
        = if_kw expr block (else_kw block)? > if_stmt

    while_stmt
        = while_kw expr block > while_stmt

    decl
        = class_decl
        / method_decl

    class_decl
        = class_kw const_ident class_body > class_decl

    class_body
        = lbracket (newlines method_decl)* rbracket

    method_decl
        = def_kw meth_ident lparen param_list rparen block > method_decl

    block
        = newlines lbracket stmt_list rbracket spacing > block

    stmt_list
        = empty_stmt_list
        / stmt (terminator stmt)* > stmt_list

    function_call
        = newlines meth_ident lparen arg_list rparen

    method_call
        = callable_expr (dot function_call)+

    expr
        = newlines cond_expr

    var_expr
        = var_ident > var_expr

    const_expr
        = const_ident > const_expr

    cond_expr
        = add_expr (cond_expr_op add_expr)* > fold_left

    add_expr
        = mult_expr (add_expr_op mult_expr)* > fold_left

    mult_expr
        = primary_expr (mult_expr_op primary_expr)* > fold_left

    primary_expr
        = method_call > method_call
        / callable_expr

    callable_expr
        = function_call > function_call
        / literal > lit_to_exp
        / const_expr
        / var_expr
        / array
        / map
        / lparen expr rparen

    arg_list
        = empty_list
        / expr (comma expr)* > arg_list

    param_list
        = empty_param_list
        / var_ident (comma var_ident)* > param_list

    empty_list = &rparen > empty_list
    empty_param_list = &rparen > empty_param_list
    empty_stmt_list = &rbracket > empty_stmt_list

    digit = ["0-9"]
    upcase_ltr = ["A-Z"]
    lowcase_ltr = ["a-z_"]
    ident_char = (upcase_ltr / lowcase_ltr / digit)

    var_ident = !digit !keyword &lowcase_ltr ident_char+ spacing > var_ident
    meth_ident = !digit !keyword ident_char+ spacing > meth_ident
    const_ident = !keyword !digit &upcase_ltr ident_char+ spacing > const_ident

    literal
        = string_lit
        / float_lit
        / int_lit

    int_lit = digit+ spacing > int_lit
    float_lit = digit+ dot digit+ spacing > float_lit
    string_lit = (dbl_quot_string_lit / sng_quot_string_lit) spacing > string_lit

    array_elem = expr > array_elem
    array = lsqbracket array_elem (comma array_elem)* rsqbracket > array

    map_entry =  (expr colon expr) > map_entry
    map = lbracket map_entry (comma map_entry)* rbracket > map

    dbl_quot_string_lit = dbl_quot (spacing_char / !dbl_quot .)* dbl_quot
    sng_quot_string_lit = sng_quot (spacing_char / !sng_quot .)* sng_quot

    spacing_char = [" \r\t"]
    spacing = spacing_char* -> ()
    newline = "\n" spacing -> ()
    semicolon = ";" spacing -> ()
    newlines = newline* spacing -> ()
    terminator = (newline / semicolon) newlines -> ()

    class_kw = "class" spacing
    def_kw = "def" spacing
    else_kw = "else" spacing
    false_kw = "false" spacing
    if_kw = "if" spacing
    nil_kw = "nil" spacing
    true_kw = "true" spacing
    while_kw = "while" spacing

    keyword
        = def_kw
        / if_kw
        / else_kw
        / class_kw
        / true_kw
        / false_kw
        / nil_kw

    add_expr_op
        = add_op > add_bin_op
        / sub_op > sub_bin_op

    mult_expr_op
        = mul_op > mul_bin_op
        / div_op > div_bin_op

    cond_expr_op
        = lt_op > lt_bin_op /
        lte_op > lte_bin_op /
        gt_op > gt_bin_op /
        gte_op > gte_bin_op /
        ne_op > ne_bin_op /
        eq_op > eq_bin_op /
        andand_op > and_bin_op /
        oror_op > or_bin_op

    bind_op = "=" spacing
    add_op = "+" spacing
    sub_op = "-" spacing
    mul_op = "*" spacing
    div_op = "/" spacing
    lt_op = "<" spacing
    lte_op = "<=" spacing
    gt_op = ">" spacing
    gte_op = ">=" spacing
    ne_op = "!=" spacing
    eq_op = "==" spacing
    andand_op  = "&&" spacing
    oror_op = "||" spacing

    lparen = "(" newlines -> ()
    rparen = newlines ")" -> ()
    lbracket = "{" newlines -> ()
    rbracket = newlines "}" -> ()
    lsqbracket = "[" newlines
    rsqbracket = newlines "]"
    dbl_quot = "\"" spacing
    sng_quot = "'" spacing
    dot = "." spacing
    comma = "," spacing
    colon = ":" spacing

    fn decl_to_stmt(decl: Decl) -> Stmt {
        Stmt::Decl(P(decl))
    }

    fn expr_to_stmt(expr: Expr) -> Stmt {
        Stmt::Expr(P(expr))
    }

    fn lit_to_exp(literal: Literal) -> Expr {
        Expr::Literal(P(literal))
    }

    fn int_lit(raw_text: Vec<char>) -> Literal {
        Literal::Integer(to_number(raw_text))
    }

    fn float_lit(mut integer: Vec<char>, fractional: Vec<char>) -> Literal {
        integer.push('.');
        Literal::Float(to_float(combine(integer, fractional)))
    }

    fn string_lit(raw_text: Vec<char>) -> Literal {
        Literal::Str(to_string(raw_text))
    }

    fn array(first: P<Expr>, rest: Vec<P<Expr>>) -> Expr {
        Expr::Array(combine_one_with_many(first, rest))
    }

    fn array_elem(expr: Expr) -> P<Expr> {
        P(expr)
    }

    fn map(first: (P<Expr>, P<Expr>), rest: Vec<(P<Expr>, P<Expr>)>) -> Expr {
        Expr::Map(combine_one_with_many(first, rest))
    }

    fn map_entry(key: Expr, val: Expr) -> (P<Expr>, P<Expr>) {
        (P(key), P(val))
    }

    fn const_expr(ident: Ident) -> Expr {
        Expr::Const(P(ident))
    }

    fn const_ident(raw_text: Vec<char>) -> Ident {
        Ident::Const(to_string(raw_text))
    }

    fn var_expr(ident: Ident) -> Expr {
        Expr::Var(P(ident))
    }

    fn var_ident(raw_text: Vec<char>) -> Ident {
        Ident::Var(to_string(raw_text))
    }

    fn meth_ident(raw_text: Vec<char>) -> Ident {
        Ident::Meth(to_string(raw_text))
    }

    fn add_bin_op() -> BinOp { Add }
    fn sub_bin_op() -> BinOp { Sub }
    fn mul_bin_op() -> BinOp { Mul }
    fn div_bin_op() -> BinOp { Div }
    fn lt_bin_op() -> BinOp { Lt }
    fn lte_bin_op() -> BinOp { Lte }
    fn gt_bin_op() -> BinOp { Gt }
    fn gte_bin_op() -> BinOp { Gte }
    fn ne_bin_op() -> BinOp { Ne }
    fn eq_bin_op() -> BinOp { Eq }
    fn and_bin_op() -> BinOp { And }
    fn or_bin_op() -> BinOp { Or }

    fn function_call(func: Ident, args: Vec<Expr>) -> Expr {
        Expr::Message(None, P(func), args)
    }

    fn method_call(recv: Expr, call: Vec<(Ident, Vec<Expr>)>) -> Expr {
        call.into_iter().fold(recv, { |accu, (method, args)|
            Expr::Message(Some(P(accu)), P(method), args)
        })
    }

    fn assign_stmt(var: Ident, expr: Expr) -> Stmt {
        Stmt::VarAssign(P(var), P(expr))
    }

    fn const_assign_stmt(constant: Ident, expr: Expr) -> Stmt {
        Stmt::ConstAssign(P(constant), P(expr))
    }

    fn class_decl(class: Ident, methods: Vec<Decl>) -> Decl {
        Decl::Class(P(class), methods)
    }

    fn method_decl(meth: Ident, params: Vec<Ident>, block: Block) -> Decl {
        Decl::Method(P(meth), params, P(block))
    }

    fn block(stmts: Vec<Stmt>) -> Block {
        Block { stmts: stmts }
    }

    fn program(first: Stmt, mut rest: Vec<Stmt>) -> Vec<Stmt> {
        combine_one_with_many(first, rest)
    }

    fn if_stmt(cond: Expr, true_blk: Block, false_blk: Option<Block>) -> Stmt {
        let false_blk = match false_blk {
            Some(blk) => Some(P(blk)),
            None => None
        };

        Stmt::If(P(cond), P(true_blk), false_blk)
    }

    fn while_stmt(cond: Expr, blk: Block) -> Stmt {
        Stmt::While(P(cond), P(blk))
    }

    fn arg_list(first: Expr, mut rest: Vec<Expr>) -> Vec<Expr> {
        combine_one_with_many(first, rest)
    }

    fn param_list(first: Ident, mut rest: Vec<Ident>) -> Vec<Ident> {
        combine_one_with_many(first, rest)
    }

    fn empty_param_list() -> Vec<Ident> {
        vec![]
    }

    fn stmt_list(first: Stmt, mut rest: Vec<Stmt>) -> Vec<Stmt> {
        combine_one_with_many(first, rest)
    }

    fn empty_list() -> Vec<Expr> {
        vec![]
    }

    fn empty_stmt_list() -> Vec<Stmt> {
        vec![]
    }

    fn to_string(raw_text: Vec<char>) -> String {
        raw_text.into_iter().collect()
    }

    fn to_number(raw_text: Vec<char>) -> i64 {
        i64::from_str(&*to_string(raw_text)).unwrap()
    }

    fn to_float(raw_text: Vec<char>) -> f64 {
        f64::from_str(&*to_string(raw_text)).unwrap()
    }

    fn fold_left(head: Expr, rest: Vec<(BinOp, Expr)>) -> Expr {
        rest.into_iter().fold(head,
          |accu, (op, expr)| Expr::Binary(op, P(accu), P(expr)))
    }

    fn combine<T: Clone>(mut left: Vec<T>, right: Vec<T>) -> Vec<T> {
        left.extend(right.into_iter());
        left
    }

    fn combine_one_with_many<T: Clone>(first: T, rest: Vec<T>) -> Vec<T> {
        combine(vec![first], rest)
    }
}

pub struct Parser {
    pub ast: Option<Vec<Stmt>>,
}

impl Parser {
    pub fn new() -> Parser {
        Parser { ast: None }
    }

    pub fn parse_file(&mut self, file_path: String) -> Result<Vec<Stmt>, String> {
        match File::open(file_path) {
            Ok(file) => {
                let mut reader = BufReader::new(file);
                let mut code = String::new();
                let _ = reader.read_to_string(&mut code);
                self.parse(code)
            }
            Err(error) => Err(format!("Error: {}", error)),
        }
    }

    pub fn parse(&mut self, code: String) -> Result<Vec<Stmt>, String> {
        let state = bailey::parse_program(code.into_state());

        match state.into_result() {
            Success(data) => Ok(data.clone()),
            Partial(data, expectation) => {
                Err(format!("Partial match: {:?} because: {:?}", data, expectation))
            }
            Failure(expectation) => {
                Err(format!("Error: {:?}", expectation))
            }
        }
    }
}

mod tests {
    use super::Parser;
    use ast::Stmt;
    use ast::Expr;
    use ast::Literal;
    use ast::Ident;
    use ast::P;

    macro_rules! expr {
        ($e:expr) => (
            Stmt::Expr($e)
        );
    }

    macro_rules! literal {
        ($e:expr) => (
            P(Expr::Literal($e))
        );
    }

    macro_rules! integer {
        ($e:expr) => (
            P(Literal::Integer($e))
        );
    }

    macro_rules! float {
        ($e: expr) => (
            P(Literal::Float($e))
        );
    }

    macro_rules! str {
        ($e:expr) => (
            P(Literal::Str($e.to_string()))
        );
    }

   macro_rules! array {
    ( $( $x:expr ),* ) => {
            P(Expr::Array(vec![$($x,)*]))
        };
    }

   macro_rules! var {
        ($e:expr) => {
            P(Expr::Var($e))
        };
   }

   macro_rules! var_ident {
        ($e:expr) => {
            P(Ident::Var($e.to_string()))
        };
   }

   macro_rules! map {
    ( $( ($k:expr, $v:expr) ),* ) => {
            P(Expr::Map(vec![$(($k, $v),)*]))
        };
    }

   #[test]
    fn test_parse_int_lit() {
        let mut parser = Parser::new();
        let code = "42;".to_string();
        let ast = parser.parse(code).unwrap();
        assert_eq!(ast, vec![
                expr!(literal!(integer!(42)))
            ]
        );
    }

    #[test]
    fn test_parse_float_lit() {
        let mut parser = Parser::new();
        let code = "42.00;".to_string();
        let ast = parser.parse(code).unwrap();
        assert_eq!(ast, vec![
                expr!(literal!(float!(42.00)))
            ]
        );
    }

    #[test]
    fn test_parse_string_lit() {
        let mut parser = Parser::new();
        let code = "\"fooooo\";".to_string();
        let ast = parser.parse(code).unwrap();
        assert_eq!(ast, vec![
                expr!(literal!(str!("fooooo")))
            ]
        );
    }

    #[test]
    fn test_parse_array() {
        let mut parser = Parser::new();
        let code = "[1, 2.0, \"foo\"];".to_string();
        let ast = parser.parse(code).unwrap();
        assert_eq!(ast, vec![
            expr!(
                array!(
                    literal!(integer!(1)),
                    literal!(float!(2.0)),
                    literal!(str!("foo"))
                )
            )
        ]);
    }

    #[test]
    fn test_parse_map() {
        let mut parser = Parser::new();
        let code = "{a: 1, b: 2};".to_string();
        let ast = parser.parse(code).unwrap();
        assert_eq!(ast, vec![
            expr!(
                map!(
                    (var!(var_ident!("a")), literal!(integer!(1))),
                    (var!(var_ident!("b")), literal!(integer!(2)))
                )
            )
        ]);
    }
}
<|endoftext|>


<commit_before>use nom::{alpha, alphanumeric, rest};
use std::vec::Vec;

use template::Chunk;

named!(var_name<Vec<u8>>,
    map!(
        recognize!(
            do_parse!(
                alpha >>
                many0!(alt!(alphanumeric | tag!("_"))) >>
                ()
            )
        ), Vec::from
    )
);

named!(var<Chunk>,
    map!(
        ws!(
            delimited!(
                tag!("{%"),
                var_name,
                tag!("%}")
            )
        ),
        |v| Chunk::Var(Vec::from(v))
    )
);

named!(escaped<Chunk>,
    do_parse!(
        tag!("{%%") >>
        (Chunk::Str(b"{%".to_vec()))
    )
);

named!(literal<Chunk>,
    map!(
        alt_complete!(take_until!("{%") | rest),
        |s| Chunk::Str(Vec::from(s))
    )
);

named!(pub template<Vec<Chunk>>,
    many0!(
        alt!(var | escaped | literal)
    )
);

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

    macro_rules! str {
        ($s: expr) => (Chunk::Str($s.to_vec()))
    }

    macro_rules! var {
        ($s: expr) => (Chunk::Var($s.to_vec()))
    }

    #[test]
    fn basic() {
        let (_, parsed) = template(b"Hello, {% who %}!").unwrap();
        let chunks = vec![str!(b"Hello, "), var!(b"who"), str!(b"!")];
        assert_eq!(chunks, parsed);
    }

    #[test]
    fn escaped() {
        let (_, parsed) = template(b"Hello, {%% who %}!").unwrap();
        let chunks = vec![str!(b"Hello, "), str!(b"{%"), str!(b" who %}!")];
        assert_eq!(chunks, parsed)
    }
}
<commit_msg>Test parsing without vars<commit_after>use nom::{alpha, alphanumeric, rest};
use std::vec::Vec;

use template::Chunk;

named!(var_name<Vec<u8>>,
    map!(
        recognize!(
            do_parse!(
                alpha >>
                many0!(alt!(alphanumeric | tag!("_"))) >>
                ()
            )
        ), Vec::from
    )
);

named!(var<Chunk>,
    map!(
        ws!(
            delimited!(
                tag!("{%"),
                var_name,
                tag!("%}")
            )
        ),
        |v| Chunk::Var(Vec::from(v))
    )
);

named!(escaped<Chunk>,
    do_parse!(
        tag!("{%%") >>
        (Chunk::Str(b"{%".to_vec()))
    )
);

named!(literal<Chunk>,
    map!(
        alt_complete!(take_until!("{%") | rest),
        |s| Chunk::Str(Vec::from(s))
    )
);

named!(pub template<Vec<Chunk>>,
    many0!(
        alt!(var | escaped | literal)
    )
);

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

    macro_rules! str {
        ($s: expr) => (Chunk::Str($s.to_vec()))
    }

    macro_rules! var {
        ($s: expr) => (Chunk::Var($s.to_vec()))
    }

    #[test]
    fn basic() {
        let (_, parsed) = template(b"Hello, {% who %}!").unwrap();
        let chunks = vec![str!(b"Hello, "), var!(b"who"), str!(b"!")];
        assert_eq!(chunks, parsed);
    }

    #[test]
    fn escaped() {
        let (_, parsed) = template(b"Hello, {%% who %}!").unwrap();
        let chunks = vec![str!(b"Hello, "), str!(b"{%"), str!(b" who %}!")];
        assert_eq!(chunks, parsed)
    }

    #[test]
    fn no_vars() {
        let (_, parsed) = template(b"Hello, world!").unwrap();
        let chunks = vec![str!(b"Hello, world!")];
        assert_eq!(chunks, parsed)
    }
}
<|endoftext|>


<commit_before>use crate::plugins;
use comrak::{
    format_html,
    nodes::{AstNode, NodeHtmlBlock, NodeValue},
    parse_document, ComrakExtensionOptions, ComrakOptions, ComrakParseOptions,
    ComrakRenderOptions,
};
use std::string::FromUtf8Error;
use std::{
    collections::BTreeMap,
    sync::{Arc, Mutex},
};
use syntect::{
    highlighting::{Color, ThemeSet},
    html::highlighted_html_for_string,
    parsing::SyntaxSet,
};
use thiserror::Error;
use typed_arena::Arena;
use url_path::UrlPath;

#[derive(Error, Debug)]
pub enum ParseError {
    #[error("Utf8Error: `{0}`")]
    Utf8Error(#[from] FromUtf8Error),
    #[error("Error getting lock from embed file")]
    EmbedFileLockError,
    #[error("Error parsing md file")]
    MdParseError,
}

#[derive(Debug)]
pub struct Html {
    pub title: Option<String>,
    pub content: String,
}

pub struct Settings {
    /// add a base directory for all links to other md files
    base_dir: Option<String>,
    /// apply ammonia to remove xss from the generated html
    clean_xss: bool,
    /// if true, external links that doesn't end with `.md` will be linked as is
    link_non_md_external: bool,
}

impl Default for Settings {
    fn default() -> Self {
        Settings {
            base_dir: None,
            clean_xss: true,
            link_non_md_external: true,
        }
    }
}

pub fn parse(arg: &str) -> Result<Html, ParseError> {
    let referred_files = pre_parse_get_embedded_files(arg);
    let embed_files = if let Ok(referred_files) = referred_files {
        let file_contents = plugins::fetch_file_contents(referred_files);
        Some(file_contents)
    } else {
        None
    };
    parse_with_settings(arg, &embed_files, &Settings::default())
}

pub fn parse_with_base_dir(
    arg: &str,
    base_dir: &str,
    embed_files: &Option<BTreeMap<String, Vec<u8>>>,
) -> Result<Html, ParseError> {
    let settings = Settings {
        base_dir: Some(base_dir.to_string()),
        ..Default::default()
    };
    parse_with_settings(arg, &embed_files, &settings)
}

pub fn parse_with_settings(
    arg: &str,
    embed_files: &Option<BTreeMap<String, Vec<u8>>>,
    settings: &Settings,
) -> Result<Html, ParseError> {
    let html = parse_via_comrak(arg, &embed_files, settings);
    html
}

fn get_comrak_options() -> ComrakOptions {
    ComrakOptions {
        extension: ComrakExtensionOptions {
            strikethrough: true,
            tagfilter: false,
            table: true,
            autolink: true,
            tasklist: true,
            superscript: false,
            header_ids: None,
            footnotes: true,
            description_lists: true,
        },
        parse: ComrakParseOptions {
            smart: false,
            default_info_string: None,
        },
        render: ComrakRenderOptions {
            hardbreaks: true,
            github_pre_lang: true,
            width: 0,
            unsafe_: true,
            escape: false,
        },
    }
}

fn iter_nodes<'a, F>(
    node: &'a AstNode<'a>,
    is_heading: Arc<Mutex<bool>>,
    title: Arc<Mutex<Option<String>>>,
    f: &F,
) where
    F: Fn(&'a AstNode<'a>),
{
    f(node);
    for c in node.children() {
        iter_nodes(c, is_heading.clone(), title.clone(), f);
    }
}

fn pre_iter_nodes<'a, F>(
    node: &'a AstNode<'a>,
    files: Arc<Mutex<Vec<String>>>,
    f: &F,
) where
    F: Fn(&'a AstNode<'a>),
{
    f(node);
    for c in node.children() {
        pre_iter_nodes(c, files.clone(), f);
    }
}
///
/// Extract the embeded files in img image and make it as a lookup
pub fn pre_parse_get_embedded_files(
    arg: &str,
) -> Result<Vec<String>, ParseError> {
    // The returned nodes are created in the supplied Arena, and are bound by its lifetime.
    let arena = Arena::new();
    let option = get_comrak_options();
    let root = parse_document(&arena, arg, &option);
    let embed_files: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![]));

    pre_iter_nodes(root, embed_files.clone(), &|node| {
        let ref mut value = node.data.borrow_mut().value;
        let new_value = match value {
            &mut NodeValue::Image(ref link) => {
                let link_url = String::from_utf8(link.url.clone())
                    .expect("unable to convert to string");
                if let Ok(mut embed_files) = embed_files.lock() {
                    embed_files.push(link_url);
                }
                value.clone()
            }
            _ => value.clone(),
        };
        *value = new_value;
    });
    let embedded = match embed_files.lock() {
        Ok(files) => Ok((*files).to_owned()),
        Err(_e) => Err(ParseError::EmbedFileLockError),
    };
    embedded
}

fn parse_via_comrak(
    arg: &str,
    embed_files: &Option<BTreeMap<String, Vec<u8>>>,
    settings: &Settings,
) -> Result<Html, ParseError> {
    // The returned nodes are created in the supplied Arena, and are bound by its lifetime.
    let arena = Arena::new();
    let option = get_comrak_options();
    let title: Arc<Mutex<Option<String>>> = Arc::new(Mutex::new(None));
    let is_heading: Arc<Mutex<bool>> = Arc::new(Mutex::new(false));
    let root = parse_document(&arena, arg, &option);

    iter_nodes(root, is_heading.clone(), title.clone(), &|node| {
        let ref mut value = node.data.borrow_mut().value;
        let new_value = match value {
            &mut NodeValue::CodeBlock(ref codeblock) => {
                let codeblock_info =
                    String::from_utf8(codeblock.info.to_owned())
                        .expect("error converting to string");
                let codeblock_literal =
                    String::from_utf8(codeblock.literal.to_owned())
                        .expect("error converting to string");
                if let Ok(out) = plugins::plugin_executor(
                    &codeblock_info,
                    &codeblock_literal,
                ) {
                    NodeValue::HtmlBlock(NodeHtmlBlock {
                        literal: out.into_bytes(),
                        block_type: 0,
                    })
                } else if let Some(code_block_html) =
                    format_source_code(&codeblock_info, &codeblock_literal)
                {
                    code_block_html
                } else {
                    value.clone()
                }
            }
            &mut NodeValue::Link(ref nodelink) => {
                if let Ok(url) = String::from_utf8(nodelink.url.clone()) {
                    if let Some(ref base_dir) = settings.base_dir {
                        let url1 = UrlPath::new(&url);
                        let url2 = url1.normalize();
                        let url3 = if url1.is_external() {
                            url2
                        } else if url1.is_absolute() {
                            url2
                        } else {
                            format!("{}/{}", base_dir, url)
                        };
                        let url4 = UrlPath::new(&url3);
                        let url5 = url4.normalize();
                        let url6 = if url4.is_external()
                            && !url4.is_extension("md")
                            && settings.link_non_md_external
                        {
                            // leave as it
                            url5
                        } else {
                            format!("/#{}", url5)
                        };
                        log::info!("url6: {}", url6);
                        let mut new_nodelink = nodelink.clone();
                        new_nodelink.url = url6.into_bytes();
                        NodeValue::Link(new_nodelink)
                    } else {
                        value.clone()
                    }
                } else {
                    value.clone()
                }
            }
            &mut NodeValue::Heading(ref heading) => {
                if heading.level == 1 {
                    if let Ok(mut is_heading) = is_heading.lock() {
                        *is_heading = true;
                    }
                }
                value.clone()
            }
            &mut NodeValue::Text(ref text) => {
                if let Ok(is_heading) = is_heading.lock() {
                    if *is_heading {
                        let txt = String::from_utf8(text.to_owned())
                            .expect("Unable to convert to string");
                        if let Ok(mut title) = title.lock() {
                            if title.is_none() {
                                // only when unset
                                *title = Some(txt.to_string());
                            }
                        }
                    }
                }
                value.clone()
            }
            &mut NodeValue::Image(ref link) => {
                let link_url = String::from_utf8(link.url.clone())
                    .expect("unable to convert to string");
                match plugins::embed_handler(&link_url, embed_files) {
                    Ok(html) => NodeValue::HtmlBlock(NodeHtmlBlock {
                        literal: html.into_bytes(),
                        block_type: 0,
                    }),
                    Err(e) => {
                        log::error!("error: {:#?}", e);
                        value.clone()
                    }
                }
            }
            _ => value.clone(),
        };
        *value = new_value;
    });

    let mut html = vec![];

    if let Ok(()) = format_html(root, &option, &mut html) {
        let render_html = String::from_utf8(html)?;
        let title = if let Ok(got) = title.lock() {
            if let Some(ref got) = *got {
                Some(got.to_string())
            } else {
                None
            }
        } else {
            None
        };
        if settings.clean_xss {
            Ok(Html {
                title,
                content: render_html,
            })
        } else {
            Ok(Html {
                title,
                content: render_html,
            })
        }
    } else {
        Err(ParseError::MdParseError)
    }
}

fn format_source_code(lang: &str, literal: &str) -> Option<NodeValue> {
    let lang_name = match lang {
        "rust" => "Rust",
        _ => "text",
    };

    let ss = SyntaxSet::load_defaults_newlines();
    let ts = ThemeSet::load_defaults();
    let theme = &ts.themes["base16-ocean.light"];
    let _c = theme.settings.background.unwrap_or(Color::WHITE);

    if let Some(syntax) = ss.find_syntax_by_name(lang_name) {
        let html = highlighted_html_for_string(literal, &ss, &syntax, theme);
        Some(NodeValue::HtmlBlock(NodeHtmlBlock {
            literal: html.into_bytes(),
            block_type: 0,
        }))
    } else {
        None
    }
}
<commit_msg>catch all errors including string conversion to utf8<commit_after>use crate::plugins;
use comrak::{
    format_html,
    nodes::{AstNode, NodeHtmlBlock, NodeValue},
    parse_document, ComrakExtensionOptions, ComrakOptions, ComrakParseOptions,
    ComrakRenderOptions,
};
use std::string::FromUtf8Error;
use std::{
    collections::BTreeMap,
    sync::{Arc, Mutex},
};
use syntect::{
    highlighting::{Color, ThemeSet},
    html::highlighted_html_for_string,
    parsing::SyntaxSet,
};
use thiserror::Error;
use typed_arena::Arena;
use url_path::UrlPath;

#[derive(Error, Debug)]
pub enum ParseError {
    #[error("Utf8Error: `{0}`")]
    Utf8Error(#[from] FromUtf8Error),
    #[error("Error getting lock from embed file")]
    EmbedFileLockError,
    #[error("Error parsing md file")]
    MdParseError,
}

#[derive(Debug)]
pub struct Html {
    pub title: Option<String>,
    pub content: String,
}

pub struct Settings {
    /// add a base directory for all links to other md files
    base_dir: Option<String>,
    /// if true, external links that doesn't end with `.md` will be linked as is
    link_non_md_external: bool,
}

impl Default for Settings {
    fn default() -> Self {
        Settings {
            base_dir: None,
            link_non_md_external: true,
        }
    }
}

pub fn parse(arg: &str) -> Result<Html, ParseError> {
    let referred_files = pre_parse_get_embedded_files(arg);
    let embed_files = if let Ok(referred_files) = referred_files {
        let file_contents = plugins::fetch_file_contents(referred_files);
        Some(file_contents)
    } else {
        None
    };
    parse_with_settings(arg, &embed_files, &Settings::default())
}

pub fn parse_with_base_dir(
    arg: &str,
    base_dir: &str,
    embed_files: &Option<BTreeMap<String, Vec<u8>>>,
) -> Result<Html, ParseError> {
    let settings = Settings {
        base_dir: Some(base_dir.to_string()),
        ..Default::default()
    };
    parse_with_settings(arg, &embed_files, &settings)
}

pub fn parse_with_settings(
    arg: &str,
    embed_files: &Option<BTreeMap<String, Vec<u8>>>,
    settings: &Settings,
) -> Result<Html, ParseError> {
    let html = parse_via_comrak(arg, &embed_files, settings);
    html
}

fn get_comrak_options() -> ComrakOptions {
    ComrakOptions {
        extension: ComrakExtensionOptions {
            strikethrough: true,
            tagfilter: false,
            table: true,
            autolink: true,
            tasklist: true,
            superscript: false,
            header_ids: None,
            footnotes: true,
            description_lists: true,
        },
        parse: ComrakParseOptions {
            smart: false,
            default_info_string: None,
        },
        render: ComrakRenderOptions {
            hardbreaks: true,
            github_pre_lang: true,
            width: 0,
            unsafe_: true,
            escape: false,
        },
    }
}

fn iter_nodes<'a, F>(
    node: &'a AstNode<'a>,
    is_heading: Arc<Mutex<bool>>,
    title: Arc<Mutex<Option<String>>>,
    f: &F,
) -> Result<(), ParseError>
where
    F: Fn(&'a AstNode<'a>) -> Result<(), ParseError>,
{
    f(node)?;
    for c in node.children() {
        iter_nodes(c, is_heading.clone(), title.clone(), f)?;
    }
    Ok(())
}

fn pre_iter_nodes<'a, F>(
    node: &'a AstNode<'a>,
    files: Arc<Mutex<Vec<String>>>,
    f: &F,
) -> Result<(), ParseError>
where
    F: Fn(&'a AstNode<'a>) -> Result<(), ParseError>,
{
    f(node)?;
    for c in node.children() {
        pre_iter_nodes(c, files.clone(), f)?;
    }
    Ok(())
}
///
/// Extract the embeded files in img image and make it as a lookup
pub fn pre_parse_get_embedded_files(
    arg: &str,
) -> Result<Vec<String>, ParseError> {
    // The returned nodes are created in the supplied Arena, and are bound by its lifetime.
    let arena = Arena::new();
    let option = get_comrak_options();
    let root = parse_document(&arena, arg, &option);
    let embed_files: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![]));

    pre_iter_nodes(root, embed_files.clone(), &|node| {
        let ref mut value = node.data.borrow_mut().value;
        let new_value = match value {
            &mut NodeValue::Image(ref link) => {
                let link_url = String::from_utf8(link.url.clone())?;
                if let Ok(mut embed_files) = embed_files.lock() {
                    embed_files.push(link_url);
                }
                value.clone()
            }
            _ => value.clone(),
        };
        *value = new_value;
        Ok(())
    })?;
    let embedded = match embed_files.lock() {
        Ok(files) => Ok((*files).to_owned()),
        Err(_e) => Err(ParseError::EmbedFileLockError),
    };
    embedded
}

fn parse_via_comrak(
    arg: &str,
    embed_files: &Option<BTreeMap<String, Vec<u8>>>,
    settings: &Settings,
) -> Result<Html, ParseError> {
    // The returned nodes are created in the supplied Arena, and are bound by its lifetime.
    let arena = Arena::new();
    let option = get_comrak_options();
    let title: Arc<Mutex<Option<String>>> = Arc::new(Mutex::new(None));
    let is_heading: Arc<Mutex<bool>> = Arc::new(Mutex::new(false));
    let root = parse_document(&arena, arg, &option);

    iter_nodes(root, is_heading.clone(), title.clone(), &|node| {
        let ref mut value = node.data.borrow_mut().value;
        let new_value = match value {
            &mut NodeValue::CodeBlock(ref codeblock) => {
                let codeblock_info =
                    String::from_utf8(codeblock.info.to_owned())
                        .expect("error converting to string");
                let codeblock_literal =
                    String::from_utf8(codeblock.literal.to_owned())
                        .expect("error converting to string");
                if let Ok(out) = plugins::plugin_executor(
                    &codeblock_info,
                    &codeblock_literal,
                ) {
                    NodeValue::HtmlBlock(NodeHtmlBlock {
                        literal: out.into_bytes(),
                        block_type: 0,
                    })
                } else if let Some(code_block_html) =
                    format_source_code(&codeblock_info, &codeblock_literal)
                {
                    code_block_html
                } else {
                    value.clone()
                }
            }
            &mut NodeValue::Link(ref nodelink) => {
                if let Ok(url) = String::from_utf8(nodelink.url.clone()) {
                    if let Some(ref base_dir) = settings.base_dir {
                        let url1 = UrlPath::new(&url);
                        let url2 = url1.normalize();
                        let url3 = if url1.is_external() {
                            url2
                        } else if url1.is_absolute() {
                            url2
                        } else {
                            format!("{}/{}", base_dir, url)
                        };
                        let url4 = UrlPath::new(&url3);
                        let url5 = url4.normalize();
                        let url6 = if url4.is_external()
                            && !url4.is_extension("md")
                            && settings.link_non_md_external
                        {
                            // leave as it
                            url5
                        } else {
                            format!("/#{}", url5)
                        };
                        log::info!("url6: {}", url6);
                        let mut new_nodelink = nodelink.clone();
                        new_nodelink.url = url6.into_bytes();
                        NodeValue::Link(new_nodelink)
                    } else {
                        value.clone()
                    }
                } else {
                    value.clone()
                }
            }
            &mut NodeValue::Heading(ref heading) => {
                if heading.level == 1 {
                    if let Ok(mut is_heading) = is_heading.lock() {
                        *is_heading = true;
                    }
                }
                value.clone()
            }
            &mut NodeValue::Text(ref text) => {
                if let Ok(is_heading) = is_heading.lock() {
                    if *is_heading {
                        let txt = String::from_utf8(text.to_owned())
                            .expect("Unable to convert to string");
                        if let Ok(mut title) = title.lock() {
                            if title.is_none() {
                                // only when unset
                                *title = Some(txt.to_string());
                            }
                        }
                    }
                }
                value.clone()
            }
            &mut NodeValue::Image(ref link) => {
                let link_url = String::from_utf8(link.url.clone())
                    .expect("unable to convert to string");
                match plugins::embed_handler(&link_url, embed_files) {
                    Ok(html) => NodeValue::HtmlBlock(NodeHtmlBlock {
                        literal: html.into_bytes(),
                        block_type: 0,
                    }),
                    Err(e) => {
                        log::error!("error: {:#?}", e);
                        value.clone()
                    }
                }
            }
            _ => value.clone(),
        };
        *value = new_value;
        Ok(())
    })?;

    let mut html = vec![];

    if let Ok(()) = format_html(root, &option, &mut html) {
        let render_html = String::from_utf8(html)?;
        let title = if let Ok(got) = title.lock() {
            if let Some(ref got) = *got {
                Some(got.to_string())
            } else {
                None
            }
        } else {
            None
        };
        Ok(Html {
            title,
            content: render_html,
        })
    } else {
        Err(ParseError::MdParseError)
    }
}

fn format_source_code(lang: &str, literal: &str) -> Option<NodeValue> {
    let lang_name = match lang {
        "rust" => "Rust",
        _ => "text",
    };

    let ss = SyntaxSet::load_defaults_newlines();
    let ts = ThemeSet::load_defaults();
    let theme = &ts.themes["base16-ocean.light"];
    let _c = theme.settings.background.unwrap_or(Color::WHITE);

    if let Some(syntax) = ss.find_syntax_by_name(lang_name) {
        let html = highlighted_html_for_string(literal, &ss, &syntax, theme);
        Some(NodeValue::HtmlBlock(NodeHtmlBlock {
            literal: html.into_bytes(),
            block_type: 0,
        }))
    } else {
        None
    }
}
<|endoftext|>


<commit_before>use crate::{
    consumer::Consumer,
    message::{BasicGetMessage, Delivery},
    pinky_swear::Pinky,
    queue::QueueState,
    types::ShortString,
    BasicProperties, Error, Result,
};
use parking_lot::Mutex;
use std::{collections::HashMap, sync::Arc};

#[derive(Clone, Debug, Default)]
pub(crate) struct Queues {
    queues: Arc<Mutex<HashMap<ShortString, QueueState>>>,
}

impl Queues {
    pub(crate) fn register(&self, queue: QueueState) {
        self.queues.lock().insert(queue.name(), queue);
    }

    pub(crate) fn deregister(&self, queue: &str) {
        self.queues.lock().remove(queue);
    }

    pub(crate) fn register_consumer(
        &self,
        queue: &str,
        consumer_tag: ShortString,
        consumer: Consumer,
    ) {
        if let Some(queue) = self.queues.lock().get_mut(queue) {
            queue.register_consumer(consumer_tag, consumer);
        }
    }

    pub(crate) fn deregister_consumer(&self, consumer_tag: &str) -> Result<()> {
        self.queues
            .lock()
            .values_mut()
            .map(|queue| queue.deregister_consumer(consumer_tag))
            .fold(Ok(()), Result::and)
    }

    pub(crate) fn drop_prefetched_messages(&self) -> Result<()> {
        self.queues
            .lock()
            .values_mut()
            .map(QueueState::drop_prefetched_messages)
            .fold(Ok(()), Result::and)
    }

    pub(crate) fn cancel_consumers(&self) -> Result<()> {
        self.queues
            .lock()
            .values_mut()
            .map(QueueState::cancel_consumers)
            .fold(Ok(()), Result::and)
    }

    pub(crate) fn error_consumers(&self, error: Error) -> Result<()> {
        self.queues
            .lock()
            .values_mut()
            .map(|queue| queue.error_consumers(error.clone()))
            .fold(Ok(()), Result::and)
    }

    pub(crate) fn start_consumer_delivery(
        &self,
        consumer_tag: &str,
        message: Delivery,
    ) -> Option<ShortString> {
        for queue in self.queues.lock().values_mut() {
            if let Some(consumer) = queue.get_consumer(consumer_tag) {
                consumer.start_new_delivery(message);
                return Some(queue.name());
            }
        }
        None
    }

    pub(crate) fn start_basic_get_delivery(
        &self,
        queue: &str,
        message: BasicGetMessage,
        pinky: Pinky<Result<Option<BasicGetMessage>>>,
    ) {
        if let Some(queue) = self.queues.lock().get_mut(queue) {
            queue.start_new_delivery(message, pinky);
        }
    }

    pub(crate) fn handle_content_header_frame(
        &self,
        queue: &str,
        consumer_tag: Option<ShortString>,
        size: u64,
        properties: BasicProperties,
    ) -> Result<()> {
        if let Some(queue) = self.queues.lock().get_mut(queue) {
            match consumer_tag {
                Some(consumer_tag) => {
                    if let Some(consumer) = queue.get_consumer(&consumer_tag) {
                        consumer.set_delivery_properties(properties);
                        if size == 0 {
                            consumer.new_delivery_complete()?;
                        }
                    }
                }
                None => {
                    queue.set_delivery_properties(properties);
                    if size == 0 {
                        queue.new_delivery_complete();
                    }
                }
            }
        }
        Ok(())
    }

    pub(crate) fn handle_body_frame(
        &self,
        queue: &str,
        consumer_tag: Option<ShortString>,
        remaining_size: usize,
        payload_size: usize,
        payload: Vec<u8>,
    ) -> Result<()> {
        if let Some(queue) = self.queues.lock().get_mut(queue) {
            match consumer_tag {
                Some(consumer_tag) => {
                    if let Some(consumer) = queue.get_consumer(&consumer_tag) {
                        consumer.receive_delivery_content(payload);
                        if remaining_size == payload_size {
                            consumer.new_delivery_complete()?;
                        }
                    }
                }
                None => {
                    queue.receive_delivery_content(payload);
                    if remaining_size == payload_size {
                        queue.new_delivery_complete();
                    }
                }
            }
        }
        Ok(())
    }
}
<commit_msg>queues: fix some action when we didn't declare the queue locally<commit_after>use crate::{
    consumer::Consumer,
    message::{BasicGetMessage, Delivery},
    pinky_swear::Pinky,
    queue::{Queue, QueueState},
    types::ShortString,
    BasicProperties, Error, Result,
};
use parking_lot::Mutex;
use std::{collections::HashMap, sync::Arc};

#[derive(Clone, Debug, Default)]
pub(crate) struct Queues {
    queues: Arc<Mutex<HashMap<ShortString, QueueState>>>,
}

impl Queues {
    pub(crate) fn register(&self, queue: QueueState) {
        self.queues.lock().insert(queue.name(), queue);
    }

    pub(crate) fn deregister(&self, queue: &str) {
        self.queues.lock().remove(queue);
    }

    fn with_queue<F: FnOnce(&mut QueueState) -> Result<()>>(&self, queue: &str, f: F) -> Result<()> {
        // FIXME: drop into(), which trait is used by the entry API?
        f(self.queues.lock().entry(queue.into()).or_insert_with(|| Queue::new(queue.into(), 0, 0).into()))
    }

    pub(crate) fn register_consumer(
        &self,
        queue: &str,
        consumer_tag: ShortString,
        consumer: Consumer,
    ) {
        self.with_queue(queue, |queue| {
            queue.register_consumer(consumer_tag, consumer);
            Ok(())
        }).expect("register_consumer cannot fail");
    }

    pub(crate) fn deregister_consumer(&self, consumer_tag: &str) -> Result<()> {
        self.queues
            .lock()
            .values_mut()
            .map(|queue| queue.deregister_consumer(consumer_tag))
            .fold(Ok(()), Result::and)
    }

    pub(crate) fn drop_prefetched_messages(&self) -> Result<()> {
        self.queues
            .lock()
            .values_mut()
            .map(QueueState::drop_prefetched_messages)
            .fold(Ok(()), Result::and)
    }

    pub(crate) fn cancel_consumers(&self) -> Result<()> {
        self.queues
            .lock()
            .values_mut()
            .map(QueueState::cancel_consumers)
            .fold(Ok(()), Result::and)
    }

    pub(crate) fn error_consumers(&self, error: Error) -> Result<()> {
        self.queues
            .lock()
            .values_mut()
            .map(|queue| queue.error_consumers(error.clone()))
            .fold(Ok(()), Result::and)
    }

    pub(crate) fn start_consumer_delivery(
        &self,
        consumer_tag: &str,
        message: Delivery,
    ) -> Option<ShortString> {
        for queue in self.queues.lock().values_mut() {
            if let Some(consumer) = queue.get_consumer(consumer_tag) {
                consumer.start_new_delivery(message);
                return Some(queue.name());
            }
        }
        None
    }

    pub(crate) fn start_basic_get_delivery(
        &self,
        queue: &str,
        message: BasicGetMessage,
        pinky: Pinky<Result<Option<BasicGetMessage>>>,
    ) {
        self.with_queue(queue, |queue| {
            queue.start_new_delivery(message, pinky);
            Ok(())
        }).expect("start_basic_get_delivery cannot fail");
    }

    pub(crate) fn handle_content_header_frame(
        &self,
        queue: &str,
        consumer_tag: Option<ShortString>,
        size: u64,
        properties: BasicProperties,
    ) -> Result<()> {
        self.with_queue(queue, |queue| {
            match consumer_tag {
                Some(consumer_tag) => {
                    if let Some(consumer) = queue.get_consumer(&consumer_tag) {
                        consumer.set_delivery_properties(properties);
                        if size == 0 {
                            consumer.new_delivery_complete()?;
                        }
                    }
                }
                None => {
                    queue.set_delivery_properties(properties);
                    if size == 0 {
                        queue.new_delivery_complete();
                    }
                }
            }
            Ok(())
        })
    }

    pub(crate) fn handle_body_frame(
        &self,
        queue: &str,
        consumer_tag: Option<ShortString>,
        remaining_size: usize,
        payload_size: usize,
        payload: Vec<u8>,
    ) -> Result<()> {
        self.with_queue(queue, |queue| {
            match consumer_tag {
                Some(consumer_tag) => {
                    if let Some(consumer) = queue.get_consumer(&consumer_tag) {
                        consumer.receive_delivery_content(payload);
                        if remaining_size == payload_size {
                            consumer.new_delivery_complete()?;
                        }
                    }
                }
                None => {
                    queue.receive_delivery_content(payload);
                    if remaining_size == payload_size {
                        queue.new_delivery_complete();
                    }
                }
            }
            Ok(())
        })
    }
}
<|endoftext|>


<commit_before>//! Raster implementation.

use ::RasterMut;

/// Depth of a raster.
#[derive(Clone,Copy,Debug,Eq,PartialEq)]
pub enum RasterDepth {
    Depth8,
    Depth16,
}

impl<'a> RasterMut<'a> {
    /// Allocate a new raster for the given destination buffer slice.
    ///
    /// # Examples
    ///
    /// ```
    /// const IMG_W: usize = 320;
    /// const IMG_H: usize = 200;
    /// let mut buf = [0; 3 * IMG_W * IMG_H];
    ///
    /// bayer::RasterMut::new(
    ///         IMG_W, IMG_H, bayer::RasterDepth::Depth8,
    ///         &mut buf);
    /// ```
    pub fn new(w: usize, h: usize, depth: RasterDepth, buf: &'a mut [u8])
            -> Self {
        let bytes_per_pixel = depth.bytes_per_pixel();
        let stride = w.checked_mul(bytes_per_pixel).expect("overflow");
        Self::with_offset(0, 0, w, h, stride, depth, buf)
    }

    /// Allocate a new raster for the given destination buffer slice.
    /// Stride is in number of bytes.
    ///
    /// # Examples
    ///
    /// ```
    /// const IMG_W: usize = 320;
    /// const IMG_H: usize = 200;
    /// let mut buf = [0; 3 * IMG_W * IMG_H];
    ///
    /// bayer::RasterMut::with_offset(
    ///         0, 0, IMG_W, IMG_H, 3 * IMG_W, bayer::RasterDepth::Depth8,
    ///         &mut buf);
    /// ```
    pub fn with_offset(
            x: usize, y: usize, w: usize, h: usize, stride: usize,
            depth: RasterDepth, buf: &'a mut [u8])
            -> Self {
        let x1 = x.checked_add(w).expect("overflow");
        let y1 = y.checked_add(h).expect("overflow");
        let bytes_per_pixel = depth.bytes_per_pixel();
        assert!(x < x1 && x1.checked_mul(bytes_per_pixel).expect("overflow") <= stride && h > 0);
        assert!(stride.checked_mul(y1).expect("overflow") <= buf.len());
        assert_eq!(stride % bytes_per_pixel, 0);

        RasterMut {
            x: x,
            y: y,
            w: w,
            h: h,
            stride: stride,
            depth: depth,
            buf: buf,
        }
    }
}

impl RasterDepth {
    /// The number of bytes per pixel for a raster of the given depth.
    fn bytes_per_pixel(self) -> usize {
        match self {
            RasterDepth::Depth8 => 3,
            RasterDepth::Depth16 => 6,
        }
    }
}

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

    #[test]
    #[should_panic]
    fn test_raster_mut_overflow() {
        let mut buf = [0; 1];
        let _ = RasterMut::new(
                ::std::usize::MAX, ::std::usize::MAX, RasterDepth::Depth8, &mut buf);
    }
}
<commit_msg>Add functions to borrow u8/u16 rows from Raster.<commit_after>//! Raster implementation.

use std::slice;

use ::RasterMut;

/// Depth of a raster.
#[derive(Clone,Copy,Debug,Eq,PartialEq)]
pub enum RasterDepth {
    Depth8,
    Depth16,
}

impl<'a> RasterMut<'a> {
    /// Allocate a new raster for the given destination buffer slice.
    ///
    /// # Examples
    ///
    /// ```
    /// const IMG_W: usize = 320;
    /// const IMG_H: usize = 200;
    /// let mut buf = [0; 3 * IMG_W * IMG_H];
    ///
    /// bayer::RasterMut::new(
    ///         IMG_W, IMG_H, bayer::RasterDepth::Depth8,
    ///         &mut buf);
    /// ```
    pub fn new(w: usize, h: usize, depth: RasterDepth, buf: &'a mut [u8])
            -> Self {
        let bytes_per_pixel = depth.bytes_per_pixel();
        let stride = w.checked_mul(bytes_per_pixel).expect("overflow");
        Self::with_offset(0, 0, w, h, stride, depth, buf)
    }

    /// Allocate a new raster for the given destination buffer slice.
    /// Stride is in number of bytes.
    ///
    /// # Examples
    ///
    /// ```
    /// const IMG_W: usize = 320;
    /// const IMG_H: usize = 200;
    /// let mut buf = [0; 3 * IMG_W * IMG_H];
    ///
    /// bayer::RasterMut::with_offset(
    ///         0, 0, IMG_W, IMG_H, 3 * IMG_W, bayer::RasterDepth::Depth8,
    ///         &mut buf);
    /// ```
    pub fn with_offset(
            x: usize, y: usize, w: usize, h: usize, stride: usize,
            depth: RasterDepth, buf: &'a mut [u8])
            -> Self {
        let x1 = x.checked_add(w).expect("overflow");
        let y1 = y.checked_add(h).expect("overflow");
        let bytes_per_pixel = depth.bytes_per_pixel();
        assert!(x < x1 && x1.checked_mul(bytes_per_pixel).expect("overflow") <= stride && h > 0);
        assert!(stride.checked_mul(y1).expect("overflow") <= buf.len());
        assert_eq!(stride % bytes_per_pixel, 0);

        RasterMut {
            x: x,
            y: y,
            w: w,
            h: h,
            stride: stride,
            depth: depth,
            buf: buf,
        }
    }

    /// Borrow a mutable u8 row slice.
    ///
    /// # Panics
    ///
    /// Panics if the raster is not 8-bpp.
    pub fn borrow_row_u8_mut(&mut self, y: usize)
            -> &mut [u8] {
        assert!(self.depth == RasterDepth::Depth8);
        assert!(y < self.h);

        let bytes_per_pixel = 3;
        let start = self.stride * (self.y + y) + bytes_per_pixel * self.x;
        let end = start + bytes_per_pixel * self.w;
        &mut self.buf[start..end]
    }

    /// Borrow a mutable u16 row slice.
    ///
    /// # Panics
    ///
    /// Panics if the raster is not 16-bpp.
    pub fn borrow_row_u16_mut(&mut self, y: usize)
            -> &mut [u16] {
        assert!(self.depth == RasterDepth::Depth16);
        assert!(y < self.h);

        let bytes_per_pixel = 6;
        let start = self.stride * (self.y + y) + bytes_per_pixel * self.x;
        let end = start + bytes_per_pixel * self.w;
        let s = &mut self.buf[start..end];

        unsafe {
            slice::from_raw_parts_mut(s.as_mut_ptr() as *mut u16, 3 * self.w)
        }
    }
}

impl RasterDepth {
    /// The number of bytes per pixel for a raster of the given depth.
    fn bytes_per_pixel(self) -> usize {
        match self {
            RasterDepth::Depth8 => 3,
            RasterDepth::Depth16 => 6,
        }
    }
}

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

    #[test]
    #[should_panic]
    fn test_raster_mut_overflow() {
        let mut buf = [0; 1];
        let _ = RasterMut::new(
                ::std::usize::MAX, ::std::usize::MAX, RasterDepth::Depth8, &mut buf);
    }

    #[test]
    fn test_borrow_row_u16_mut() {
        let expected = [
            0x00,0x00, 0x01,0x01, 0x02,0x02,
            0x03,0x03, 0x04,0x04, 0x05,0x05,
            0x06,0x06, 0x07,0x07, 0x08,0x08,
            0x09,0x09, 0x0A,0x0A, 0x0B,0x0B ];

        const IMG_W: usize = 4;
        const IMG_H: usize = 1;
        let mut buf = [0u8; 6 * IMG_W * IMG_H];

        {
            let mut dst = RasterMut::new(
                    IMG_W, IMG_H, RasterDepth::Depth16, &mut buf);
            let row = dst.borrow_row_u16_mut(0);

            for (i, elt) in row.iter_mut().enumerate() {
                // Work around different endians.
                let i = i as u16;
                *elt = (i << 8) | i;
            }
        }

        assert_eq!(&buf[0..6 * IMG_W * IMG_H], &expected[..]);
    }
}
<|endoftext|>


<commit_before>extern crate serialize;

use std::io::{File, Open, Append, Read, ReadWrite};
use std::io::fs::PathExtensions;
use std::io::{BufferedReader, BufferedWriter};
use std::path::BytesContainer;
use self::serialize::base64::{STANDARD, FromBase64, ToBase64};

pub type ReaderResult<T, E> = Result<T, E>;

pub struct Reader {

    path: Path,

    read_buffer: BufferedReader<File>,

    write_buffer: BufferedWriter<File>,

}

pub trait ReaderFile {

    fn open(&self) -> Box<File>;

    fn insert_string(&mut self, String);

    fn encode_record(&self, String) -> String;

    fn decode_record(&self, String) -> String; //TODO Maybe change this to JSON later?

}

impl Reader {

    pub fn new(apath: Path) -> Reader {
        Reader {
            path: {
                if !apath.exists() { File::create(&apath.clone()); }
                apath.clone()
            },
            read_buffer: {
                match File::open_mode(&apath.clone(), Open, Read) {
                    Ok(file)    => { BufferedReader::new(file) },
                    Err(..)     => { panic!("Failed to create a read buffer to file path."); }
                }
            },
            write_buffer: {
                match File::open_mode(&apath.clone(), Append, ReadWrite) {
                    Ok(file)    => { BufferedWriter::new(file) },
                    Err(..)     => { panic!("Failed to create a write buffer to file path."); }
                }
            }
        }
    }

    fn spill(&mut self) -> Vec<String> {
        let mut result: Vec<String> = Vec::new();
        for line_iter in self.read_buffer.lines() {
        //    println!("{}", line_iter.unwrap());
        //    let line = String::from_str(file.read_line().ok().expect("Nothing to read.").trim());
            result.push(line_iter.unwrap().trim().to_string());
        }
        return result;
    }

    fn insert_str(&mut self, item: &str) {
        self.write_buffer.write_line(item);
        self.write_buffer.flush();
    }

    fn insert(&mut self, item: &[u8]) {
        self.write_buffer.write(item);
        self.write_buffer.flush();
    }

}

impl ReaderFile for Reader {

    fn open(&self) -> Box<File> {
        match File::open_mode(&self.path, Open, ReadWrite) {
            Ok(file)    => box file,
            Err(..)     => { panic!("File {} couldn't be opened!", &self.path.display()); },
        }
    }

    fn insert_string(&mut self, item: String) {
        self.insert_str(item.as_slice());
    }

    fn encode_record(&self, item: String) -> String {
        item.container_as_bytes().to_base64(STANDARD)
    }

    fn decode_record(&self, item: String) -> String {
        match item.as_slice().from_base64() {
            Ok(vec) => {
                match String::from_utf8(vec) {
                    Ok(e)       => e,
                    Err(..)  => panic!("Invalid UTF-8 sequence."),
                }
            }
            Err(..) => panic!("Corrupt data, unable to decode."),
        }
    }

}

#[test]
fn test_open_file() {
    let reader = Reader::new(Path::new("tests/base-test.txt"));
}

#[test]
fn test_create_file() {
    use std::io::fs;
    use std::io::fs::PathExtensions;
    let path = Path::new("tests/base-test-created.txt");
    assert!(!path.exists());
    let reader = Reader::new(path.clone());
    assert!(path.exists());
}

#[test]
fn test_read_file() {
    // We should output the entire contents of the database file we open
    // into standard output.
    let mut reader = setup();
    let expected = vec!["10 11".to_string(), "20 21".to_string()];
    assert_eq!(expected, reader.spill());
}

#[test]
fn test_write_string_to_file() {
    let mut reader = setup();
    let expected = vec!["10 11".to_string(), "20 21".to_string(), "30 31".to_string()];
    reader.insert_string("30 31".to_string());
    assert_eq![expected, reader.spill()];
}

#[test]
fn test_write_str_to_file() {
    let mut reader = setup();
    let expected = vec!["10 11".to_string(), "20 21".to_string(), "30 31".to_string()];
    reader.insert_str("30 31");
    assert_eq![expected, reader.spill()];
}

#[test]
fn test_encode_string() {
    let reader = setup();
    let expected = "dGhpcyBpcyBhIGxpbmU=";
    let result = reader.encode_record("this is a line".to_string());
    assert_eq![expected, result];
}

#[test]
fn test_decode_string() {
    let reader = setup();
    let expected = "this is a line";
    let result = reader.decode_record("dGhpcyBpcyBhIGxpbmU=".to_string());
    assert_eq![expected, result];
}

#[allow(dead_code, unused_must_use)]
fn setup() -> Reader {
    use std::io::fs;

    let mut file = File::create(&Path::new("tests/base-test.txt")).ok().expect("fooo");
    file.write_str("10 11\n20 21\n");

    let p = Path::new("tests/base-test-created.txt");
    if p.exists() {
        fs::unlink(&p);
    }

    Reader::new(Path::new("tests/base-test.txt"))
}
<commit_msg>Added Record struct for resulting data in file<commit_after>extern crate serialize;

use std::io::{File, Open, Append, Read, ReadWrite};
use std::io::fs::PathExtensions;
use std::io::{BufferedReader, BufferedWriter};
use std::path::BytesContainer;
use self::serialize::base64::{STANDARD, FromBase64, ToBase64};

pub type ReaderResult<T, E> = Result<T, E>;

pub struct Reader {

    path: Path,

    read_buffer: BufferedReader<File>,

    write_buffer: BufferedWriter<File>,

}

struct Record {

    id: u64,

    payload: String,

    metadata: String,

}

pub trait ReaderFile {

    fn open(&self) -> Box<File>;

    fn insert_string(&mut self, String);

    fn encode_record(&self, String) -> String;

    fn decode_record(&self, String) -> String; //TODO Maybe change this to JSON later?

}

impl Reader {

    pub fn new(apath: Path) -> Reader {
        Reader {
            path: {
                if !apath.exists() { File::create(&apath.clone()); }
                apath.clone()
            },
            read_buffer: {
                match File::open_mode(&apath.clone(), Open, Read) {
                    Ok(file)    => { BufferedReader::new(file) },
                    Err(..)     => { panic!("Failed to create a read buffer to file path."); }
                }
            },
            write_buffer: {
                match File::open_mode(&apath.clone(), Append, ReadWrite) {
                    Ok(file)    => { BufferedWriter::new(file) },
                    Err(..)     => { panic!("Failed to create a write buffer to file path."); }
                }
            }
        }
    }

    fn spill(&mut self) -> Vec<String> {
        let mut result: Vec<String> = Vec::new();
        for line_iter in self.read_buffer.lines() {
        //    println!("{}", line_iter.unwrap());
        //    let line = String::from_str(file.read_line().ok().expect("Nothing to read.").trim());
            result.push(line_iter.unwrap().trim().to_string());
        }
        return result;
    }

    fn insert_str(&mut self, item: &str) {
        self.write_buffer.write_line(item);
        self.write_buffer.flush();
    }

    fn insert(&mut self, item: &[u8]) {
        self.write_buffer.write(item);
        self.write_buffer.flush();
    }

}

impl ReaderFile for Reader {

    fn open(&self) -> Box<File> {
        match File::open_mode(&self.path, Open, ReadWrite) {
            Ok(file)    => box file,
            Err(..)     => { panic!("File {} couldn't be opened!", &self.path.display()); },
        }
    }

    fn insert_string(&mut self, item: String) {
        self.insert_str(item.as_slice());
    }

    fn encode_record(&self, item: String) -> String {
        item.container_as_bytes().to_base64(STANDARD)
    }

    fn decode_record(&self, item: String) -> String {
        match item.as_slice().from_base64() {
            Ok(vec) => {
                match String::from_utf8(vec) {
                    Ok(e)       => e,
                    Err(..)  => panic!("Invalid UTF-8 sequence."),
                }
            }
            Err(..) => panic!("Corrupt data, unable to decode."),
        }
    }

}

#[test]
fn test_open_file() {
    let reader = Reader::new(Path::new("tests/base-test.txt"));
}

#[test]
fn test_create_file() {
    use std::io::fs;
    use std::io::fs::PathExtensions;
    let path = Path::new("tests/base-test-created.txt");
    assert!(!path.exists());
    let reader = Reader::new(path.clone());
    assert!(path.exists());
}

#[test]
fn test_read_file() {
    // We should output the entire contents of the database file we open
    // into standard output.
    let mut reader = setup();
    let expected = vec!["10 11".to_string(), "20 21".to_string()];
    assert_eq!(expected, reader.spill());
}

#[test]
fn test_write_string_to_file() {
    let mut reader = setup();
    let expected = vec!["10 11".to_string(), "20 21".to_string(), "30 31".to_string()];
    reader.insert_string("30 31".to_string());
    assert_eq![expected, reader.spill()];
}

#[test]
fn test_write_str_to_file() {
    let mut reader = setup();
    let expected = vec!["10 11".to_string(), "20 21".to_string(), "30 31".to_string()];
    reader.insert_str("30 31");
    assert_eq![expected, reader.spill()];
}

#[test]
fn test_encode_string() {
    let reader = setup();
    let expected = "dGhpcyBpcyBhIGxpbmU=";
    let result = reader.encode_record("this is a line".to_string());
    assert_eq![expected, result];
}

#[test]
fn test_decode_string() {
    let reader = setup();
    let expected = "this is a line";
    let result = reader.decode_record("dGhpcyBpcyBhIGxpbmU=".to_string());
    assert_eq![expected, result];
}

#[allow(dead_code, unused_must_use)]
fn setup() -> Reader {
    use std::io::fs;

    let mut file = File::create(&Path::new("tests/base-test.txt")).ok().expect("fooo");
    file.write_str("10 11\n20 21\n");

    let p = Path::new("tests/base-test-created.txt");
    if p.exists() {
        fs::unlink(&p);
    }

    Reader::new(Path::new("tests/base-test.txt"))
}
<|endoftext|>


<commit_before>use std::hash::{Hash, Hasher, SipHasher};
use std::collections::HashSet;

pub trait SearchSpace {
    type State: Ord + Hash + Eq;
    type Action;
    type Iterator: Iterator<Item=Self::Action>;

    fn actions(&self, state: &Self::State) -> Self::Iterator;
    fn next_state(&self, state: &Self::State, action: &Self::Action) -> Self::State;
    fn is_goal(&self, state: &Self::State) -> bool;
}

pub fn depth_first_search<S>(space: &S, start: S::State) -> Option<Vec<S::Action>>
where S: SearchSpace {
    let mut path = Vec::new();
    let actions = space.actions(&start);
    let mut frontier = vec![(start, actions)];
    let mut visited = HashSet::new();

    loop {
        let result = match frontier.last_mut() {
            None => return None,
            Some(&mut (ref mut state, ref mut actions)) => {
                if space.is_goal(&state) {
                    return Some(path);
                }
                match actions.next() {
                    None => None,
                    Some(action) => {
                        let next_state = space.next_state(&state, &action);

                        let mut hasher = SipHasher::new();
                        next_state.hash(&mut hasher);
                        let hash = hasher.finish();
                        if visited.contains(&hash) {
                            continue;
                        }
                        visited.insert(hash);

                        let next_actions = space.actions(&next_state);
                        path.push(action);
                        Some((next_state, next_actions))
                    }
                }
            }
        };
        match result {
            None => {
                path.pop();
                frontier.pop();
            },
            Some((next_state, next_actions)) => {
                frontier.push((next_state, next_actions));
            },
        };
    }
}

#[cfg(test)]
pub mod tests {
    use std::vec::IntoIter;
    use super::*;

    #[test]
    pub fn test_depth_first_search() {
        struct S {
            goal: i32,
        }

        #[derive(Debug, Clone, PartialEq)]
        enum Direction {
            Left,
            Right
        }

        impl SearchSpace for S {
            type State = i32;
            type Action = Direction;
            type Iterator = IntoIter<Self::Action>;

            fn actions(&self, state: &i32) -> Self::Iterator {
                if *state == 0 || *state == 1 {
                    vec![Direction::Left, Direction::Right].into_iter()
                } else if *state == 2 {
                    vec![Direction::Left].into_iter()
                }
                else {
                    vec![].into_iter()
                }
            }

            fn next_state(&self, state: &i32, action: &Direction) -> i32 {
                match *state {
                    0 => match *action {
                        Direction::Left => 1,
                        Direction::Right => 2,
                    },
                    1 => match *action {
                        Direction::Left => 3,
                        Direction::Right => 4,
                    },
                    2 => 2,
                    node => node
                }
            }

            fn is_goal(&self, state: &i32) -> bool {
                return self.goal == *state
            }
        }

        impl S {
            fn solve(start: i32, goal: i32) -> Option<Vec<Direction>> {
                let space = S { goal: goal };
                depth_first_search(&space, start)
            }
        }

        assert_eq!(S::solve(0, 0).unwrap(), vec![]);
        assert_eq!(S::solve(0, 1).unwrap(), vec![Direction::Left]);
        assert_eq!(S::solve(0, 2).unwrap(), vec![Direction::Right]);
        assert_eq!(S::solve(0, 3).unwrap(), vec![Direction::Left, Direction::Left]);
        assert_eq!(S::solve(0, 4).unwrap(), vec![Direction::Left, Direction::Right]);
        assert_eq!(S::solve(2, 2).unwrap(), vec![]);
        assert!(S::solve(2, 0).is_none());
        assert!(S::solve(5, 0).is_none());
    }
}
<commit_msg>Remove Ord and Eq bounds from State<commit_after>use std::hash::{Hash, Hasher, SipHasher};
use std::collections::HashSet;

pub trait SearchSpace {
    type State: Hash;
    type Action;
    type Iterator: Iterator<Item=Self::Action>;

    fn actions(&self, state: &Self::State) -> Self::Iterator;
    fn next_state(&self, state: &Self::State, action: &Self::Action) -> Self::State;
    fn is_goal(&self, state: &Self::State) -> bool;
}

pub fn depth_first_search<S>(space: &S, start: S::State) -> Option<Vec<S::Action>>
where S: SearchSpace {
    let mut path = Vec::new();
    let actions = space.actions(&start);
    let mut frontier = vec![(start, actions)];
    let mut visited = HashSet::new();

    loop {
        let result = match frontier.last_mut() {
            None => return None,
            Some(&mut (ref mut state, ref mut actions)) => {
                if space.is_goal(&state) {
                    return Some(path);
                }
                match actions.next() {
                    None => None,
                    Some(action) => {
                        let next_state = space.next_state(&state, &action);

                        let mut hasher = SipHasher::new();
                        next_state.hash(&mut hasher);
                        let hash = hasher.finish();
                        if visited.contains(&hash) {
                            continue;
                        }
                        visited.insert(hash);

                        let next_actions = space.actions(&next_state);
                        path.push(action);
                        Some((next_state, next_actions))
                    }
                }
            }
        };
        match result {
            None => {
                path.pop();
                frontier.pop();
            },
            Some((next_state, next_actions)) => {
                frontier.push((next_state, next_actions));
            },
        };
    }
}

#[cfg(test)]
pub mod tests {
    use std::vec::IntoIter;
    use super::*;

    #[test]
    pub fn test_depth_first_search() {
        struct S {
            goal: i32,
        }

        #[derive(Debug, Clone, PartialEq)]
        enum Direction {
            Left,
            Right
        }

        impl SearchSpace for S {
            type State = i32;
            type Action = Direction;
            type Iterator = IntoIter<Self::Action>;

            fn actions(&self, state: &i32) -> Self::Iterator {
                if *state == 0 || *state == 1 {
                    vec![Direction::Left, Direction::Right].into_iter()
                } else if *state == 2 {
                    vec![Direction::Left].into_iter()
                }
                else {
                    vec![].into_iter()
                }
            }

            fn next_state(&self, state: &i32, action: &Direction) -> i32 {
                match *state {
                    0 => match *action {
                        Direction::Left => 1,
                        Direction::Right => 2,
                    },
                    1 => match *action {
                        Direction::Left => 3,
                        Direction::Right => 4,
                    },
                    2 => 2,
                    node => node
                }
            }

            fn is_goal(&self, state: &i32) -> bool {
                return self.goal == *state
            }
        }

        impl S {
            fn solve(start: i32, goal: i32) -> Option<Vec<Direction>> {
                let space = S { goal: goal };
                depth_first_search(&space, start)
            }
        }

        assert_eq!(S::solve(0, 0).unwrap(), vec![]);
        assert_eq!(S::solve(0, 1).unwrap(), vec![Direction::Left]);
        assert_eq!(S::solve(0, 2).unwrap(), vec![Direction::Right]);
        assert_eq!(S::solve(0, 3).unwrap(), vec![Direction::Left, Direction::Left]);
        assert_eq!(S::solve(0, 4).unwrap(), vec![Direction::Left, Direction::Right]);
        assert_eq!(S::solve(2, 2).unwrap(), vec![]);
        assert!(S::solve(2, 0).is_none());
        assert!(S::solve(5, 0).is_none());
    }
}
<|endoftext|>


<commit_before>use std::thread;
use std::thread::JoinHandle;
use std::path::Path;

use websocket::{WebSocketStream, Server};
use websocket::Message as WebMessage;
use websocket::Sender as WebSender;
use websocket::client::Sender as WebClientSender;
use websocket::Receiver as WebReceiver;
use websocket::message::Type as WebMessageType;
use websocket::server::Connection;
use websocket::header::WebSocketProtocol;

use git2::Repository;
use git2::ObjectType;

use payload;
use State;

extern crate fsevent;
use self::fsevent::Event as FsEvent;
use std::sync::mpsc::channel;
use std::sync::mpsc::Sender;
use std::sync::mpsc::Receiver;

use serde_xml as xml;

#[derive(Debug)]
enum NotifierMessage<'a> {
    WebMessage(WebMessage<'a>),
    FsEvent(FsEvent)
}

pub fn start() {
    let server = Server::bind("127.0.0.1:2794").unwrap();
    thread::spawn(move || {
        for connection in server {
            thread::spawn(move || connect(connection.unwrap()));
        }
    });
}

fn connect(connection: Connection<WebSocketStream, WebSocketStream>) {
    let request = connection.read_request().unwrap();
    let headers = request.headers.clone();
    request.validate().unwrap();
    let mut response = request.accept();
    println!("Connected");

    if let Some(&WebSocketProtocol(ref protocols)) = headers.get() {
        if protocols.contains(&("rust-websocket".to_string())) {
            response.headers.set(WebSocketProtocol(vec!["superconductor".to_string()]));
        }
    }

    let mut client = response.send().unwrap();
    let message = WebMessage::text(payload::generate(None));
    client.send_message(&message).unwrap();

    let (tx, rx) = channel::<NotifierMessage>();
    let (mut sender, mut receiver) = client.split();
    let notifier = thread::spawn(move || start_notifier(rx, sender));
    let txc = tx.clone();
    let monitor = thread::spawn(move || start_monitor(txc));
    for message in receiver.incoming_messages() {
        let message: WebMessage = message.unwrap_or(WebMessage::close());
        match message.opcode {
            WebMessageType::Close => {
                tx.send(NotifierMessage::WebMessage(message));
                break;
            },
            _ => tx.send(NotifierMessage::WebMessage(message))
        };
    }
    monitor.join();
    notifier.join();
}

fn start_monitor(tx: Sender<NotifierMessage>) {
    let (ftx, rx) = channel();
    let observer = thread::spawn(move || {
        println!("Monitoring");
        let fsevent = fsevent::FsEvent::new(ftx);
        fsevent.append_path(".");
        fsevent.observe();
    });
    loop {
        let event = rx.recv().unwrap();
        tx.send(NotifierMessage::FsEvent(event));
    }
    observer.join();
}

fn start_notifier(rx: Receiver<NotifierMessage>, mut sender: WebClientSender<WebSocketStream>) {
    let mut last_state: Option<State> = None;
    loop {
        let value = rx.recv().unwrap();
        match value {
            NotifierMessage::WebMessage(message) => {
                match message.opcode {
                    WebMessageType::Close => {
                        break;
                    },
                    WebMessageType::Ping => {
                        let message = WebMessage::pong(message.payload);
                        sender.send_message(&message).unwrap();
                    },
                    _ => {
                        let payload = String::from_utf8_lossy(message.payload.as_ref());
                        println!("{:?}", payload);
                        let state: State = xml::from_str(&payload).unwrap();
                        last_state = Some(state.clone());
                        println!("{:?}", state);

                        let repo = Repository::discover(".").unwrap();
                        let head = repo.head().unwrap().peel(ObjectType::Commit).unwrap();
                        let mut index = repo.index().unwrap();

                        let to_remove = index.iter().fold(vec![], |mut acc, entry| {
                            let entry_path = String::from_utf8_lossy(entry.path.as_ref());
                            match state.include.iter().find(|i| i.as_ref() == entry_path) {
                                None => acc.push(entry_path.into_owned()),
                                _ => {}
                            };
                            acc
                        });

                        repo.reset_default(Some(&head), to_remove.iter()).unwrap();
                        for change in state.clone().include {
                            let path = Path::new(&change);
                            index.add_path(path).unwrap();
                        }
                        index.write().unwrap();

                        if let Some(event) = state.save_update.clone() {
                            let author = repo.signature().unwrap();
                            index.read(false);
                            let tree_oid = index.write_tree().unwrap();
                            let tree = repo.find_tree(tree_oid).unwrap();
                            repo.commit(Some("HEAD"), &author, &author, &state.message, &tree, &[&head.as_commit().unwrap()]);
                            let message = WebMessage::text(payload::generate(None));
                            sender.send_message(&message).unwrap();
                        } else {
                            let message = WebMessage::text(payload::generate(Some(state)));
                            sender.send_message(&message).unwrap();
                        }
                    }
                }
            },
            NotifierMessage::FsEvent(event) => {
                let repo = Repository::discover(".").unwrap();
                let message = WebMessage::text(payload::generate(last_state.clone()));
                sender.send_message(&message).unwrap();
            }
        }
    }
}
<commit_msg>Commit should reset after submit<commit_after>use std::thread;
use std::thread::JoinHandle;
use std::path::Path;

use websocket::{WebSocketStream, Server};
use websocket::Message as WebMessage;
use websocket::Sender as WebSender;
use websocket::client::Sender as WebClientSender;
use websocket::Receiver as WebReceiver;
use websocket::message::Type as WebMessageType;
use websocket::server::Connection;
use websocket::header::WebSocketProtocol;

use git2::Repository;
use git2::ObjectType;

use payload;
use State;

extern crate fsevent;
use self::fsevent::Event as FsEvent;
use std::sync::mpsc::channel;
use std::sync::mpsc::Sender;
use std::sync::mpsc::Receiver;

use serde_xml as xml;

#[derive(Debug)]
enum NotifierMessage<'a> {
    WebMessage(WebMessage<'a>),
    FsEvent(FsEvent)
}

pub fn start() {
    let server = Server::bind("127.0.0.1:2794").unwrap();
    thread::spawn(move || {
        for connection in server {
            thread::spawn(move || connect(connection.unwrap()));
        }
    });
}

fn connect(connection: Connection<WebSocketStream, WebSocketStream>) {
    let request = connection.read_request().unwrap();
    let headers = request.headers.clone();
    request.validate().unwrap();
    let mut response = request.accept();
    println!("Connected");

    if let Some(&WebSocketProtocol(ref protocols)) = headers.get() {
        if protocols.contains(&("rust-websocket".to_string())) {
            response.headers.set(WebSocketProtocol(vec!["superconductor".to_string()]));
        }
    }

    let mut client = response.send().unwrap();
    let message = WebMessage::text(payload::generate(None));
    client.send_message(&message).unwrap();

    let (tx, rx) = channel::<NotifierMessage>();
    let (mut sender, mut receiver) = client.split();
    let notifier = thread::spawn(move || start_notifier(rx, sender));
    let txc = tx.clone();
    let monitor = thread::spawn(move || start_monitor(txc));
    for message in receiver.incoming_messages() {
        let message: WebMessage = message.unwrap_or(WebMessage::close());
        match message.opcode {
            WebMessageType::Close => {
                tx.send(NotifierMessage::WebMessage(message));
                break;
            },
            _ => tx.send(NotifierMessage::WebMessage(message))
        };
    }
    monitor.join();
    notifier.join();
}

fn start_monitor(tx: Sender<NotifierMessage>) {
    let (ftx, rx) = channel();
    let observer = thread::spawn(move || {
        println!("Monitoring");
        let fsevent = fsevent::FsEvent::new(ftx);
        fsevent.append_path(".");
        fsevent.observe();
    });
    loop {
        let event = rx.recv().unwrap();
        tx.send(NotifierMessage::FsEvent(event));
    }
    observer.join();
}

fn start_notifier(rx: Receiver<NotifierMessage>, mut sender: WebClientSender<WebSocketStream>) {
    let mut last_state: Option<State> = None;
    loop {
        let value = rx.recv().unwrap();
        match value {
            NotifierMessage::WebMessage(message) => {
                match message.opcode {
                    WebMessageType::Close => {
                        break;
                    },
                    WebMessageType::Ping => {
                        let message = WebMessage::pong(message.payload);
                        sender.send_message(&message).unwrap();
                    },
                    _ => {
                        let payload = String::from_utf8_lossy(message.payload.as_ref());
                        println!("{:?}", payload);
                        let state: State = xml::from_str(&payload).unwrap();
                        println!("{:?}", state);

                        let repo = Repository::discover(".").unwrap();
                        let head = repo.head().unwrap().peel(ObjectType::Commit).unwrap();
                        let mut index = repo.index().unwrap();

                        let to_remove = index.iter().fold(vec![], |mut acc, entry| {
                            let entry_path = String::from_utf8_lossy(entry.path.as_ref());
                            match state.include.iter().find(|i| i.as_ref() == entry_path) {
                                None => acc.push(entry_path.into_owned()),
                                _ => {}
                            };
                            acc
                        });

                        repo.reset_default(Some(&head), to_remove.iter()).unwrap();
                        for change in state.clone().include {
                            let path = Path::new(&change);
                            index.add_path(path).unwrap();
                        }
                        index.write().unwrap();

                        if let Some(event) = state.save_update.clone() {
                            let author = repo.signature().unwrap();
                            index.read(false);
                            let tree_oid = index.write_tree().unwrap();
                            let tree = repo.find_tree(tree_oid).unwrap();
                            repo.commit(Some("HEAD"), &author, &author, &state.message, &tree, &[&head.as_commit().unwrap()]);
                            let message = WebMessage::text(payload::generate(None));
                            sender.send_message(&message).unwrap();
                            last_state = None;
                        } else {
                            last_state = Some(state);
                        }
                        let message = WebMessage::text(payload::generate(last_state.clone()));
                        sender.send_message(&message).unwrap();
                    }
                }
            },
            NotifierMessage::FsEvent(event) => {
                let repo = Repository::discover(".").unwrap();
                let message = WebMessage::text(payload::generate(last_state.clone()));
                sender.send_message(&message).unwrap();
            }
        }
    }
}
<|endoftext|>