<commit_before>use std::rc::Rc;
use std::ops::Deref;

use expr::{Expr,Prim};
use env::Env;
use read::read;

fn f_foldl<F:Fn(&mut Env, Expr, &Expr) -> Expr>(mut env: &mut Env, f: &F, init: Expr, args: &Expr) -> Expr {
    let mut res = init;
    let mut head = args;
    let nil = &Expr::Nil;
    while head != nil {
        match head {
            &Expr::Cons(ref car, ref cdr) => {
                res = f(env, res, car);
                head = cdr;
            }
            _ => panic!("invalid argument {:?} to function", args.clone())
        }
    }
    res
}

fn f_reverse(mut env: &mut Env, args: &Expr) -> Expr {
    f_foldl(env, &|_, acc, x| Expr::Cons(Rc::new(x.clone()), Rc::new(acc)), Expr::Nil, args)
}

fn f_foldr<F:Fn(&mut Env, Expr, &Expr) -> Expr>(mut env: &mut Env, f: &F, init: Expr, args: &Expr) -> Expr {
    match args {
        &Expr::Nil => init,
        &Expr::Cons(ref car, ref cdr) => {
            let v = f_foldr(env, f, init, cdr);
            f(env, v, car)
        }
        _ => panic!("invalid argument {:?} to function", args)
    }
}

fn f_map<F:Fn(&mut Env, Expr) -> Expr>(mut env: &mut Env, f: &F, list: &Expr) -> Expr {
    f_foldr(env, &|env, acc, x| Expr::cons(f(env, x.clone()), acc)
                 , Expr::Nil, list)
}

fn f_iter<F:Fn(&mut Env, Expr)>(mut env: &mut Env, f: &F, list: &Expr) -> Expr {
    f_foldr(env, &|env, acc, x| {f(env,x.clone()); Expr::Nil}
                 , Expr::Nil, list)
}

// since rust's macro cannot treat binop, work around macro is needed.
macro_rules! expr {
    ($e:expr) => {
        $e
    }
}

macro_rules! def_arith_op {
    ($name: ident, $op: tt, $init: expr) => {
        fn $name(mut env: &mut Env, args: Expr) -> Expr {
            let (init, args) = match args {
                Expr::Cons(ref hd, ref tl) => match tl.deref() {
                    tl @ &Expr::Cons(_, _) => (hd.deref().clone(), tl.clone()),
                    tl => ($init, Expr::cons(hd.deref().clone(), tl.clone()))
                },
                args => ($init, args)
            };
            f_foldl(env, &|_, x, y| match (x, y) {
                (Expr::Int(x), &Expr::Int(y)) => Expr::Int(expr!(x $op y)),
                (x, y) => panic!("non int args {:?} and {:?} are given to $op", x, y)
            }, init, &args)

        }
    }
}

def_arith_op!(k_add, +, Expr::Int(0));
def_arith_op!(k_sub, -, Expr::Int(0));
def_arith_op!(k_mul, *, Expr::Int(1));
def_arith_op!(k_div, /, Expr::Int(1));

fn k_concat(mut env: &mut Env, args: Expr) -> Expr {
    f_foldl(env, &|_, acc, x| match (acc, x) {
        (Expr::Str(ref acc), &Expr::Str(ref x)) => {
            Expr::Str(format!("{}{}",acc, x))
        },
        (_, y) => panic!("non string args {:?} are given to concat", y)
    }
            , Expr::Str("".to_string()), &args)
}

fn k_funcall(mut env: &mut Env, args: Expr) -> Expr {
    match args {
        Expr::Cons(f, args) => funcall(env, f.deref(), args.deref().clone()),
        args => panic!("illeagal form of funcall {:?}", args)
    }
}

fn bind_names(mut env: &mut Env, params: Expr, args: Expr) {
    let mut phead = &params;
    let mut ahead = &args;
    let nil = &Expr::Nil;
    while phead != nil && ahead != nil {
        match (phead, ahead) {
            (&Expr::Cons(ref pcar, ref pcdr), &Expr::Cons(ref acar, ref acdr)) => {
                match pcar.deref().clone() {
                    Expr::Sym(ref name) => env.register(name.clone(), acar.deref().clone()),
                    pcar => panic!("illeagal form of params {:?}", pcar)
                };
                phead = pcdr.deref();
                ahead = acdr.deref();
            },
            _ => panic!("ileagal form of funcall")
        }
    }

}

fn funcall(mut env: &mut Env, f: &Expr, args: Expr) -> Expr {
    match f {
        &Expr::FLambda(ref prim) => match prim {
            &Prim::Add => k_add(env, args),
            &Prim::Sub => k_sub(env, args),
            &Prim::Mul => k_mul(env, args),
            &Prim::Div => k_div(env, args),
            &Prim::Funcall => k_funcall(env, args),
            &Prim::Concat => k_concat(env, args)
        },
        &Expr::Lambda(ref params, ref body) => {
            env.new_local();
            bind_names(env, params.deref().clone(), args);
            let ret = eval(env, body.deref().clone());
            env.end_local();
            ret
        },
        f => panic!("{:?} is not a function", f)
    }
}

fn k_quote(mut env: &mut Env, args: Expr) -> Expr {
    match args {
        Expr::Cons(ref car, ref nil) => car.deref().clone(),
        _ => unreachable!()
    }
}

fn k_feval(mut env: &mut Env, args: Expr) -> Expr {
    match args {
        Expr::Cons(ref car, ref nil) => feval(env, car.deref().clone()),
        _ => unreachable!()
    }
}

fn k_lambda(mut env: &mut Env, args: Expr) -> Expr {
    match args {
        Expr::Cons(params, body) => Expr::Lambda(params, Rc::new(Expr::Cons(Rc::new(Expr::Sym("progn".to_string())), body))),
        _ => unreachable!()
    }
}

fn k_progn(mut env: &mut Env, args: Expr) -> Expr {
    let mut head = &args;
    let nil = &Expr::Nil;
    let mut res = Expr::Nil;
    while head != nil {
        match head {
            &Expr::Cons(ref car, ref cdr) => {
                res = eval(env, car.deref().clone());
                head = cdr.deref();
            },
            _ => panic!("invalid form of progn or lambda")
        }
    };
    res
}

fn feval(mut env: &mut Env, expr: Expr) -> Expr {
    match expr {
        Expr::Sym(ref sym) => match &sym[..] {
            "+" => Expr::FLambda(Prim::Add),
            "-" => Expr::FLambda(Prim::Sub),
            "*" => Expr::FLambda(Prim::Mul),
            "/" => Expr::FLambda(Prim::Div),
            "concat" => Expr::FLambda(Prim::Concat),
            "funcall" => Expr::FLambda(Prim::Funcall),
            fun => match env.ffind(&fun.to_string()) {
                Some(f) => f.clone(),
                None => panic!("function {:?} not found", fun)
            }
        },
        Expr::Cons(ref op, ref rest) => {
            let op = op.deref();
            match op {
                &Expr::Sym(ref sym) => match &sym[..] {
                    "lambda" => k_lambda(env, rest.deref().clone()),
                    op => panic!("invalid expression '({:?} {:?})' found at function potision", op, rest)
                },
                op => panic!("invalid expression '({:?} {:?})' found at function potision", op, rest)
            }
        }
        Expr::Lambda(_, _) => expr,
        x => panic!("{:?} is not a function", x)
    }
}

fn eval(mut env: &mut Env, expr: Expr) -> Expr {
    match expr {
        Expr::Nil |
        Expr::EOF |
        Expr::Str(_) |
        Expr::Int(_) |
        Expr::Lambda(_, _) |
        Expr::FLambda(_) => expr,
        Expr::Sym(ref name) => match env.find(&name.to_string()) {
            Some(v) => v.clone(),
            None => panic!("variable {:?} not found", name)
        }
,
        Expr::Cons(ref car, ref cdr) => {
            let car = car.deref();
            let cdr = cdr.deref();
            match car {
                &Expr::Sym(ref sym) => match &sym[..] {
                    "quote" => k_quote(env, cdr.clone()),
                    "function" => k_feval(env, cdr.clone()),
                    "lambda" => k_lambda(env, cdr.clone()),
                    "progn" => k_progn(env, cdr.clone()),
                    _ => {
                        let f = feval(env, car.clone());
                        let arg = f_map(env, &|env, x| eval(env, x), cdr);
                        funcall(env, &f, arg)
                    }
                },
                car => {
                    let f = feval(env, car.clone());
                    let arg = f_map(env, &|env, x| eval(env, x), cdr);
                    funcall(env, &f, arg)
                }
            }
        }
    }
}

#[test]
fn test_atom(){
    assert!(eval(&mut Env::new(), read("1")) == (Expr::Int(1)));
    assert!(eval(&mut Env::new(), read("()")) == (Expr::Nil));
    assert!(eval(&mut Env::new(), read("")) == (Expr::EOF));
    assert!(eval(&mut Env::new(), read("\"string\"")) == (Expr::Str("string".to_string())));
}

#[test]
fn test_add(){
    assert!(eval(&mut Env::new(), read("(+)")) == (Expr::Int(0)));
    assert!(eval(&mut Env::new(), read("(+ 1)")) == (Expr::Int(1)));
    assert!(eval(&mut Env::new(), read("(+ 1 2)")) == (Expr::Int(3)));
    assert!(eval(&mut Env::new(), read("(+ 1 2 3)")) == (Expr::Int(6)));
}

#[test]
fn test_sub(){
    assert!(eval(&mut Env::new(), read("(-)")) == (Expr::Int(0)));
    assert!(eval(&mut Env::new(), read("(- 1)")) == (Expr::Int(-1)));
    assert!(eval(&mut Env::new(), read("(- 1 2)")) == (Expr::Int(-1)));
    assert!(eval(&mut Env::new(), read("(- 1 2 3)")) == (Expr::Int(-4)));
}

#[test]
fn test_mul(){
    assert!(eval(&mut Env::new(), read("(*)")) == (Expr::Int(1)));
    assert!(eval(&mut Env::new(), read("(* 1)")) == (Expr::Int(1)));
    assert!(eval(&mut Env::new(), read("(* 1 2)")) == (Expr::Int(2)));
    assert!(eval(&mut Env::new(), read("(* 1 2 3)")) == (Expr::Int(6)));
}

#[test]
fn test_div(){
    assert!(eval(&mut Env::new(), read("(/)")) == (Expr::Int(1)));
    assert!(eval(&mut Env::new(), read("(/ 1)")) == (Expr::Int(1)));
    assert!(eval(&mut Env::new(), read("(/ 3 2)")) == (Expr::Int(1)));
    assert!(eval(&mut Env::new(), read("(/ 3 2 1)")) == (Expr::Int(1)));
}

#[test]
fn test_nested_arith(){
    assert!(eval(&mut Env::new(), read("(/ (- (+ 1 (* 2 3)) 3) 2)")) == (Expr::Int(2)));
}

#[test]
fn test_concat(){
    assert!(eval(&mut Env::new(), read("(concat \"a\" \"b\" \"cd\")")) == (Expr::Str("abcd".to_string())))
}

#[test]
fn test_progn(){
    assert!(eval(&mut Env::new(), read("(progn 1 2)")) == (Expr::Int(2)));
    assert!(eval(&mut Env::new(), read("(progn (+ 1 2) (+ 2 3))")) == (Expr::Int(5)));
}

#[test]
fn test_lambda(){
    assert!(eval(&mut Env::new(), read("(lambda (x) x)")) == (Expr::Lambda(Rc::new(Expr::list1(Expr::Sym("x".to_string()))),
                                                                           Rc::new(Expr::list2(Expr::Sym("progn".to_string()), Expr::Sym("x".to_string()))))));
    assert!(eval(&mut Env::new(), read("((lambda (x) (+ x x)) 1)")) == (Expr::Int(2)))
}

#[test]
fn test_funcall(){
    assert!(eval(&mut Env::new(), read("(funcall #'+ 1 2)")) == (Expr::Int(3)));
    assert!(eval(&mut Env::new(), read("(funcall #'(lambda (x y) (* x y)) 1 2)")) == (Expr::Int(2)));
    assert!(eval(&mut Env::new(), read("(funcall (lambda (x y) (* x y)) 1 2)")) == (Expr::Int(2)))
}

<commit_msg>add get_args!<commit_after>use std::rc::Rc;
use std::ops::Deref;

use expr::{Expr,Prim};
use env::Env;
use read::read;

fn f_foldl<F:Fn(&mut Env, Expr, &Expr) -> Expr>(mut env: &mut Env, f: &F, init: Expr, args: &Expr) -> Expr {
    let mut res = init;
    let mut head = args;
    let nil = &Expr::Nil;
    while head != nil {
        match head {
            &Expr::Cons(ref car, ref cdr) => {
                res = f(env, res, car);
                head = cdr;
            }
            _ => panic!("invalid argument {:?} to function", args.clone())
        }
    }
    res
}

fn f_reverse(mut env: &mut Env, args: &Expr) -> Expr {
    f_foldl(env, &|_, acc, x| Expr::Cons(Rc::new(x.clone()), Rc::new(acc)), Expr::Nil, args)
}

fn f_foldr<F:Fn(&mut Env, Expr, &Expr) -> Expr>(mut env: &mut Env, f: &F, init: Expr, args: &Expr) -> Expr {
    match args {
        &Expr::Nil => init,
        &Expr::Cons(ref car, ref cdr) => {
            let v = f_foldr(env, f, init, cdr);
            f(env, v, car)
        }
        _ => panic!("invalid argument {:?} to function", args)
    }
}

fn f_map<F:Fn(&mut Env, Expr) -> Expr>(mut env: &mut Env, f: &F, list: &Expr) -> Expr {
    f_foldr(env, &|env, acc, x| Expr::cons(f(env, x.clone()), acc)
                 , Expr::Nil, list)
}

fn f_iter<F:Fn(&mut Env, Expr)>(mut env: &mut Env, f: &F, list: &Expr) -> Expr {
    f_foldr(env, &|env, acc, x| {f(env,x.clone()); Expr::Nil}
                 , Expr::Nil, list)
}

// since rust's macro cannot treat binop, work around macro is needed.
macro_rules! expr {
    ($e:expr) => {
        $e
    }
}

macro_rules! def_arith_op {
    ($name: ident, $op: tt, $init: expr) => {
        fn $name(mut env: &mut Env, args: Expr) -> Expr {
            let (init, args) = match args {
                Expr::Cons(ref hd, ref tl) => match tl.deref() {
                    tl @ &Expr::Cons(_, _) => (hd.deref().clone(), tl.clone()),
                    tl => ($init, Expr::cons(hd.deref().clone(), tl.clone()))
                },
                args => ($init, args)
            };
            f_foldl(env, &|_, x, y| match (x, y) {
                (Expr::Int(x), &Expr::Int(y)) => Expr::Int(expr!(x $op y)),
                (x, y) => panic!("non int args {:?} and {:?} are given to $op", x, y)
            }, init, &args)

        }
    }
}

def_arith_op!(k_add, +, Expr::Int(0));
def_arith_op!(k_sub, -, Expr::Int(0));
def_arith_op!(k_mul, *, Expr::Int(1));
def_arith_op!(k_div, /, Expr::Int(1));

macro_rules! get_args_one {
    ($v:expr, int) => {
        match $v {
            &Expr::Int(x) => {x.clone()},
            hd => panic!("nil expected but got {:?}", hd)
        }
    };
    ($v:expr, str) => {
        match $v {
            &Expr::Str(ref x) => {x.clone()},
            hd => panic!("string expected but got {:?}", hd)
        }
    };
    ($v:expr, sym) => {
        match $v {
            &Expr::Sym(ref x) => {x.clone()},
            hd => panic!("symbol expected but got {:?}", hd)
        }
    };
    ($v:expr, nil) => {
        match $v {
            &Expr::Int(x) => {x.clone()},
            hd => panic!("nil expected but got {:?}", hd)
        }
    };
}

#[macro_export]
macro_rules! get_args {
    ($args: expr, ($var: ident, $ident: tt), $($other:tt), *) =>
        (
            let $var = match $args {
                Expr::Cons(ref hd, ref tl) => get_args_one!(hd.deref(), $ident),
                Expr::Nil => panic!("invalid number of arguments"),
                args => panic!("invalid argument to function call")
            };
            get_args!(tl.deref.clone(), $($other),*)
        )
    ;
    ($args: expr, ) => ();
}

fn k_double(mut env: &mut Env, args: Expr) -> Expr {
    get_args!(args, (x, int),);
    Expr::Int(x*2)
}

fn k_concat(mut env: &mut Env, args: Expr) -> Expr {
    f_foldl(env, &|_, acc, x| match (acc, x) {
        (Expr::Str(ref acc), &Expr::Str(ref x)) => {
            Expr::Str(format!("{}{}",acc, x))
        },
        (_, y) => panic!("non string args {:?} are given to concat", y)
    }
            , Expr::Str("".to_string()), &args)
}

fn k_funcall(mut env: &mut Env, args: Expr) -> Expr {
    match args {
        Expr::Cons(f, args) => funcall(env, f.deref(), args.deref().clone()),
        args => panic!("illeagal form of funcall {:?}", args)
    }
}

fn bind_names(mut env: &mut Env, params: Expr, args: Expr) {
    let mut phead = &params;
    let mut ahead = &args;
    let nil = &Expr::Nil;
    while phead != nil && ahead != nil {
        match (phead, ahead) {
            (&Expr::Cons(ref pcar, ref pcdr), &Expr::Cons(ref acar, ref acdr)) => {
                match pcar.deref().clone() {
                    Expr::Sym(ref name) => env.register(name.clone(), acar.deref().clone()),
                    pcar => panic!("illeagal form of params {:?}", pcar)
                };
                phead = pcdr.deref();
                ahead = acdr.deref();
            },
            _ => panic!("ileagal form of funcall")
        }
    }

}

fn funcall(mut env: &mut Env, f: &Expr, args: Expr) -> Expr {
    match f {
        &Expr::FLambda(ref prim) => match prim {
            &Prim::Add => k_add(env, args),
            &Prim::Sub => k_sub(env, args),
            &Prim::Mul => k_mul(env, args),
            &Prim::Div => k_div(env, args),
            &Prim::Funcall => k_funcall(env, args),
            &Prim::Concat => k_concat(env, args),
            &Prim::Double => k_double(env, args)
        },
        &Expr::Lambda(ref params, ref body) => {
            env.new_local();
            bind_names(env, params.deref().clone(), args);
            let ret = eval(env, body.deref().clone());
            env.end_local();
            ret
        },
        f => panic!("{:?} is not a function", f)
    }
}

fn k_quote(mut env: &mut Env, args: Expr) -> Expr {
    match args {
        Expr::Cons(ref car, ref nil) => car.deref().clone(),
        _ => unreachable!()
    }
}

fn k_feval(mut env: &mut Env, args: Expr) -> Expr {
    match args {
        Expr::Cons(ref car, ref nil) => feval(env, car.deref().clone()),
        _ => unreachable!()
    }
}

fn k_lambda(mut env: &mut Env, args: Expr) -> Expr {
    match args {
        Expr::Cons(params, body) => Expr::Lambda(params, Rc::new(Expr::Cons(Rc::new(Expr::Sym("progn".to_string())), body))),
        _ => unreachable!()
    }
}

fn k_progn(mut env: &mut Env, args: Expr) -> Expr {
    let mut head = &args;
    let nil = &Expr::Nil;
    let mut res = Expr::Nil;
    while head != nil {
        match head {
            &Expr::Cons(ref car, ref cdr) => {
                res = eval(env, car.deref().clone());
                head = cdr.deref();
            },
            _ => panic!("invalid form of progn or lambda")
        }
    };
    res
}

fn feval(mut env: &mut Env, expr: Expr) -> Expr {
    match expr {
        Expr::Sym(ref sym) => match &sym[..] {
            "+" => Expr::FLambda(Prim::Add),
            "-" => Expr::FLambda(Prim::Sub),
            "*" => Expr::FLambda(Prim::Mul),
            "/" => Expr::FLambda(Prim::Div),
            "concat" => Expr::FLambda(Prim::Concat),
            "funcall" => Expr::FLambda(Prim::Funcall),
            "double" => Expr::FLambda(Prim::Double),
            fun => match env.ffind(&fun.to_string()) {
                Some(f) => f.clone(),
                None => panic!("function {:?} not found", fun)
            }
        },
        Expr::Cons(ref op, ref rest) => {
            let op = op.deref();
            match op {
                &Expr::Sym(ref sym) => match &sym[..] {
                    "lambda" => k_lambda(env, rest.deref().clone()),
                    op => panic!("invalid expression '({:?} {:?})' found at function potision", op, rest)
                },
                op => panic!("invalid expression '({:?} {:?})' found at function potision", op, rest)
            }
        }
        Expr::Lambda(_, _) => expr,
        x => panic!("{:?} is not a function", x)
    }
}

pub fn eval(mut env: &mut Env, expr: Expr) -> Expr {
    match expr {
        Expr::Nil |
        Expr::EOF |
        Expr::Str(_) |
        Expr::Int(_) |
        Expr::Lambda(_, _) |
        Expr::FLambda(_) => expr,
        Expr::Sym(ref name) => match env.find(&name.to_string()) {
            Some(v) => v.clone(),
            None => panic!("variable {:?} not found", name)
        }
,
        Expr::Cons(ref car, ref cdr) => {
            let car = car.deref();
            let cdr = cdr.deref();
            match car {
                &Expr::Sym(ref sym) => match &sym[..] {
                    "quote" => k_quote(env, cdr.clone()),
                    "function" => k_feval(env, cdr.clone()),
                    "lambda" => k_lambda(env, cdr.clone()),
                    "progn" => k_progn(env, cdr.clone()),
                    _ => {
                        let f = feval(env, car.clone());
                        let arg = f_map(env, &|env, x| eval(env, x), cdr);
                        funcall(env, &f, arg)
                    }
                },
                car => {
                    let f = feval(env, car.clone());
                    let arg = f_map(env, &|env, x| eval(env, x), cdr);
                    funcall(env, &f, arg)
                }
            }
        }
    }
}

#[test]
fn test_atom(){
    assert!(eval(&mut Env::new(), read("1")) == (Expr::Int(1)));
    assert!(eval(&mut Env::new(), read("()")) == (Expr::Nil));
    assert!(eval(&mut Env::new(), read("")) == (Expr::EOF));
    assert!(eval(&mut Env::new(), read("\"string\"")) == (Expr::Str("string".to_string())));
}

#[test]
fn test_add(){
    assert!(eval(&mut Env::new(), read("(+)")) == (Expr::Int(0)));
    assert!(eval(&mut Env::new(), read("(+ 1)")) == (Expr::Int(1)));
    assert!(eval(&mut Env::new(), read("(+ 1 2)")) == (Expr::Int(3)));
    assert!(eval(&mut Env::new(), read("(+ 1 2 3)")) == (Expr::Int(6)));
}

#[test]
fn test_sub(){
    assert!(eval(&mut Env::new(), read("(-)")) == (Expr::Int(0)));
    assert!(eval(&mut Env::new(), read("(- 1)")) == (Expr::Int(-1)));
    assert!(eval(&mut Env::new(), read("(- 1 2)")) == (Expr::Int(-1)));
    assert!(eval(&mut Env::new(), read("(- 1 2 3)")) == (Expr::Int(-4)));
}

#[test]
fn test_mul(){
    assert!(eval(&mut Env::new(), read("(*)")) == (Expr::Int(1)));
    assert!(eval(&mut Env::new(), read("(* 1)")) == (Expr::Int(1)));
    assert!(eval(&mut Env::new(), read("(* 1 2)")) == (Expr::Int(2)));
    assert!(eval(&mut Env::new(), read("(* 1 2 3)")) == (Expr::Int(6)));
}

#[test]
fn test_div(){
    assert!(eval(&mut Env::new(), read("(/)")) == (Expr::Int(1)));
    assert!(eval(&mut Env::new(), read("(/ 1)")) == (Expr::Int(1)));
    assert!(eval(&mut Env::new(), read("(/ 3 2)")) == (Expr::Int(1)));
    assert!(eval(&mut Env::new(), read("(/ 3 2 1)")) == (Expr::Int(1)));
}

#[test]
fn test_nested_arith(){
    assert!(eval(&mut Env::new(), read("(/ (- (+ 1 (* 2 3)) 3) 2)")) == (Expr::Int(2)));
}

#[test]
fn test_concat(){
    assert!(eval(&mut Env::new(), read("(concat \"a\" \"b\" \"cd\")")) == (Expr::Str("abcd".to_string())))
}

#[test]
fn test_progn(){
    assert!(eval(&mut Env::new(), read("(progn 1 2)")) == (Expr::Int(2)));
    assert!(eval(&mut Env::new(), read("(progn (+ 1 2) (+ 2 3))")) == (Expr::Int(5)));
}

#[test]
fn test_lambda(){
    assert!(eval(&mut Env::new(), read("(lambda (x) x)")) == (Expr::Lambda(Rc::new(Expr::list1(Expr::Sym("x".to_string()))),
                                                                           Rc::new(Expr::list2(Expr::Sym("progn".to_string()), Expr::Sym("x".to_string()))))));
    assert!(eval(&mut Env::new(), read("((lambda (x) (+ x x)) 1)")) == (Expr::Int(2)))
}

#[test]
fn test_funcall(){
    assert!(eval(&mut Env::new(), read("(funcall #'+ 1 2)")) == (Expr::Int(3)));
    assert!(eval(&mut Env::new(), read("(funcall #'(lambda (x y) (* x y)) 1 2)")) == (Expr::Int(2)));
    assert!(eval(&mut Env::new(), read("(funcall (lambda (x y) (* x y)) 1 2)")) == (Expr::Int(2)))
}

#[test]
fn test_double() {
    assert!(eval(&mut Env::new(), read("(double 1)")) == (Expr::Int(2)))
}
<|endoftext|>


<commit_before>use crate::colour::Colour;
use crate::graph::{Graph, Position};
use crate::grid::Grid;

pub enum GameState {
    Solving,
    Solved,
}

pub struct Game {
    pub state: GameState,
    pub graph: Graph,
    number_of_clicks: u32,
}

const TOP_LEFT_CELL: Position = Position{column: 0_usize, row: 0_usize};

impl Game {
    pub fn create(size: u32) -> Self {
        let grid = Grid::generate(size as usize);
        let graph = Graph::create(&grid);
        Self {
            state: GameState::Solving,
            graph,
            number_of_clicks: 0,
        }
    }

    pub fn fill_component_of_top_left_cell_with(&mut self, colour: Colour) {
        self.number_of_clicks += 1;
        self.graph.change_colour_of_component_at(&TOP_LEFT_CELL, colour);
    }
}
<commit_msg>Store number of allowed clicks<commit_after>use crate::colour::Colour;
use crate::graph::{Graph, Position};
use crate::grid::Grid;

pub enum GameState {
    Solving,
    Solved,
}

pub struct Game {
    pub state: GameState,
    pub graph: Graph,
    number_of_clicks: u32,
    allowed_clicks: u32,
}

const TOP_LEFT_CELL: Position = Position{column: 0_usize, row: 0_usize};

impl Game {
    pub fn create(size: u32) -> Self {
        let num_colours = 4;
        let grid = Grid::generate(size as usize);
        let graph = Graph::create(&grid);

        let allowed_clicks = 25 * 2 * size * num_colours / (2 * 14 * 6);

        Self {
            state: GameState::Solving,
            graph,
            number_of_clicks: 0,
            allowed_clicks,
        }
    }

    pub fn fill_component_of_top_left_cell_with(&mut self, colour: Colour) {
        self.number_of_clicks += 1;
        self.graph.change_colour_of_component_at(&TOP_LEFT_CELL, colour);
    }
}
<|endoftext|>


<commit_before>use std;
use std::num::FromPrimitive;
use std::ffi::c_str_to_bytes;
use std::str;
use std::borrow::ToOwned;
use ffi;
use {
    FtResult,
    GlyphSlot,
    Matrix,
    Vector,
};

#[repr(u32)]
#[derive(Copy)]
pub enum KerningMode {
    KerningDefault = ffi::FT_KERNING_DEFAULT,
    KerningUnfitted = ffi::FT_KERNING_UNFITTED,
    KerningUnscaled = ffi::FT_KERNING_UNSCALED
}

bitflags!(
flags LoadFlag: i32 {
    const DEFAULT                    = ffi::FT_LOAD_DEFAULT,
    const NO_SCALE                   = ffi::FT_LOAD_NO_SCALE,
    const NO_HINTING                 = ffi::FT_LOAD_NO_HINTING,
    const RENDER                     = ffi::FT_LOAD_RENDER,
    const NO_BITMAP                  = ffi::FT_LOAD_NO_BITMAP,
    const VERTICAL_LAYOUT            = ffi::FT_LOAD_VERTICAL_LAYOUT,
    const FORCE_AUTOHINT             = ffi::FT_LOAD_FORCE_AUTOHINT,
    const CROP_BITMAP                = ffi::FT_LOAD_CROP_BITMAP,
    const PEDANTIC                   = ffi::FT_LOAD_PEDANTIC,
    const IGNORE_GLOBAL_ADVANCE_WITH = ffi::FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH,
    const NO_RECURSE                 = ffi::FT_LOAD_NO_RECURSE,
    const IGNORE_TRANSFORM           = ffi::FT_LOAD_IGNORE_TRANSFORM,
    const MONOCHROME                 = ffi::FT_LOAD_MONOCHROME,
    const LINEAR_DESIGN              = ffi::FT_LOAD_LINEAR_DESIGN,
    const NO_AUTOHINT                = ffi::FT_LOAD_NO_AUTOHINT,
    const TARGET_NORMAL              = ffi::FT_LOAD_TARGET_NORMAL,
    const TARGET_LIGHT               = ffi::FT_LOAD_TARGET_LIGHT,
    const TARGET_MONO                = ffi::FT_LOAD_TARGET_MONO,
    const TARGET_LCD                 = ffi::FT_LOAD_TARGET_LCD,
    const TARGET_LCD_V               = ffi::FT_LOAD_TARGET_LCD_V,
    const COLOR                      = ffi::FT_LOAD_COLOR
});

#[derive(Eq, PartialEq, Hash)]
pub struct Face {
    library_raw: ffi::FT_Library,
    raw: ffi::FT_Face,
    glyph: GlyphSlot,
}

impl Face {
    pub fn from_raw(library_raw: ffi::FT_Library, raw: ffi::FT_Face) -> Face {
        unsafe {
            ffi::FT_Reference_Library(library_raw);
        }

        Face {
            library_raw: library_raw,
            raw: raw,
            glyph: unsafe { GlyphSlot::from_raw(library_raw, (*raw).glyph) },
        }
    }

    pub fn attach_file(&mut self, filepathname: &str) -> FtResult<()> {
        unsafe {
            let err = ffi::FT_Attach_File(self.raw, filepathname.as_slice().as_ptr() as *const i8);
            if err == ffi::FT_Err_Ok {
                Ok(())
            } else {
                Err(FromPrimitive::from_i32(err).unwrap())
            }
        }
    }

    pub fn reference(&mut self) -> FtResult<()> {
        unsafe {
            let err = ffi::FT_Reference_Face(self.raw);
            if err == ffi::FT_Err_Ok {
                Ok(())
            } else {
                Err(FromPrimitive::from_i32(err).unwrap())
            }
        }
    }

    pub fn set_char_size(&mut self, char_width: ffi::FT_F26Dot6, char_height: ffi::FT_F26Dot6, horz_resolution: u32, vert_resolution: u32) -> FtResult<()> {
        unsafe {
            let err = ffi::FT_Set_Char_Size(self.raw, char_width, char_height, horz_resolution, vert_resolution);
            if err == ffi::FT_Err_Ok {
                Ok(())
            } else {
                Err(FromPrimitive::from_i32(err).unwrap())
            }
        }
    }

    pub fn set_pixel_sizes(&mut self, pixel_width: u32, pixel_height: u32) -> FtResult<()> {
        unsafe {
            let err = ffi::FT_Set_Pixel_Sizes(self.raw, pixel_width, pixel_height);
            if err == ffi::FT_Err_Ok {
                Ok(())
            } else {
                Err(FromPrimitive::from_i32(err).unwrap())
            }
        }
    }

    pub fn load_glyph(&mut self, glyph_index: u32, load_flags: LoadFlag) -> FtResult<()> {
        unsafe {
            let err = ffi::FT_Load_Glyph(self.raw, glyph_index, load_flags.bits);
            if err == ffi::FT_Err_Ok {
                Ok(())
            } else {
                Err(FromPrimitive::from_i32(err).unwrap())
            }
        }
    }

    pub fn load_char(&mut self, char_code: usize, load_flags: LoadFlag) -> FtResult<()> {
        unsafe {
            let err = ffi::FT_Load_Char(self.raw, char_code as ffi::FT_ULong, load_flags.bits);
            if err == ffi::FT_Err_Ok {
                Ok(())
            } else {
                Err(FromPrimitive::from_i32(err).unwrap())
            }
        }
    }

    pub fn set_transform(&mut self, matrix: &Matrix, delta: &Vector) {
        unsafe {
            ffi::FT_Set_Transform(self.raw, matrix, delta);
        }
    }

    pub fn get_char_index(&self, charcode: usize) -> u32 {
        unsafe {
            ffi::FT_Get_Char_Index(self.raw, charcode as ffi::FT_ULong)
        }
    }

    pub fn get_kerning(&self, left_char_index: u32, right_char_index: u32, kern_mode: KerningMode)
        -> FtResult<Vector> {

        let vec = Vector { x: 0, y: 0 };

        let err_code = unsafe {
            ffi::FT_Get_Kerning(self.raw, left_char_index, right_char_index,
                                kern_mode as u32, std::mem::transmute(&vec))
        };

        if err_code == ffi::FT_Err_Ok {
            Ok(vec)
        } else {
            Err(FromPrimitive::from_i32(err_code).unwrap())
        }
    }

    // According to FreeType doc, each time you load a new glyph image,
    // the previous one is erased from the glyph slot.
    #[inline(always)]
    pub fn glyph(&self) -> &GlyphSlot {
        &self.glyph
    }

    #[inline(always)]
    pub fn has_horizontal(&self) -> bool {
        ffi::FT_HAS_HORIZONTAL(self.raw)
    }

    #[inline(always)]
    pub fn has_vertical(&self) -> bool {
        ffi::FT_HAS_VERTICAL(self.raw)
    }

    #[inline(always)]
    pub fn has_kerning(&self) -> bool {
        ffi::FT_HAS_KERNING(self.raw)
    }

    #[inline(always)]
    pub fn is_scalable(&self) -> bool {
        ffi::FT_IS_SCALABLE(self.raw)
    }

    #[inline(always)]
    pub fn is_sfnt(&self) -> bool {
        ffi::FT_IS_SFNT(self.raw)
    }

    #[inline(always)]
    pub fn is_fixed_width(&self) -> bool {
        ffi::FT_IS_FIXED_WIDTH(self.raw)
    }

    #[inline(always)]
    pub fn has_fixed_sizes(&self) -> bool {
        ffi::FT_HAS_FIXED_SIZES(self.raw)
    }

    #[inline(always)]
    pub fn has_glyph_names(&self) -> bool {
        ffi::FT_HAS_GLYPH_NAMES(self.raw)
    }

    #[inline(always)]
    pub fn is_cid_keyed(&self) -> bool {
        ffi::FT_IS_CID_KEYED(self.raw)
    }

    #[inline(always)]
    pub fn is_tricky(&self) -> bool {
        ffi::FT_IS_TRICKY(self.raw)
    }

    #[inline(always)]
    pub fn has_color(&self) -> bool {
        ffi::FT_HAS_COLOR(self.raw)
    }

    #[inline(always)]
    pub fn raw(&self) -> &ffi::FT_FaceRec {
        unsafe {
            &*self.raw
        }
    }

    #[inline(always)]
    pub fn ascender(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).ascender
        }
    }

    #[inline(always)]
    pub fn descender(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).descender
        }
    }

    #[inline(always)]
    pub fn height(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).height
        }
    }

    #[inline(always)]
    pub fn max_advance_width(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).max_advance_width
        }
    }

    #[inline(always)]
    pub fn max_advance_height(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).max_advance_height
        }
    }

    #[inline(always)]
    pub fn underline_position(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).underline_position
        }
    }

    #[inline(always)]
    pub fn underline_thickness(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).underline_thickness
        }
    }

    pub fn family_name(&self) -> Option<String> {

        let family_name_ptr = unsafe { (*self.raw).family_name };

        if family_name_ptr.is_null() {
            None
        } else {
            let family_name = unsafe { c_str_to_bytes(&family_name_ptr) };
            match str::from_utf8(family_name) {
                Ok(string)  => Some(string.to_owned()),
                _           => None
            }
        }
    }

    pub fn style_name(&self) -> Option<String> {

        let style_name_ptr = unsafe { (*self.raw).style_name };

        if style_name_ptr.is_null() {
            None
        } else {
            let style_name = unsafe { c_str_to_bytes(&style_name_ptr) };
            match str::from_utf8(style_name) {
                Ok(string)  => Some(string.to_owned()),
                _           => None
            }
        }
    }
}

impl Drop for Face {
    fn drop(&mut self) {
        unsafe {
            match ffi::FT_Done_Face(self.raw) {
                ffi::FT_Err_Ok => {
                    if ffi::FT_Done_Library(self.library_raw) != ffi::FT_Err_Ok {
                        panic!("Failed to deref library");
                    }
                },
                _ => panic!("Failed to drop face"),
            }
        }
    }
}
<commit_msg>fix a couple more integer types<commit_after>use std;
use std::num::FromPrimitive;
use std::ffi::c_str_to_bytes;
use std::str;
use std::borrow::ToOwned;
use ffi;
use {
    FtResult,
    GlyphSlot,
    Matrix,
    Vector,
};

#[repr(u32)]
#[derive(Copy)]
pub enum KerningMode {
    KerningDefault = ffi::FT_KERNING_DEFAULT,
    KerningUnfitted = ffi::FT_KERNING_UNFITTED,
    KerningUnscaled = ffi::FT_KERNING_UNSCALED
}

bitflags!(
flags LoadFlag: i32 {
    const DEFAULT                    = ffi::FT_LOAD_DEFAULT,
    const NO_SCALE                   = ffi::FT_LOAD_NO_SCALE,
    const NO_HINTING                 = ffi::FT_LOAD_NO_HINTING,
    const RENDER                     = ffi::FT_LOAD_RENDER,
    const NO_BITMAP                  = ffi::FT_LOAD_NO_BITMAP,
    const VERTICAL_LAYOUT            = ffi::FT_LOAD_VERTICAL_LAYOUT,
    const FORCE_AUTOHINT             = ffi::FT_LOAD_FORCE_AUTOHINT,
    const CROP_BITMAP                = ffi::FT_LOAD_CROP_BITMAP,
    const PEDANTIC                   = ffi::FT_LOAD_PEDANTIC,
    const IGNORE_GLOBAL_ADVANCE_WITH = ffi::FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH,
    const NO_RECURSE                 = ffi::FT_LOAD_NO_RECURSE,
    const IGNORE_TRANSFORM           = ffi::FT_LOAD_IGNORE_TRANSFORM,
    const MONOCHROME                 = ffi::FT_LOAD_MONOCHROME,
    const LINEAR_DESIGN              = ffi::FT_LOAD_LINEAR_DESIGN,
    const NO_AUTOHINT                = ffi::FT_LOAD_NO_AUTOHINT,
    const TARGET_NORMAL              = ffi::FT_LOAD_TARGET_NORMAL,
    const TARGET_LIGHT               = ffi::FT_LOAD_TARGET_LIGHT,
    const TARGET_MONO                = ffi::FT_LOAD_TARGET_MONO,
    const TARGET_LCD                 = ffi::FT_LOAD_TARGET_LCD,
    const TARGET_LCD_V               = ffi::FT_LOAD_TARGET_LCD_V,
    const COLOR                      = ffi::FT_LOAD_COLOR
});

#[derive(Eq, PartialEq, Hash)]
pub struct Face {
    library_raw: ffi::FT_Library,
    raw: ffi::FT_Face,
    glyph: GlyphSlot,
}

impl Face {
    pub fn from_raw(library_raw: ffi::FT_Library, raw: ffi::FT_Face) -> Face {
        unsafe {
            ffi::FT_Reference_Library(library_raw);
        }

        Face {
            library_raw: library_raw,
            raw: raw,
            glyph: unsafe { GlyphSlot::from_raw(library_raw, (*raw).glyph) },
        }
    }

    pub fn attach_file(&mut self, filepathname: &str) -> FtResult<()> {
        unsafe {
            let err = ffi::FT_Attach_File(self.raw, filepathname.as_slice().as_ptr() as *const i8);
            if err == ffi::FT_Err_Ok {
                Ok(())
            } else {
                Err(FromPrimitive::from_i32(err).unwrap())
            }
        }
    }

    pub fn reference(&mut self) -> FtResult<()> {
        unsafe {
            let err = ffi::FT_Reference_Face(self.raw);
            if err == ffi::FT_Err_Ok {
                Ok(())
            } else {
                Err(FromPrimitive::from_i32(err).unwrap())
            }
        }
    }

    pub fn set_char_size(&mut self, char_width: isize, char_height: isize, horz_resolution: u32, vert_resolution: u32) -> FtResult<()> {
        unsafe {
            let err = ffi::FT_Set_Char_Size(self.raw, char_width as ffi::FT_F26Dot6,
                                            char_height as ffi::FT_F26Dot6, horz_resolution,
                                            vert_resolution);
            if err == ffi::FT_Err_Ok {
                Ok(())
            } else {
                Err(FromPrimitive::from_i32(err).unwrap())
            }
        }
    }

    pub fn set_pixel_sizes(&mut self, pixel_width: u32, pixel_height: u32) -> FtResult<()> {
        unsafe {
            let err = ffi::FT_Set_Pixel_Sizes(self.raw, pixel_width, pixel_height);
            if err == ffi::FT_Err_Ok {
                Ok(())
            } else {
                Err(FromPrimitive::from_i32(err).unwrap())
            }
        }
    }

    pub fn load_glyph(&mut self, glyph_index: u32, load_flags: LoadFlag) -> FtResult<()> {
        unsafe {
            let err = ffi::FT_Load_Glyph(self.raw, glyph_index, load_flags.bits);
            if err == ffi::FT_Err_Ok {
                Ok(())
            } else {
                Err(FromPrimitive::from_i32(err).unwrap())
            }
        }
    }

    pub fn load_char(&mut self, char_code: usize, load_flags: LoadFlag) -> FtResult<()> {
        unsafe {
            let err = ffi::FT_Load_Char(self.raw, char_code as ffi::FT_ULong, load_flags.bits);
            if err == ffi::FT_Err_Ok {
                Ok(())
            } else {
                Err(FromPrimitive::from_i32(err).unwrap())
            }
        }
    }

    pub fn set_transform(&mut self, matrix: &Matrix, delta: &Vector) {
        unsafe {
            ffi::FT_Set_Transform(self.raw, matrix, delta);
        }
    }

    pub fn get_char_index(&self, charcode: usize) -> u32 {
        unsafe {
            ffi::FT_Get_Char_Index(self.raw, charcode as ffi::FT_ULong)
        }
    }

    pub fn get_kerning(&self, left_char_index: u32, right_char_index: u32, kern_mode: KerningMode)
        -> FtResult<Vector> {

        let vec = Vector { x: 0, y: 0 };

        let err_code = unsafe {
            ffi::FT_Get_Kerning(self.raw, left_char_index, right_char_index,
                                kern_mode as u32, std::mem::transmute(&vec))
        };

        if err_code == ffi::FT_Err_Ok {
            Ok(vec)
        } else {
            Err(FromPrimitive::from_i32(err_code).unwrap())
        }
    }

    // According to FreeType doc, each time you load a new glyph image,
    // the previous one is erased from the glyph slot.
    #[inline(always)]
    pub fn glyph(&self) -> &GlyphSlot {
        &self.glyph
    }

    #[inline(always)]
    pub fn has_horizontal(&self) -> bool {
        ffi::FT_HAS_HORIZONTAL(self.raw)
    }

    #[inline(always)]
    pub fn has_vertical(&self) -> bool {
        ffi::FT_HAS_VERTICAL(self.raw)
    }

    #[inline(always)]
    pub fn has_kerning(&self) -> bool {
        ffi::FT_HAS_KERNING(self.raw)
    }

    #[inline(always)]
    pub fn is_scalable(&self) -> bool {
        ffi::FT_IS_SCALABLE(self.raw)
    }

    #[inline(always)]
    pub fn is_sfnt(&self) -> bool {
        ffi::FT_IS_SFNT(self.raw)
    }

    #[inline(always)]
    pub fn is_fixed_width(&self) -> bool {
        ffi::FT_IS_FIXED_WIDTH(self.raw)
    }

    #[inline(always)]
    pub fn has_fixed_sizes(&self) -> bool {
        ffi::FT_HAS_FIXED_SIZES(self.raw)
    }

    #[inline(always)]
    pub fn has_glyph_names(&self) -> bool {
        ffi::FT_HAS_GLYPH_NAMES(self.raw)
    }

    #[inline(always)]
    pub fn is_cid_keyed(&self) -> bool {
        ffi::FT_IS_CID_KEYED(self.raw)
    }

    #[inline(always)]
    pub fn is_tricky(&self) -> bool {
        ffi::FT_IS_TRICKY(self.raw)
    }

    #[inline(always)]
    pub fn has_color(&self) -> bool {
        ffi::FT_HAS_COLOR(self.raw)
    }

    #[inline(always)]
    pub fn raw(&self) -> &ffi::FT_FaceRec {
        unsafe {
            &*self.raw
        }
    }

    #[inline(always)]
    pub fn ascender(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).ascender
        }
    }

    #[inline(always)]
    pub fn descender(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).descender
        }
    }

    #[inline(always)]
    pub fn height(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).height
        }
    }

    #[inline(always)]
    pub fn max_advance_width(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).max_advance_width
        }
    }

    #[inline(always)]
    pub fn max_advance_height(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).max_advance_height
        }
    }

    #[inline(always)]
    pub fn underline_position(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).underline_position
        }
    }

    #[inline(always)]
    pub fn underline_thickness(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).underline_thickness
        }
    }

    pub fn family_name(&self) -> Option<String> {

        let family_name_ptr = unsafe { (*self.raw).family_name };

        if family_name_ptr.is_null() {
            None
        } else {
            let family_name = unsafe { c_str_to_bytes(&family_name_ptr) };
            match str::from_utf8(family_name) {
                Ok(string)  => Some(string.to_owned()),
                _           => None
            }
        }
    }

    pub fn style_name(&self) -> Option<String> {

        let style_name_ptr = unsafe { (*self.raw).style_name };

        if style_name_ptr.is_null() {
            None
        } else {
            let style_name = unsafe { c_str_to_bytes(&style_name_ptr) };
            match str::from_utf8(style_name) {
                Ok(string)  => Some(string.to_owned()),
                _           => None
            }
        }
    }
}

impl Drop for Face {
    fn drop(&mut self) {
        unsafe {
            match ffi::FT_Done_Face(self.raw) {
                ffi::FT_Err_Ok => {
                    if ffi::FT_Done_Library(self.library_raw) != ffi::FT_Err_Ok {
                        panic!("Failed to deref library");
                    }
                },
                _ => panic!("Failed to drop face"),
            }
        }
    }
}
<|endoftext|>


<commit_before>use core::*;
use bitboard::*;
use moves::*;
use board::*;
use tables::*;

use std::collections::HashMap;

bitflags! {
    pub struct CastlingRights: u32 {
        const WHITE_KINGSIDE  = 0b0001;
        const WHITE_QUEENSIDE = 0b0010;
        const BLACK_KINGSIDE  = 0b0100;
        const BLACK_QUEENSIDE = 0b1000;
    }
}

#[derive(Debug, PartialEq, Clone, Copy)]
pub struct Game {
    pub board: Board,
    pub to_move: Color,
    pub ep_square: Option<Square>,
    pub castling_rights: CastlingRights,
    pub fifty_move_count: u32,
    pub moves: u32
}

impl Game {
    pub fn starting_position() -> Game {
        Game {
            board: Board::starting_position(),
            to_move: Color::White,
            ep_square: None,
            castling_rights: CastlingRights::all(),
            fifty_move_count: 0,
            moves: 1,
        }
    }

    pub fn empty_position() -> Game {
        Game {
            board: Board::empty_position(),
            to_move: Color::White,
            ep_square: None,
            castling_rights: CastlingRights::empty(),
            fifty_move_count: 0,
            moves: 1
        }
    }

    pub fn from_fen(fen: &'static str) -> Option<Game> {
        let words: Vec<&str> = fen.split(' ').collect();

        if words.len() != 6 {
            return None;
        }

        let mut game = Game::empty_position();

        use PieceType::*;
        use Color::*;

        { // build up the game board
            let mut current_square: Square = Square::new(63);

            let decrement_square = |sq: &mut Square, n: u32| {
                if sq.unwrap() > 0 {
                    *sq = Square::new(sq.unwrap() - n);
                }
            };

            let mut add_piece = |color: Color, piece: PieceType, sq: &mut Square| {
                game.board.set_piece_bit(color, piece, *sq);
                decrement_square(sq, 1);
            };

            for ch in words[0].chars() {
                match ch {
                    'p' => add_piece(Black , Pawn   , &mut current_square) ,
                    'n' => add_piece(Black , Knight , &mut current_square) ,
                    'b' => add_piece(Black , Bishop , &mut current_square) ,
                    'r' => add_piece(Black , Rook   , &mut current_square) ,
                    'q' => add_piece(Black , Queen  , &mut current_square) ,
                    'k' => add_piece(Black , King   , &mut current_square) ,
                    'P' => add_piece(White , Pawn   , &mut current_square) ,
                    'N' => add_piece(White , Knight , &mut current_square) ,
                    'B' => add_piece(White , Bishop , &mut current_square) ,
                    'R' => add_piece(White , Rook   , &mut current_square) ,
                    'Q' => add_piece(White , Queen  , &mut current_square) ,
                    'K' => add_piece(White , King   , &mut current_square) ,
                    '1' => decrement_square(&mut current_square, 1),
                    '2' => decrement_square(&mut current_square, 2),
                    '3' => decrement_square(&mut current_square, 3),
                    '4' => decrement_square(&mut current_square, 4),
                    '5' => decrement_square(&mut current_square, 5),
                    '6' => decrement_square(&mut current_square, 6),
                    '7' => decrement_square(&mut current_square, 7),
                    '8' => decrement_square(&mut current_square, 8),
                    '/' => {},
                    _ => return None
                }
            }
        }

        match words[1] {
            "w" => game.to_move = White,
            "b" => game.to_move = Black,
            _ => return None
        }

        for ch in words[2].chars() {
            match ch {
                'K' => game.castling_rights |= CastlingRights::WHITE_KINGSIDE,
                'Q' => game.castling_rights |= CastlingRights::WHITE_QUEENSIDE,
                'k' => game.castling_rights |= CastlingRights::BLACK_KINGSIDE,
                'q' => game.castling_rights |= CastlingRights::BLACK_QUEENSIDE,
                '-' => {},
                _ => return None
            }
        }

        match words[3] {
            "-" => game.ep_square = None,
            _ => match Square::from_algebraic(words[3]) {
                None => return None,
                Some(sq) => game.ep_square = Some(sq)
            }
        }

        match words[4].parse::<u32>() {
            Err(_) => return None,
            Ok(x) => game.fifty_move_count = x
        }

        match words[5].parse::<u32>() {
            Err(_) => return None,
            Ok(x) => game.moves = x
        }

        return Some(game);
    }

    pub fn generate_moves(&self, move_buffer: &mut Vec<Move>) {
        move_buffer.clear();

        use Color::*;
        use PieceType::*;

        let friendly_color   = self.to_move;
        let opponent_color  = !friendly_color;

        let empty_squares   = self.board.unoccupied();
        let all_pieces      = self.board.occupied();
        let friendly_pieces = self.board.occupied_by(friendly_color);
        let opponent_pieces = self.board.occupied_by(!friendly_color);

        let king_square     = self.board.get_king_square(friendly_color);
        let king_attackers = self.board.attackers(king_square, opponent_color);
        let checkers = king_attackers.population();
        let in_check = checkers > 0;
        let king_moves = KING_TABLE[king_square.idx()];
        let king_danger_squares = self.board.attacked(!friendly_color, true);

        if checkers > 1 {
            for to in king_moves & empty_squares & !king_danger_squares {
                move_buffer.push(Move::new(king_square, to, QUIET_FLAG));
            }
            return;
        }

        let mut capture_mask = opponent_pieces;
        let mut quiet_mask = empty_squares;

        if checkers == 1 {
            capture_mask = king_attackers;

            let checker_square = king_attackers.bitscan_forward();
            if self.board.piece_at(checker_square).unwrap().ptype.is_slider() {
                quiet_mask = ray_between_squares(king_square, checker_square);
            } else {
                quiet_mask = Bitboard::new(0);
            }
        }

        let not_king_bit = !king_square.bitrep();

        let mut pinned_diagonally = Bitboard::new(0);
        let mut pinned_nondiagonally = Bitboard::new(0);
        {
            let opRQ = self.board.get_pieces(opponent_color, Rook) | self.board.get_pieces(opponent_color, Queen);
            let mut pinner = xray_rook_attacks(all_pieces, friendly_pieces, king_square) & opRQ;
            for pinner_square in pinner {
                let connecting_bits = ray_between_squares(king_square, pinner_square);
                let pinned_bit = connecting_bits & friendly_pieces;
                assert!(pinned_bit.population() == 1);
                pinned_nondiagonally |= pinned_bit;
            }

            let opBQ = self.board.get_pieces(opponent_color, Bishop) | self.board.get_pieces(opponent_color, Queen);
            pinner = xray_bishop_attacks(all_pieces, friendly_pieces, king_square) & opBQ;
            for pinner_square in pinner {
                let connecting_bits = ray_between_squares(king_square, pinner_square);
                let pinned_bit = connecting_bits & friendly_pieces;
                assert!(pinned_bit.population() == 1);
                pinned_diagonally |= pinned_bit;
            }
        }

        let pinned = pinned_diagonally | pinned_nondiagonally;

        // MOVE GENERATION FOR UNPINNED PIECES

        /*********/
        /* PAWNS */
        /*********/
        {
            let unpinned_pawns = self.board.get_pieces(friendly_color, Pawn) & !pinned;
            let advanced_pawns = if friendly_color == White { unpinned_pawns.shifted_up() } else { unpinned_pawns.shifted_down() };
            let double_advanced_pawns = if friendly_color == White { advanced_pawns.shifted_up() } else { advanced_pawns.shifted_down() };
            let delta_pawn_single_push: i32 = if self.to_move == White { -8 } else { 8 };
            let delta_pawn_double_push: i32 = if self.to_move == White { -16 } else { 16 };
            let double_pawn_push_rank = if self.to_move == White { RANK4 } else { RANK5 };
            let promotion_rank = if self.to_move == White { 8 } else { 1 };

            // single pushes (and promotions)
            for to in advanced_pawns & empty_squares & quiet_mask
            {
                let from = Square::new((to.unwrap() as i32 + delta_pawn_single_push) as u32);

                if to.rank() == promotion_rank {
                    move_buffer.push(Move::new(from, to, BISHOP_PROMO_FLAG));
                    move_buffer.push(Move::new(from, to, KNIGHT_PROMO_FLAG));
                    move_buffer.push(Move::new(from, to, ROOK_PROMO_FLAG));
                    move_buffer.push(Move::new(from, to, QUEEN_PROMO_FLAG));
                } else {
                    move_buffer.push(Move::new(from, to, QUIET_FLAG));
                }
            }

            // double pushes
            for to in double_advanced_pawns & empty_squares & double_pawn_push_rank & quiet_mask {

                let from = Square::new((to.unwrap() as i32 + delta_pawn_double_push) as u32);

                move_buffer.push(Move::new(from, to, DOUBLE_PAWN_PUSH_FLAG));
            }

            // captures (and capture-promotions)
            for from in unpinned_pawns
            {
                let pawn_attacks = match self.ep_square {
                    None => PAWN_ATTACKS[friendly_color as usize][from.idx()] & opponent_pieces & capture_mask,
                    Some(ep) => PAWN_ATTACKS[friendly_color as usize][from.idx()] & ( (opponent_pieces | ep.bitrep()) & capture_mask)
                };

                for to in pawn_attacks
                {
                    if to.rank() == promotion_rank {
                        move_buffer.push(Move::new(from, to, BISHOP_PROMO_CAPTURE_FLAG));
                        move_buffer.push(Move::new(from, to, KNIGHT_PROMO_CAPTURE_FLAG));
                        move_buffer.push(Move::new(from, to, ROOK_PROMO_CAPTURE_FLAG));
                        move_buffer.push(Move::new(from, to, QUEEN_PROMO_CAPTURE_FLAG));
                    } else if self.ep_square.is_some() && self.ep_square.unwrap() == to {
                        // TODO: test for discovered checks after ep capture!
                        move_buffer.push(Move::new(from, to, EP_CAPTURE_FLAG));
                    } else {
                        move_buffer.push(Move::new(from, to, CAPTURE_FLAG));
                    }
                }
            }

        }

        /***********/
        /* KNIGHTS */
        /***********/
        {
            for from in self.board.get_pieces(friendly_color, Knight) & !pinned
            {
                let knight_moves = KNIGHT_TABLE[from.idx()];

                /* quiets */
                for to in knight_moves & empty_squares & quiet_mask {
                    move_buffer.push(Move::new(from, to, QUIET_FLAG));
                }

                /* captures */
                for to in knight_moves & opponent_pieces & capture_mask {
                    move_buffer.push(Move::new(from, to, CAPTURE_FLAG));
                }
            }
        }

        /***********/
        /* BISHOPS */
        /***********/

        for from in self.board.get_pieces(friendly_color, Bishop) & !pinned
        {
            let bishop_moves = get_bishop_rays(from, all_pieces);

            /* quiets */
            for to in bishop_moves & empty_squares & quiet_mask {
                move_buffer.push(Move::new(from, to, QUIET_FLAG));
            }

            /* captures */
            for to in bishop_moves & opponent_pieces & capture_mask {
                move_buffer.push(Move::new(from, to, CAPTURE_FLAG));
            }
        }

        /*********/
        /* ROOKS */
        /*********/

        for from in self.board.get_pieces(friendly_color, Rook) & !pinned
        {
            let rook_moves = get_rook_rays(from, all_pieces);

            /* quiets */
            for to in rook_moves & empty_squares & quiet_mask {
                move_buffer.push(Move::new(from, to, QUIET_FLAG));
            }

            /* captures */
            for to in rook_moves & opponent_pieces & capture_mask {
                move_buffer.push(Move::new(from, to, CAPTURE_FLAG));
            }
        }

        /*********/
        /* QUEEN */
        /*********/

        for from in self.board.get_pieces(friendly_color, Queen) & !pinned
        {
            let queen_moves = get_queen_rays(from, all_pieces);

            /* quiets */
            for to in queen_moves & empty_squares {
                move_buffer.push(Move::new(from, to, QUIET_FLAG));
            }

            /* captures */
            for to in queen_moves & opponent_pieces {
                move_buffer.push(Move::new(from, to, CAPTURE_FLAG));
            }
        }

        /********/
        /* KING */
        /********/

        {
            /* quiets */
            for to in king_moves & empty_squares & !king_danger_squares {
                move_buffer.push(Move::new(king_square, to, QUIET_FLAG));
            }

            /* captures */
            for to in king_moves & opponent_pieces & capture_mask {
                move_buffer.push(Move::new(king_square, to, CAPTURE_FLAG));
            }

            /* castling */
            let has_kingside_castle_rights = self.castling_rights.intersects(CastlingRights::WHITE_KINGSIDE);
            let has_queenside_castle_rights = self.castling_rights.intersects(CastlingRights::WHITE_QUEENSIDE);

            if has_kingside_castle_rights && !in_check {
                let kingside_castle_path_open = (all_pieces & WHITE_KINGSIDE_CASTLE_BITS).empty();

                if kingside_castle_path_open {
                    let mut castle_path_is_safe: bool = true;

                    if (WHITE_KINGSIDE_CASTLE_BITS & king_danger_squares).nonempty() {
                        castle_path_is_safe = false;
                    }

                    if castle_path_is_safe {
                        move_buffer.push(Move::new(king_square, Square::new(1), KING_CASTLE_FLAG));
                    }
                }
            }

            if has_queenside_castle_rights && !in_check {
                let queenside_castle_path_open = (all_pieces & WHITE_QUEENSIDE_CASTLE_BITS).empty();

                if queenside_castle_path_open {
                    let mut castle_path_is_safe: bool = true;

                    if (WHITE_QUEENSIDE_CASTLE_BITS & king_danger_squares).nonempty() {
                        castle_path_is_safe = false;
                    }

                    if castle_path_is_safe {
                        move_buffer.push(Move::new(king_square, Square::new(5), QUEEN_CASTLE_FLAG));
                    }
                }
            }
        }
    }
}
<commit_msg>cleanup ep capture code<commit_after>use core::*;
use bitboard::*;
use moves::*;
use board::*;
use tables::*;

use std::collections::HashMap;

bitflags! {
    pub struct CastlingRights: u32 {
        const WHITE_KINGSIDE  = 0b0001;
        const WHITE_QUEENSIDE = 0b0010;
        const BLACK_KINGSIDE  = 0b0100;
        const BLACK_QUEENSIDE = 0b1000;
    }
}

#[derive(Debug, PartialEq, Clone, Copy)]
pub struct Game {
    pub board: Board,
    pub to_move: Color,
    pub ep_square: Option<Square>,
    pub castling_rights: CastlingRights,
    pub fifty_move_count: u32,
    pub moves: u32
}

impl Game {
    pub fn starting_position() -> Game {
        Game {
            board: Board::starting_position(),
            to_move: Color::White,
            ep_square: None,
            castling_rights: CastlingRights::all(),
            fifty_move_count: 0,
            moves: 1,
        }
    }

    pub fn empty_position() -> Game {
        Game {
            board: Board::empty_position(),
            to_move: Color::White,
            ep_square: None,
            castling_rights: CastlingRights::empty(),
            fifty_move_count: 0,
            moves: 1
        }
    }

    pub fn from_fen(fen: &'static str) -> Option<Game> {
        let words: Vec<&str> = fen.split(' ').collect();

        if words.len() != 6 {
            return None;
        }

        let mut game = Game::empty_position();

        use PieceType::*;
        use Color::*;

        { // build up the game board
            let mut current_square: Square = Square::new(63);

            let decrement_square = |sq: &mut Square, n: u32| {
                if sq.unwrap() > 0 {
                    *sq = Square::new(sq.unwrap() - n);
                }
            };

            let mut add_piece = |color: Color, piece: PieceType, sq: &mut Square| {
                game.board.set_piece_bit(color, piece, *sq);
                decrement_square(sq, 1);
            };

            for ch in words[0].chars() {
                match ch {
                    'p' => add_piece(Black , Pawn   , &mut current_square) ,
                    'n' => add_piece(Black , Knight , &mut current_square) ,
                    'b' => add_piece(Black , Bishop , &mut current_square) ,
                    'r' => add_piece(Black , Rook   , &mut current_square) ,
                    'q' => add_piece(Black , Queen  , &mut current_square) ,
                    'k' => add_piece(Black , King   , &mut current_square) ,
                    'P' => add_piece(White , Pawn   , &mut current_square) ,
                    'N' => add_piece(White , Knight , &mut current_square) ,
                    'B' => add_piece(White , Bishop , &mut current_square) ,
                    'R' => add_piece(White , Rook   , &mut current_square) ,
                    'Q' => add_piece(White , Queen  , &mut current_square) ,
                    'K' => add_piece(White , King   , &mut current_square) ,
                    '1' => decrement_square(&mut current_square, 1),
                    '2' => decrement_square(&mut current_square, 2),
                    '3' => decrement_square(&mut current_square, 3),
                    '4' => decrement_square(&mut current_square, 4),
                    '5' => decrement_square(&mut current_square, 5),
                    '6' => decrement_square(&mut current_square, 6),
                    '7' => decrement_square(&mut current_square, 7),
                    '8' => decrement_square(&mut current_square, 8),
                    '/' => {},
                    _ => return None
                }
            }
        }

        match words[1] {
            "w" => game.to_move = White,
            "b" => game.to_move = Black,
            _ => return None
        }

        for ch in words[2].chars() {
            match ch {
                'K' => game.castling_rights |= CastlingRights::WHITE_KINGSIDE,
                'Q' => game.castling_rights |= CastlingRights::WHITE_QUEENSIDE,
                'k' => game.castling_rights |= CastlingRights::BLACK_KINGSIDE,
                'q' => game.castling_rights |= CastlingRights::BLACK_QUEENSIDE,
                '-' => {},
                _ => return None
            }
        }

        match words[3] {
            "-" => game.ep_square = None,
            _ => match Square::from_algebraic(words[3]) {
                None => return None,
                Some(sq) => game.ep_square = Some(sq)
            }
        }

        match words[4].parse::<u32>() {
            Err(_) => return None,
            Ok(x) => game.fifty_move_count = x
        }

        match words[5].parse::<u32>() {
            Err(_) => return None,
            Ok(x) => game.moves = x
        }

        return Some(game);
    }

    pub fn generate_moves(&self, move_buffer: &mut Vec<Move>) {
        move_buffer.clear();

        use Color::*;
        use PieceType::*;

        let friendly_color   = self.to_move;
        let opponent_color  = !friendly_color;

        let empty_squares   = self.board.unoccupied();
        let all_pieces      = self.board.occupied();
        let friendly_pieces = self.board.occupied_by(friendly_color);
        let opponent_pieces = self.board.occupied_by(!friendly_color);

        let king_square     = self.board.get_king_square(friendly_color);
        let king_attackers = self.board.attackers(king_square, opponent_color);
        let checkers = king_attackers.population();
        let in_check = checkers > 0;
        let king_moves = KING_TABLE[king_square.idx()];
        let king_danger_squares = self.board.attacked(!friendly_color, true);

        if checkers > 1 {
            for to in king_moves & empty_squares & !king_danger_squares {
                move_buffer.push(Move::new(king_square, to, QUIET_FLAG));
            }
            return;
        }

        let mut capture_mask = opponent_pieces;
        let mut quiet_mask = empty_squares;

        if checkers == 1 {
            capture_mask = king_attackers;

            let checker_square = king_attackers.bitscan_forward();
            if self.board.piece_at(checker_square).unwrap().ptype.is_slider() {
                quiet_mask = ray_between_squares(king_square, checker_square);
            } else {
                quiet_mask = Bitboard::new(0);
            }
        }

        let not_king_bit = !king_square.bitrep();

        let mut pinned_diagonally = Bitboard::new(0);
        let mut pinned_nondiagonally = Bitboard::new(0);
        {
            let opRQ = self.board.get_pieces(opponent_color, Rook) | self.board.get_pieces(opponent_color, Queen);
            let mut pinner = xray_rook_attacks(all_pieces, friendly_pieces, king_square) & opRQ;
            for pinner_square in pinner {
                let connecting_bits = ray_between_squares(king_square, pinner_square);
                let pinned_bit = connecting_bits & friendly_pieces;
                assert!(pinned_bit.population() == 1);
                pinned_nondiagonally |= pinned_bit;
            }

            let opBQ = self.board.get_pieces(opponent_color, Bishop) | self.board.get_pieces(opponent_color, Queen);
            pinner = xray_bishop_attacks(all_pieces, friendly_pieces, king_square) & opBQ;
            for pinner_square in pinner {
                let connecting_bits = ray_between_squares(king_square, pinner_square);
                let pinned_bit = connecting_bits & friendly_pieces;
                assert!(pinned_bit.population() == 1);
                pinned_diagonally |= pinned_bit;
            }
        }

        let pinned = pinned_diagonally | pinned_nondiagonally;

        // MOVE GENERATION FOR UNPINNED PIECES

        /*********/
        /* PAWNS */
        /*********/
        {
            let unpinned_pawns = self.board.get_pieces(friendly_color, Pawn) & !pinned;
            let advanced_pawns = if friendly_color == White { unpinned_pawns.shifted_up() } else { unpinned_pawns.shifted_down() };
            let double_advanced_pawns = if friendly_color == White { advanced_pawns.shifted_up() } else { advanced_pawns.shifted_down() };
            let delta_pawn_single_push: i32 = if self.to_move == White { -8 } else { 8 };
            let delta_pawn_double_push: i32 = if self.to_move == White { -16 } else { 16 };
            let double_pawn_push_rank = if self.to_move == White { RANK4 } else { RANK5 };
            let promotion_rank = if self.to_move == White { 8 } else { 1 };

            // single pushes (and promotions)
            for to in advanced_pawns & empty_squares & quiet_mask
            {
                let from = Square::new((to.unwrap() as i32 + delta_pawn_single_push) as u32);

                if to.rank() == promotion_rank {
                    move_buffer.push(Move::new(from, to, BISHOP_PROMO_FLAG));
                    move_buffer.push(Move::new(from, to, KNIGHT_PROMO_FLAG));
                    move_buffer.push(Move::new(from, to, ROOK_PROMO_FLAG));
                    move_buffer.push(Move::new(from, to, QUEEN_PROMO_FLAG));
                } else {
                    move_buffer.push(Move::new(from, to, QUIET_FLAG));
                }
            }

            // double pushes
            for to in double_advanced_pawns & empty_squares & double_pawn_push_rank & quiet_mask {

                let from = Square::new((to.unwrap() as i32 + delta_pawn_double_push) as u32);

                move_buffer.push(Move::new(from, to, DOUBLE_PAWN_PUSH_FLAG));
            }

            // captures (and capture-promotions)
            for from in unpinned_pawns
            {
                let pawn_attack_pattern = PAWN_ATTACKS[friendly_color as usize][from.idx()];
                let capturable_squares = match self.ep_square {
                    None => opponent_pieces,
                    Some(ep) => opponent_pieces | ep.bitrep()
                };

                for to in pawn_attack_pattern & capturable_squares & capture_mask
                {
                    if to.rank() == promotion_rank {
                        move_buffer.push(Move::new(from, to, BISHOP_PROMO_CAPTURE_FLAG));
                        move_buffer.push(Move::new(from, to, KNIGHT_PROMO_CAPTURE_FLAG));
                        move_buffer.push(Move::new(from, to, ROOK_PROMO_CAPTURE_FLAG));
                        move_buffer.push(Move::new(from, to, QUEEN_PROMO_CAPTURE_FLAG));
                    } else if self.ep_square.is_some() && self.ep_square.unwrap() == to {
                        // TODO: test for discovered checks after ep capture!
                        move_buffer.push(Move::new(from, to, EP_CAPTURE_FLAG));
                    } else {
                        move_buffer.push(Move::new(from, to, CAPTURE_FLAG));
                    }
                }
            }

        }

        /***********/
        /* KNIGHTS */
        /***********/
        {
            for from in self.board.get_pieces(friendly_color, Knight) & !pinned
            {
                let knight_moves = KNIGHT_TABLE[from.idx()];

                /* quiets */
                for to in knight_moves & empty_squares & quiet_mask {
                    move_buffer.push(Move::new(from, to, QUIET_FLAG));
                }

                /* captures */
                for to in knight_moves & opponent_pieces & capture_mask {
                    move_buffer.push(Move::new(from, to, CAPTURE_FLAG));
                }
            }
        }

        /***********/
        /* BISHOPS */
        /***********/

        for from in self.board.get_pieces(friendly_color, Bishop) & !pinned
        {
            let bishop_moves = get_bishop_rays(from, all_pieces);

            /* quiets */
            for to in bishop_moves & empty_squares & quiet_mask {
                move_buffer.push(Move::new(from, to, QUIET_FLAG));
            }

            /* captures */
            for to in bishop_moves & opponent_pieces & capture_mask {
                move_buffer.push(Move::new(from, to, CAPTURE_FLAG));
            }
        }

        /*********/
        /* ROOKS */
        /*********/

        for from in self.board.get_pieces(friendly_color, Rook) & !pinned
        {
            let rook_moves = get_rook_rays(from, all_pieces);

            /* quiets */
            for to in rook_moves & empty_squares & quiet_mask {
                move_buffer.push(Move::new(from, to, QUIET_FLAG));
            }

            /* captures */
            for to in rook_moves & opponent_pieces & capture_mask {
                move_buffer.push(Move::new(from, to, CAPTURE_FLAG));
            }
        }

        /*********/
        /* QUEEN */
        /*********/

        for from in self.board.get_pieces(friendly_color, Queen) & !pinned
        {
            let queen_moves = get_queen_rays(from, all_pieces);

            /* quiets */
            for to in queen_moves & empty_squares {
                move_buffer.push(Move::new(from, to, QUIET_FLAG));
            }

            /* captures */
            for to in queen_moves & opponent_pieces {
                move_buffer.push(Move::new(from, to, CAPTURE_FLAG));
            }
        }

        /********/
        /* KING */
        /********/

        {
            /* quiets */
            for to in king_moves & empty_squares & !king_danger_squares {
                move_buffer.push(Move::new(king_square, to, QUIET_FLAG));
            }

            /* captures */
            for to in king_moves & opponent_pieces & capture_mask {
                move_buffer.push(Move::new(king_square, to, CAPTURE_FLAG));
            }

            /* castling */
            let has_kingside_castle_rights = self.castling_rights.intersects(CastlingRights::WHITE_KINGSIDE);
            let has_queenside_castle_rights = self.castling_rights.intersects(CastlingRights::WHITE_QUEENSIDE);

            if has_kingside_castle_rights && !in_check {
                let kingside_castle_path_open = (all_pieces & WHITE_KINGSIDE_CASTLE_BITS).empty();

                if kingside_castle_path_open {
                    let mut castle_path_is_safe: bool = true;

                    if (WHITE_KINGSIDE_CASTLE_BITS & king_danger_squares).nonempty() {
                        castle_path_is_safe = false;
                    }

                    if castle_path_is_safe {
                        move_buffer.push(Move::new(king_square, Square::new(1), KING_CASTLE_FLAG));
                    }
                }
            }

            if has_queenside_castle_rights && !in_check {
                let queenside_castle_path_open = (all_pieces & WHITE_QUEENSIDE_CASTLE_BITS).empty();

                if queenside_castle_path_open {
                    let mut castle_path_is_safe: bool = true;

                    if (WHITE_QUEENSIDE_CASTLE_BITS & king_danger_squares).nonempty() {
                        castle_path_is_safe = false;
                    }

                    if castle_path_is_safe {
                        move_buffer.push(Move::new(king_square, Square::new(5), QUEEN_CASTLE_FLAG));
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::borrow::Borrow;
use std::ops::Deref;
use std::hash;
use tendril;

#[derive(Eq, PartialEq, Debug, Clone)]
pub struct Atom(tendril::Tendril<tendril::fmt::UTF8, tendril::Atomic>);

impl hash::Hash for Atom {
    #[inline]
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        let atom_str: &str = &self.0;
        atom_str.hash(state)
    }
}

impl Borrow<str> for Atom {
    #[inline(always)]
    fn borrow(&self) -> &str {
        &self.0
    }
}

impl Deref for Atom {
    type Target = str;
    #[inline(always)]
    fn deref(&self) -> &str {
        &self.0
    }
}

impl<T: AsRef<str>> From<T> for Atom {
    #[inline(always)]
	fn from(from: T) -> Atom {
		Atom(from.as_ref().into())
	}
}

/*
#[cfg(test)]
mod tests {
    use string_cache::Atom;
    use test;
    use std::sync::Arc;
    use tendril;
    use std::collections::HashMap;

    type TheTendril = tendril::Tendril<tendril::fmt::UTF8, tendril::Atomic>;

    #[bench]
    fn bench_atom_into(b: &mut test::Bencher) {
        let items = vec![
            "my_queue_1".to_owned(),
            "my_own_queue_100000".to_owned(),
            "my_longer_queue_name_100001".to_owned()
        ];
        let atoms: Vec<Atom> = items.iter().map(|s| s.into()).collect();
        b.iter(|| {
            for s in &items {
                let atom: Atom = s.into();
                test::black_box(atom);
            }
        });
        test::black_box(atoms);
    }

    #[bench]
    fn bench_arc_string_into(b: &mut test::Bencher) {
        let items = vec![
            "my_queue_1".to_owned(),
            "my_own_queue_100000".to_owned(),
            "my_longer_queue_name_100001".to_owned()
        ];
        b.iter(|| {
            for s in &items {
                test::black_box(Arc::new(s.clone()));
            }
        })
    }

    #[bench]
    fn bench_string_into(b: &mut test::Bencher) {
        let items = vec![
            "my_queue_1".to_owned(),
            "my_own_queue_100000".to_owned(),
            "my_longer_queue_name_100001".to_owned()
        ];
        b.iter(|| {
            for s in &items {
                test::black_box(s.clone());
            }
        })
    }

    #[bench]
    fn bench_sync_tendril_into(b: &mut test::Bencher) {
        let items = vec![
            "my_queue_1".to_owned(),
            "my_own_queue_100000".to_owned(),
            "my_longer_queue_name_100001".to_owned()
        ];
        b.iter(|| {
            for s in &items {
                let tendril_str = TheTendril::from_slice(s.as_ref());
                test::black_box(s);
            }
        })
    }

    #[bench]
    fn bench_atom_hashmap(b: &mut test::Bencher) {
        let items_v = vec![
            "my_queue_1".to_owned(),
            "my_own_queue_100000".to_owned(),
            "my_longer_queue_name_100001".to_owned()
        ];
        let items_hm: HashMap<Atom, _> = items_v.iter().map(
            |s| (s.into(), s.clone())).collect();
        b.iter(|| {
            for s in &items_v {
                let atom: Atom = s.into();
                test::black_box(items_hm.get(&atom));
            }
        });
    }

    #[bench]
    fn bench_tendril_hashmap(b: &mut test::Bencher) {
        let items_v = vec![
            "my_queue".to_owned(),
            "my_own_queue_100000".to_owned(),
            "my_longer_queue_name_100001".to_owned()
        ];
        let items_hm: HashMap<TheTendril, _> = items_v.iter().map(
            |s| (TheTendril::from_slice(s.as_ref()), s.clone())).collect();
        b.iter(|| {
            for s in &items_v {
                let atom: TheTendril = TheTendril::from_slice(s.as_ref());
                test::black_box(items_hm.get(&atom));
            }
        });
    }

    #[bench]
    fn bench_string_hashmap(b: &mut test::Bencher) {
        let items_v = vec![
            "my_queue_1".to_owned(),
            "my_own_queue_100000".to_owned(),
            "my_longer_queue_name_100001".to_owned()
        ];
        let items_hm: HashMap<_, _> = items_v.iter().map(
            |s| (s.clone(), s.clone())).collect();
        b.iter(|| {
            for s in &items_v {
                let string: String = s.clone();
                test::black_box(items_hm.get(&string));
                test::black_box(string);
            }
        });
    }
}
*/<commit_msg>test that atom is borrow compatible with str<commit_after>use std::borrow::Borrow;
use std::ops::Deref;
use std::hash;
use tendril;

#[derive(Eq, PartialEq, Debug, Clone)]
pub struct Atom(tendril::Tendril<tendril::fmt::UTF8, tendril::Atomic>);

impl hash::Hash for Atom {
    #[inline]
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        let atom_str: &str = &self.0;
        atom_str.hash(state)
    }
}

impl Borrow<str> for Atom {
    #[inline(always)]
    fn borrow(&self) -> &str {
        &self.0
    }
}

impl Deref for Atom {
    type Target = str;
    #[inline(always)]
    fn deref(&self) -> &str {
        &self.0
    }
}

impl<T: AsRef<str>> From<T> for Atom {
    #[inline(always)]
	fn from(from: T) -> Atom {
		Atom(from.as_ref().into())
	}
}

#[cfg(test)]
mod tests {
    use super::Atom;
    use std::collections::HashMap;

    #[test]
    fn borrow_str_compatible() {
        let mut hm: HashMap<Atom, _> = HashMap::new();
        hm.insert("key1".into(), 1);
        hm.insert("key2".into(), 2);
        assert_eq!(hm.get("key1"), Some(&1));
        assert_eq!(hm.get("key2"), Some(&2));
    }
}

/*
#[cfg(test)]
mod benchs {
    // use string_cache::Atom;
    use super::Atom;
    use test;
    use std::sync::Arc;
    use tendril;
    use std::collections::HashMap;

    type TheTendril = tendril::Tendril<tendril::fmt::UTF8, tendril::Atomic>;

    #[bench]
    fn bench_atom_into(b: &mut test::Bencher) {
        let items = vec![
            "my_queue_1".to_owned(),
            "my_own_queue_100000".to_owned(),
            "my_longer_queue_name_100001".to_owned()
        ];
        let atoms: Vec<Atom> = items.iter().map(|s| s.into()).collect();
        b.iter(|| {
            for s in &items {
                let atom: Atom = s.into();
                test::black_box(atom);
            }
        });
        test::black_box(atoms);
    }

    #[bench]
    fn bench_arc_string_into(b: &mut test::Bencher) {
        let items = vec![
            "my_queue_1".to_owned(),
            "my_own_queue_100000".to_owned(),
            "my_longer_queue_name_100001".to_owned()
        ];
        b.iter(|| {
            for s in &items {
                test::black_box(Arc::new(s.clone()));
            }
        })
    }

    #[bench]
    fn bench_string_into(b: &mut test::Bencher) {
        let items = vec![
            "my_queue_1".to_owned(),
            "my_own_queue_100000".to_owned(),
            "my_longer_queue_name_100001".to_owned()
        ];
        b.iter(|| {
            for s in &items {
                test::black_box(s.clone());
            }
        })
    }

    #[bench]
    fn bench_sync_tendril_into(b: &mut test::Bencher) {
        let items = vec![
            "my_queue_1".to_owned(),
            "my_own_queue_100000".to_owned(),
            "my_longer_queue_name_100001".to_owned()
        ];
        b.iter(|| {
            for s in &items {
                let tendril_str = TheTendril::from_slice(s.as_ref());
                test::black_box(tendril_str);
            }
        })
    }

    #[bench]
    fn bench_atom_clone(b: &mut test::Bencher) {
        let items: Vec<Atom> = vec![
            "my_queue_1".into(),
            "my_own_queue_100000".into(),
            "my_longer_queue_name_100001".into()
        ];
        b.iter(|| {
            for s in &items {
                test::black_box(s.clone());
            }
        })
    }

    #[bench]
    fn bench_atom_hashmap(b: &mut test::Bencher) {
        let items_v = vec![
            "my_queue_1".to_owned(),
            "my_own_queue_100000".to_owned(),
            "my_longer_queue_name_100001".to_owned()
        ];
        let items_hm: HashMap<Atom, _> = items_v.iter().map(
            |s| (s.into(), s.clone())).collect();
        b.iter(|| {
            for s in &items_v {
                let atom: Atom = s.into();
                test::black_box(items_hm.get(&atom));
            }
        });
    }

    #[bench]
    fn bench_tendril_hashmap(b: &mut test::Bencher) {
        let items_v = vec![
            "my_queue".to_owned(),
            "my_own_queue_100000".to_owned(),
            "my_longer_queue_name_100001".to_owned()
        ];
        let items_hm: HashMap<TheTendril, _> = items_v.iter().map(
            |s| (TheTendril::from_slice(s.as_ref()), s.clone())).collect();
        b.iter(|| {
            for s in &items_v {
                let atom: TheTendril = TheTendril::from_slice(s.as_ref());
                test::black_box(items_hm.get(&atom));
            }
        });
    }

    #[bench]
    fn bench_string_hashmap(b: &mut test::Bencher) {
        let items_v = vec![
            "my_queue_1".to_owned(),
            "my_own_queue_100000".to_owned(),
            "my_longer_queue_name_100001".to_owned()
        ];
        let items_hm: HashMap<_, _> = items_v.iter().map(
            |s| (s.clone(), s.clone())).collect();
        b.iter(|| {
            for s in &items_v {
                let string: String = s.clone();
                test::black_box(items_hm.get(&string));
                test::black_box(string);
            }
        });
    }
}
*/<|endoftext|>


<commit_before>use crate::hb;
use std;
use std::os::raw::c_void;
use std::ptr::NonNull;

use std::marker::PhantomData;
use std::path::Path;

use crate::blob::Blob;
use crate::common::{HarfbuzzObject, Owned, Shared, Tag};

/// A wrapper around `hb_face_t`.
///
/// An excerpt from harfbuzz documentation:
/// > Font face is objects represent a single face in a font family. More
/// > exactly, a font face represents a single face in a binary font file. Font
/// > faces are typically built from a binary blob and a face index. Font faces
/// > are used to create fonts.
#[derive(Debug)]
pub struct Face<'a> {
    raw: NonNull<hb::hb_face_t>,
    marker: PhantomData<&'a [u8]>,
}

impl<'a> Face<'a> {
    /// Create a new `Face` from the data.
    ///
    /// If `data` is not a valid font then this function returns the empty face.
    pub fn new<T: Into<Shared<Blob<'a>>>>(data: T, index: u32) -> Owned<Face<'a>> {
        let blob = data.into();
        let hb_face = unsafe { hb::hb_face_create(blob.as_raw(), index) };
        unsafe { Owned::from_raw(hb_face) }
    }

    /// Returns a "null" face.
    pub fn empty() -> Owned<Face<'static>> {
        let hb_face = unsafe { hb::hb_face_get_empty() };
        unsafe { Owned::from_raw(hb_face) }
    }

    /// Create a new face from the contents of the file at `path`.
    ///
    /// This function reads the contents of the file at `path` into memory,
    /// creates a `Blob` and then calls `Face::new`.
    ///
    /// See also the discussion in `Blob::from_file`.
    pub fn from_file<P: AsRef<Path>>(path: P, index: u32) -> std::io::Result<Owned<Face<'static>>> {
        let blob = Blob::from_file(path)?;
        Ok(Face::new(blob, index))
    }

    /// Create a face from the bytes of a given slice and an index specifying
    /// which font to read from an OpenType font collection.
    pub fn from_bytes<'b>(bytes: &'b [u8], index: u32) -> Owned<Face<'b>> {
        let blob = Blob::with_bytes(bytes);
        Face::new(blob, index)
    }

    /// Create a new face from a closure that returns a raw
    /// [`Blob`](struct.Blob.html) of table data.
    pub fn from_table_func<'b, F>(func: F) -> Owned<Face<'b>>
    where
        F: 'b + Send + Sync + FnMut(Tag) -> Option<Shared<Blob<'b>>>,
    {
        extern "C" fn destroy_box<U>(ptr: *mut c_void) {
            unsafe { Box::from_raw(ptr as *mut U) };
        }
        extern "C" fn table_func<'b, F>(
            _: *mut hb::hb_face_t,
            tag: hb::hb_tag_t,
            user_data: *mut c_void,
        ) -> *mut hb::hb_blob_t
        where
            F: FnMut(Tag) -> Option<Shared<Blob<'b>>>,
        {
            let tag = Tag(tag);
            let closure = unsafe { &mut *(user_data as *mut F) };
            let blob = closure(tag);
            match blob {
                Some(blob) => Shared::into_raw(blob),
                None => std::ptr::null_mut(),
            }
        }
        let boxed_closure = Box::new(func);
        unsafe {
            let face = hb::hb_face_create_for_tables(
                Some(table_func::<'b, F>),
                Box::into_raw(boxed_closure) as *mut _,
                Some(destroy_box::<F>),
            );
            Owned::from_raw(face)
        }
    }

    pub fn face_data(&self) -> Shared<Blob<'a>> {
        unsafe {
            let raw_blob = hb::hb_face_reference_blob(self.as_raw());
            Shared::from_raw_owned(raw_blob)
        }
    }

    /// Returns the slice of bytes for the table named `tag` or None if there is
    /// no table with `tag`.
    pub fn table_with_tag(&self, tag: impl Into<Tag>) -> Option<Shared<Blob<'a>>> {
        unsafe {
            let raw_blob = hb::hb_face_reference_table(self.as_raw(), tag.into().0);
            if raw_blob.is_null() {
                None
            } else {
                let blob: Shared<Blob<'_>> = Shared::from_raw_owned(raw_blob);
                if blob.is_empty() {
                    None
                } else {
                    Some(blob)
                }
            }
        }
    }

    pub fn index(&self) -> u32 {
        unsafe { hb::hb_face_get_index(self.as_raw()) }
    }

    pub fn set_upem(&mut self, upem: u32) {
        unsafe { hb::hb_face_set_upem(self.as_raw(), upem) };
    }

    pub fn upem(&self) -> u32 {
        unsafe { hb::hb_face_get_upem(self.as_raw()) }
    }

    pub fn set_glyph_count(&mut self, count: u32) {
        unsafe { hb::hb_face_set_glyph_count(self.as_raw(), count) };
    }

    /// Returns the number of glyphs contained in the face.
    pub fn glyph_count(&self) -> u32 {
        unsafe { hb::hb_face_get_glyph_count(self.as_raw()) }
    }
}

unsafe impl<'a> HarfbuzzObject for Face<'a> {
    type Raw = hb::hb_face_t;

    unsafe fn from_raw(raw: *const hb::hb_face_t) -> Self {
        Face {
            raw: NonNull::new(raw as *mut _).unwrap(),
            marker: PhantomData,
        }
    }

    fn as_raw(&self) -> *mut Self::Raw {
        self.raw.as_ptr()
    }

    unsafe fn reference(&self) {
        hb::hb_face_reference(self.as_raw());
    }

    unsafe fn dereference(&self) {
        hb::hb_face_destroy(self.as_raw());
    }
}

unsafe impl<'a> Send for Face<'a> {}
unsafe impl<'a> Sync for Face<'a> {}

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

    #[test]
    fn test_face_from_table_func() {
        let face = Face::from_table_func(|table_tag| {
            let content = format!("{}-table", table_tag);
            Some(content.into_bytes().into())
        });

        let maxp_table = face.table_with_tag(b"maxp").unwrap();
        assert_eq!(maxp_table.as_ref(), b"maxp-table");

        let maxp_table = face.table_with_tag(b"hhea").unwrap();
        assert_eq!(&maxp_table.as_ref(), b"hhea-table");
    }
}
<commit_msg>Add variation support<commit_after>use crate::hb;
use std;
use std::os::raw::c_void;
use std::ptr::NonNull;

use std::marker::PhantomData;
use std::path::Path;

use crate::blob::Blob;
use crate::common::{HarfbuzzObject, Owned, Shared, Tag};

/// A wrapper around `hb_face_t`.
///
/// An excerpt from harfbuzz documentation:
/// > Font face is objects represent a single face in a font family. More
/// > exactly, a font face represents a single face in a binary font file. Font
/// > faces are typically built from a binary blob and a face index. Font faces
/// > are used to create fonts.
#[derive(Debug)]
pub struct Face<'a> {
    raw: NonNull<hb::hb_face_t>,
    marker: PhantomData<&'a [u8]>,
}

impl<'a> Face<'a> {
    /// Create a new `Face` from the data.
    ///
    /// If `data` is not a valid font then this function returns the empty face.
    pub fn new<T: Into<Shared<Blob<'a>>>>(data: T, index: u32) -> Owned<Face<'a>> {
        let blob = data.into();
        let hb_face = unsafe { hb::hb_face_create(blob.as_raw(), index) };
        unsafe { Owned::from_raw(hb_face) }
    }

    /// Returns a "null" face.
    pub fn empty() -> Owned<Face<'static>> {
        let hb_face = unsafe { hb::hb_face_get_empty() };
        unsafe { Owned::from_raw(hb_face) }
    }

    /// Create a new face from the contents of the file at `path`.
    ///
    /// This function reads the contents of the file at `path` into memory,
    /// creates a `Blob` and then calls `Face::new`.
    ///
    /// See also the discussion in `Blob::from_file`.
    pub fn from_file<P: AsRef<Path>>(path: P, index: u32) -> std::io::Result<Owned<Face<'static>>> {
        let blob = Blob::from_file(path)?;
        Ok(Face::new(blob, index))
    }

    /// Create a face from the bytes of a given slice and an index specifying
    /// which font to read from an OpenType font collection.
    pub fn from_bytes<'b>(bytes: &'b [u8], index: u32) -> Owned<Face<'b>> {
        let blob = Blob::with_bytes(bytes);
        Face::new(blob, index)
    }

    /// Create a new face from a closure that returns a raw
    /// [`Blob`](struct.Blob.html) of table data.
    pub fn from_table_func<'b, F>(func: F) -> Owned<Face<'b>>
    where
        F: 'b + Send + Sync + FnMut(Tag) -> Option<Shared<Blob<'b>>>,
    {
        extern "C" fn destroy_box<U>(ptr: *mut c_void) {
            unsafe { Box::from_raw(ptr as *mut U) };
        }
        extern "C" fn table_func<'b, F>(
            _: *mut hb::hb_face_t,
            tag: hb::hb_tag_t,
            user_data: *mut c_void,
        ) -> *mut hb::hb_blob_t
        where
            F: FnMut(Tag) -> Option<Shared<Blob<'b>>>,
        {
            let tag = Tag(tag);
            let closure = unsafe { &mut *(user_data as *mut F) };
            let blob = closure(tag);
            match blob {
                Some(blob) => Shared::into_raw(blob),
                None => std::ptr::null_mut(),
            }
        }
        let boxed_closure = Box::new(func);
        unsafe {
            let face = hb::hb_face_create_for_tables(
                Some(table_func::<'b, F>),
                Box::into_raw(boxed_closure) as *mut _,
                Some(destroy_box::<F>),
            );
            Owned::from_raw(face)
        }
    }

    pub fn face_data(&self) -> Shared<Blob<'a>> {
        unsafe {
            let raw_blob = hb::hb_face_reference_blob(self.as_raw());
            Shared::from_raw_owned(raw_blob)
        }
    }

    /// Returns the slice of bytes for the table named `tag` or None if there is
    /// no table with `tag`.
    pub fn table_with_tag(&self, tag: impl Into<Tag>) -> Option<Shared<Blob<'a>>> {
        unsafe {
            let raw_blob = hb::hb_face_reference_table(self.as_raw(), tag.into().0);
            if raw_blob.is_null() {
                None
            } else {
                let blob: Shared<Blob<'_>> = Shared::from_raw_owned(raw_blob);
                if blob.is_empty() {
                    None
                } else {
                    Some(blob)
                }
            }
        }
    }

    pub fn index(&self) -> u32 {
        unsafe { hb::hb_face_get_index(self.as_raw()) }
    }

    pub fn set_upem(&mut self, upem: u32) {
        unsafe { hb::hb_face_set_upem(self.as_raw(), upem) };
    }

    pub fn upem(&self) -> u32 {
        unsafe { hb::hb_face_get_upem(self.as_raw()) }
    }

    pub fn set_glyph_count(&mut self, count: u32) {
        unsafe { hb::hb_face_set_glyph_count(self.as_raw(), count) };
    }

    /// Returns the number of glyphs contained in the face.
    pub fn glyph_count(&self) -> u32 {
        unsafe { hb::hb_face_get_glyph_count(self.as_raw()) }
    }

    #[cfg(variation_support)]
    pub fn get_variation_axis_infos(&self) -> Vec<VariationAxisInfo> {
        let mut count = unsafe { hb::hb_ot_var_get_axis_count(self.as_raw()) };
        let mut vector: Vec<VariationAxisInfo> = Vec::with_capacity(count as usize);
        unsafe {
            hb::hb_ot_var_get_axis_infos(
                self.as_raw(),
                0,
                &mut count,
                vector.as_mut_ptr() as *mut _,
            )
        };
        unsafe { vector.set_len(count as usize) };
        vector
    }
}

#[cfg(variation_support)]
#[derive(Debug, Clone, Copy)]
#[repr(transparent)]
pub struct VariationAxisInfo(pub hb::hb_ot_var_axis_info_t);

unsafe impl<'a> HarfbuzzObject for Face<'a> {
    type Raw = hb::hb_face_t;

    unsafe fn from_raw(raw: *const hb::hb_face_t) -> Self {
        Face {
            raw: NonNull::new(raw as *mut _).unwrap(),
            marker: PhantomData,
        }
    }

    fn as_raw(&self) -> *mut Self::Raw {
        self.raw.as_ptr()
    }

    unsafe fn reference(&self) {
        hb::hb_face_reference(self.as_raw());
    }

    unsafe fn dereference(&self) {
        hb::hb_face_destroy(self.as_raw());
    }
}

unsafe impl<'a> Send for Face<'a> {}
unsafe impl<'a> Sync for Face<'a> {}

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

    #[test]
    fn test_face_from_table_func() {
        let face = Face::from_table_func(|table_tag| {
            let content = format!("{}-table", table_tag);
            Some(content.into_bytes().into())
        });

        let maxp_table = face.table_with_tag(b"maxp").unwrap();
        assert_eq!(maxp_table.as_ref(), b"maxp-table");

        let maxp_table = face.table_with_tag(b"hhea").unwrap();
        assert_eq!(&maxp_table.as_ref(), b"hhea-table");
    }
}
<|endoftext|>


<commit_before>fn each(v: &mut [u32], op: &fn(v: &mut u32)) {
	let mut n = 0;
	while n < v.len() {
		op(&mut v[n]);
		n += 1;
	}
}

struct Beta {
	pc:			u32,
	register:	[u32, ..31],
	memory:		[u8, ..4096]
}

impl Beta {
	fn reset(&mut self) {
		self.pc = 0;
		do each(self.register) |r| { *r = 0; }

		//println(fmt!("reset. pc at %d", self.pc as int));
	}

	fn tick(&self) {
		//println(fmt!("tick. pc at %d", self.pc as int));

	}
}

fn main() {
	let mut b = ~Beta { pc: 10u32, register: [3u32, ..31], memory: [0u8, ..4*1024] };
	b.reset();
	b.tick();
	println("success");
}
<commit_msg>PC increments.<commit_after>fn each(v: &mut [u32], op: &fn(v: &mut u32)) {
	let mut n = 0;
	while n < v.len() {
		op(&mut v[n]);
		n += 1;
	}
}

struct Beta {
	pc:			u32,
	register:	[u32, ..31],
	memory:		[u8, ..4096]
}

impl Beta {
	fn reset(&mut self) {
		self.pc = 0;
		do each(self.register) |r| { *r = 0; }

		//println(fmt!("reset. pc at %d", self.pc as int));
	}

	fn tick(&mut self) {
		self.pc += 4;
		//println(fmt!("tick. pc at %d", self.pc as int));
	}
}

fn main() {
	let mut b = ~Beta { pc: 10u32, register: [3u32, ..31], memory: [0u8, ..4*1024] };
	b.reset();
	b.tick();
	println("success");
}
<|endoftext|>


<commit_before>use super::math::Vec2;
use super::shape::shape::Shape;

#[derive(Clone)]
pub enum BodyType {
	StaticBody,
	KinematicBody,
	DynamicBody
}

pub struct BodyDef {
	body_type: BodyType,
	position: Vec2,
	angle: f32,
}

#[derive(Clone)]
pub struct Body {
	pub shape: Shape,
	pub body_type: BodyType,
	pub position: Vec2,
	pub velocity: Vec2,
	pub restitution: f32,
	pub mass: f32
}

impl Body {
	pub fn integrate(&mut self, timeStep: f32) {
		if self.mass <= 0.0 {
			return;
		}
		let inv_mass = 1.0 / self.mass;
		if inv_mass > 0.0 && timeStep > 0.0 {
			//Add gravity to the object;
			let force_accum = Vec2::new(0.0, 3.0);

			let total_accel = force_accum.multiply(inv_mass);
			self.velocity = self.velocity + total_accel.multiply(timeStep);
			self.position = self.position + self.velocity.multiply(timeStep);
		}
	}
}
<commit_msg>Testing inv_mass for nan and infinity<commit_after>use super::math::Vec2;
use super::shape::shape::Shape;

#[derive(Clone)]
pub enum BodyType {
	StaticBody,
	KinematicBody,
	DynamicBody
}

pub struct BodyDef {
	body_type: BodyType,
	position: Vec2,
	angle: f32,
}

#[derive(Clone)]
pub struct Body {
	pub shape: Shape,
	pub body_type: BodyType,
	pub position: Vec2,
	pub velocity: Vec2,
	pub restitution: f32,
	pub mass: f32
}

impl Body {
	pub fn integrate(&mut self, timeStep: f32) {
		if self.mass <= 0.0 {
			return;
		}
		let inv_mass = 1.0 / self.mass;
		if !inv_mass.is_nan() && !inv_mass.is_infinite() && inv_mass > 0.0 && timeStep > 0.0 {
			//Add gravity to the object;
			let force_accum = Vec2::new(0.0, 3.0);

			let total_accel = force_accum.multiply(inv_mass);
			self.velocity = self.velocity + total_accel.multiply(timeStep);
			self.position = self.position + self.velocity.multiply(timeStep);
		}
	}
}
<|endoftext|>