<commit_before>use std::collections::{HashMap, HashSet};
use std::rc::Rc;

#[derive(Debug, PartialEq, Clone)]
pub enum CC {
    // condition codes
    E, L, LE, G, GE,
}

#[derive(Debug, Clone)]
pub enum Ast {
    Symbol(Rc<String>),
    Number(i64),
    Bool(bool),
    List(Vec<Ast>),
    FuncName(Rc<String>),  // for closure-conversion

    Define(Rc<String>, Vec<Rc<String>>, Box<Ast>),
    If(Box<Ast>,     // cnd
       Box<Ast>,     // thn
       Box<Ast>),    // els
    Let(Vec<(Rc<String>, Ast)>, Box<Ast>),
    Lambda(Vec<Rc<String>>, Box<Ast>),
    Tuple(Vec<Ast>),
    Cmp(CC, Box<Ast>, Box<Ast>),
    App(Box<Ast>, Vec<Ast>),
    Prog(Vec<Ast>, Box<Ast>),
    Nil,
}

static mut VAR_COUNTER : i32 = 0;
pub fn get_unique_varname(stem: &str) -> String {
    unsafe {
        VAR_COUNTER += 1;
        return stem.to_string() + &VAR_COUNTER.to_string();
    }
}

impl Ast {
    pub fn uniquify(&self, mapping: &mut HashMap<Rc<String>, Rc<String>>) -> Self {
        match self {
            Ast::Symbol(name) => {
                let uniq_name = mapping.get(name)
                    .expect("unbound symbol");
                Ast::Symbol(uniq_name.clone())
            },
            Ast::Number(_) | Ast::Bool(_) => self.clone(),
            Ast::Tuple(elts) => {
                let elts =
                    elts.iter().map(|e| e.uniquify(mapping)).collect();
                Ast::Tuple(elts)
            },
            Ast::Let(bindings, body) => {
                let mut new_bindings = vec![];
                for (k, v) in bindings {
                    let uniq_k = Rc::new(get_unique_varname(&k));
                    new_bindings.push((uniq_k.clone(),
                                       v.uniquify(mapping)));
                    mapping.insert(k.clone(), uniq_k.clone());

                }
                Ast::Let(new_bindings,
                         Box::new(body.uniquify(mapping)))
            },
            Ast::List(elts) => {
                let new_elts : Vec<_> = elts.iter().map(|e| e.uniquify(mapping)).collect();
                Ast::List(new_elts)
            },
            Ast::Cmp(cc, left, right) =>
                return Ast::Cmp(cc.clone(),
                                box left.uniquify(mapping),
                                box right.uniquify(mapping)),
            Ast::Lambda(args, body) => {
                let mut new_args = vec![];
                for arg in args {
                    let new_arg = Rc::new(get_unique_varname(arg));
                    new_args.push(new_arg.clone());
                    mapping.insert(arg.clone(), new_arg.clone());
                }

                 Ast::Lambda(new_args,
                             box body.uniquify(mapping))
            },
            Ast::Define(name, args, val) => {
                let uniq_fname = Rc::new(get_unique_varname(name));
                mapping.insert(name.clone(), uniq_fname.clone());

                let mut new_args = vec![];
                for arg in args {
                    let new_arg = Rc::new(get_unique_varname(arg));
                    new_args.push(new_arg.clone());
                    mapping.insert(arg.clone(), new_arg.clone());
                }

                Ast::Define(uniq_fname.clone(),
                            new_args,
                            box val.uniquify(mapping))
            },
            Ast::If(cond, thn, els) =>
                Ast::If(box (cond.uniquify(mapping)),
                        box (thn.uniquify(mapping)),
                        box (els.uniquify(mapping))),
            Ast::App(f, args) => {
                let new_args : Vec<_> = args.iter()
                    .map(|a| a.uniquify(mapping)).collect();
                Ast::App(box f.uniquify(mapping),
                         new_args)
            },
            Ast::Prog(defs, e) => {
                let new_defs : Vec<_> = defs.iter()
                    .map(|def| def.uniquify(mapping)).collect();
                Ast::Prog(new_defs, box e.uniquify(mapping))
            },
            _ => panic!("NYI"),
        }
    }

    fn get_free_variables(&self,
                          env: &HashSet<Rc<String>>,
                          parent_env: &HashSet<Rc<String>>) -> Vec<Rc<String>> {
        match self {
            Ast::Number(_) => vec![],
            Ast::Symbol(name) => {
                match env.get(name) {
                    Some(_) => vec![],
                    None => {
                        match parent_env.get(name) {
                            Some(_) => vec![name.clone()],
                            None => panic!("no binding found in parent env for free-variable {} env: {:?} parent-env: {:?}", name, env, parent_env),
                        }
                    }
                }
            },
            Ast::If(cnd, thn, els) => {
                let mut cnd_freevars =
                    cnd.get_free_variables(env, parent_env);
                let thn_freevars =
                    thn.get_free_variables(env, parent_env);
                let els_freevars =
                    els.get_free_variables(env, parent_env);

                cnd_freevars.extend_from_slice(&thn_freevars);
                cnd_freevars.extend_from_slice(&els_freevars);

                return cnd_freevars;
            },
            Ast::Define(_, args, body) |
            Ast::Lambda(args, body) => {
                let mut new_parent_env : HashSet<Rc<String>> = HashSet::new()
                    .union(&env).cloned().collect();
                new_parent_env = new_parent_env
                    .union(&parent_env).cloned().collect();

                let new_env : HashSet<Rc<String>> = args.iter().map(|a| a.clone()).collect();

                println!("[lambda] new_env: {:?} new_parent_env: {:?}",
                         new_env,
                         new_parent_env);

                body.get_free_variables(&new_env, &new_parent_env)
            },
            Ast::Let(bindings, body) => {
                let mut new_env = HashSet::new();
                let mut bindings_free_vars = vec![];
                for (k, v) in bindings {
                    let v_freevars : Vec<_> =
                        v.get_free_variables(env, parent_env);
                    new_env.insert(k.clone());
                    bindings_free_vars.extend_from_slice(&v_freevars);
                }

                new_env = new_env.union(&env).cloned().collect();
                let body_freevars : Vec<_> =
                    body.get_free_variables(&new_env,
                                            parent_env);
                bindings_free_vars.extend_from_slice(&body_freevars);

                return bindings_free_vars;
            },
            Ast::App(_, args) => {
                let mut args_freevars = vec![];
                for arg in args {
                    let arg_freevars : Vec<_> =
                        arg.get_free_variables(env,
                                               parent_env);
                    args_freevars.extend_from_slice(&arg_freevars);
                }

                return args_freevars;
            },
            _ => panic!("NYI: {:?}", self),
        }
    }

    fn symbol_is_primitive(sym: &str) -> bool {
        match sym {
            "+" | "-" | "tuple-ref" | "tuple" => true,
            _ => false,
        }
    }

    fn get_define_name(def: &Ast) -> Rc<String> {
        match def {
            Ast::Define(name, _, _) => name.clone(),
            _ => panic!("not a Define"),
        }
    }

    /// Converts a lambda into a top-level define'd function. For all
    /// functions, adds a closure arg, and updates function
    /// applications to pass the closure arg. The `clos` arg is a
    /// tuple (f, a1, ..., an) capturing free variables.
    pub fn convert_to_closures(&self, env: &HashSet<Rc<String>>, toplevel_funs: &HashSet<Rc<String>>)
                           -> (Ast, Vec<Ast>) {
        match self {
            Ast::Cmp(_, _, _) |
            Ast::Bool(_) |
            Ast::Symbol(_) |
            Ast::FuncName(_) |
            Ast::Number(_) => (self.clone(), vec![]),
            Ast::If(cnd, thn, els) => {
                let (converted_cnd, mut cnd_defines) =
                    cnd.convert_to_closures(env, toplevel_funs);
                let (converted_thn, thn_defines) =
                    thn.convert_to_closures(env, toplevel_funs);
                let (converted_els, els_defines) =
                    els.convert_to_closures(env, toplevel_funs);

                let converted = Ast::If(box converted_cnd,
                                        box converted_thn,
                                        box converted_els);

                cnd_defines.extend_from_slice(&thn_defines);
                cnd_defines.extend_from_slice(&els_defines);

                return (converted, cnd_defines);
            },
            Ast::Define(name, args, body) => {
                let mut new_args = args.clone();
                let mut new_env = env.clone();

                for arg in args {
                    new_env.insert(arg.clone());
                }
                let (converted_body, body_defines) =
                    body.convert_to_closures(&new_env, toplevel_funs);

                new_args.insert(0, Rc::new("clos".to_string()));

                let converted = Ast::Define(name.clone(),
                                            new_args,
                                            box converted_body);

                return (converted, body_defines);

            },
            Ast::Lambda(args, body) => {
                let mut new_env = HashSet::new();
                let mut new_args = args.clone();
                for arg in args {
                    new_env.insert(arg.clone());
                }

                let (converted_body, mut new_defines) =
                    body.convert_to_closures(&new_env, toplevel_funs);

                let lambda_name = Rc::new(get_unique_varname("lam"));
                let free_vars : Vec<_> = body.get_free_variables(&new_env,
                                                                 env);
                let mut load_free_vars = converted_body;
                for (i, fvar) in free_vars.iter().enumerate() {
                    let bindings = vec![(fvar.clone(),
                                         Ast::App(box Ast::Symbol(Rc::new("tuple-ref".to_string())),
                                                  vec![Ast::Symbol(Rc::new("clos".to_string())),
                                                       Ast::Number((i+1) as i64)]))];
                    load_free_vars =
                        Ast::Let(bindings,
                                 box load_free_vars);
                }

                new_args.insert(0, Rc::new("clos".to_string()));

                let mut closure_elts =
                    vec![Ast::FuncName(lambda_name.clone())];

                let free_vars : Vec<Ast> =
                    free_vars.iter().map(|fv| Ast::Symbol(fv.clone())).collect();
                closure_elts.extend_from_slice(&free_vars[..]);
                let closure = Ast::Tuple(closure_elts);

                new_defines.extend_from_slice(&[
                    Ast::Define(lambda_name.clone(),
                                new_args,
                                box load_free_vars)
                ]);

                return (closure, new_defines);
            },
            Ast::Tuple(elts) => {
                let mut converted_elts = vec![];
                let mut elts_defines = vec![];

                for elt in elts {
                    let (conv_elt, elt_defines) : (Ast, Vec<Ast>) =
                        elt.convert_to_closures(env, toplevel_funs);
                    converted_elts.push(conv_elt);
                    elts_defines.extend_from_slice(&elt_defines);
                }

                let converted = Ast::Tuple(converted_elts);
                return (converted, elts_defines);

            },
            Ast::App(box Ast::Symbol(f), ref args)
                if Self::symbol_is_primitive(f) => {
                    let mut converted_args = vec![];
                    let mut args_defines = vec![];

                    for arg in args.clone() {
                        let (conv_arg, arg_defines) : (Ast, Vec<Ast>) =
                            arg.convert_to_closures(env, toplevel_funs);
                        converted_args.push(conv_arg);
                        args_defines.extend_from_slice(&arg_defines);
                    }

                    let converted = Ast::App(box Ast::Symbol(f.clone()),
                                             converted_args);
                    return (converted, args_defines);
                },
            Ast::App(box Ast::Symbol(f), ref args)
                if !Self::symbol_is_primitive(f) => {
                    let fname = match toplevel_funs.get(f) {
                        Some(_) => Ast::Tuple(vec![Ast::FuncName(f.clone())]),
                        None => Ast::Symbol(f.clone()),
                    };

                    let (fclos, fdefines) : (Ast, Vec<Ast>) =
                        fname.convert_to_closures(env, toplevel_funs);
                    let f_temp = Rc::new(get_unique_varname("tmp"));

                    let mut converted_args =
                        vec![Ast::Symbol(f_temp.clone())];
                    let mut args_defines = vec![];

                    for arg in args {
                        let (conv_arg, arg_defines) : (Ast, Vec<Ast>) =
                            arg.convert_to_closures(env, toplevel_funs);
                        converted_args.push(conv_arg);
                        args_defines.extend_from_slice(&arg_defines);
                    }

                    args_defines.extend_from_slice(&fdefines);

                    let converted = Ast::Let(vec![(f_temp.clone(), fclos)],
                                               box Ast::App(
                                                   box Ast::App(box Ast::Symbol(Rc::new("tuple-ref".to_string())),
                                                                vec![Ast::Symbol(f_temp),
                                                                     Ast::Number(0)]),
                                                   converted_args));
                    return (converted, args_defines);
                },
            Ast::Let(bindings, body) => {
                let mut new_bindings = vec![];
                let mut bindings_defines = vec![];
                let mut new_env = env.clone();

                for (k, v) in bindings {
                    let (converted_v, v_defines) : (Ast, Vec<Ast>) =
                        v.convert_to_closures(env, toplevel_funs);

                    new_env.insert(k.clone());
                    new_bindings.push((k.clone(), converted_v));
                    bindings_defines.extend_from_slice(&v_defines);
                };

                let (converted_body, body_defines) : (Ast, Vec<Ast>) =
                    body.convert_to_closures(&new_env, toplevel_funs);

                bindings_defines.extend_from_slice(&body_defines);

                let converted = Ast::Let(new_bindings,
                                         box converted_body);
                return (converted, bindings_defines);
            },
            Ast::Prog(defines, main) => {
                let mut converted_defines = vec![];
                let mut defines_new_defines = vec![];
                let mut toplevel_funs = toplevel_funs.clone();

                for def in defines {
                    toplevel_funs.insert(Self::get_define_name(&def));
                    let (converted_define, new_defines) : (Ast, Vec<Ast>) =
                        def.convert_to_closures(env, &toplevel_funs);

                    converted_defines.push(converted_define);
                    defines_new_defines.extend_from_slice(&new_defines);
                }

                let (converted_main, main_defines) : (Ast, Vec<Ast>) =
                    main.convert_to_closures(env, &toplevel_funs);

                converted_defines.extend_from_slice(&defines_new_defines);
                converted_defines.extend_from_slice(&main_defines);

                let converted = Ast::Prog(converted_defines,
                                            box converted_main);

                return (converted, vec![]);
            },
            _ => panic!("NYI: {:?}", self),
        }
    }
}
<commit_msg>FIX: Remove copy of `get_unique_varname`<commit_after>use std::collections::{HashMap, HashSet};
use std::rc::Rc;

use util::get_unique_varname;

#[derive(Debug, PartialEq, Clone)]
pub enum CC {
    // condition codes
    E, L, LE, G, GE,
}

#[derive(Debug, Clone)]
pub enum Ast {
    Symbol(Rc<String>),
    Number(i64),
    Bool(bool),
    List(Vec<Ast>),
    FuncName(Rc<String>),  // for closure-conversion

    Define(Rc<String>, Vec<Rc<String>>, Box<Ast>),
    If(Box<Ast>,     // cnd
       Box<Ast>,     // thn
       Box<Ast>),    // els
    Let(Vec<(Rc<String>, Ast)>, Box<Ast>),
    Lambda(Vec<Rc<String>>, Box<Ast>),
    Tuple(Vec<Ast>),
    Cmp(CC, Box<Ast>, Box<Ast>),
    App(Box<Ast>, Vec<Ast>),
    Prog(Vec<Ast>, Box<Ast>),
    Nil,
}

impl Ast {
    pub fn uniquify(&self, mapping: &mut HashMap<Rc<String>, Rc<String>>) -> Self {
        match self {
            Ast::Symbol(name) => {
                let uniq_name = mapping.get(name)
                    .expect("unbound symbol");
                Ast::Symbol(uniq_name.clone())
            },
            Ast::Number(_) | Ast::Bool(_) => self.clone(),
            Ast::Tuple(elts) => {
                let elts =
                    elts.iter().map(|e| e.uniquify(mapping)).collect();
                Ast::Tuple(elts)
            },
            Ast::Let(bindings, body) => {
                let mut new_bindings = vec![];
                for (k, v) in bindings {
                    let uniq_k = Rc::new(get_unique_varname(&k));
                    new_bindings.push((uniq_k.clone(),
                                       v.uniquify(mapping)));
                    mapping.insert(k.clone(), uniq_k.clone());

                }
                Ast::Let(new_bindings,
                         Box::new(body.uniquify(mapping)))
            },
            Ast::List(elts) => {
                let new_elts : Vec<_> = elts.iter().map(|e| e.uniquify(mapping)).collect();
                Ast::List(new_elts)
            },
            Ast::Cmp(cc, left, right) =>
                return Ast::Cmp(cc.clone(),
                                box left.uniquify(mapping),
                                box right.uniquify(mapping)),
            Ast::Lambda(args, body) => {
                let mut new_args = vec![];
                for arg in args {
                    let new_arg = Rc::new(get_unique_varname(arg));
                    new_args.push(new_arg.clone());
                    mapping.insert(arg.clone(), new_arg.clone());
                }

                 Ast::Lambda(new_args,
                             box body.uniquify(mapping))
            },
            Ast::Define(name, args, val) => {
                let uniq_fname = Rc::new(get_unique_varname(name));
                mapping.insert(name.clone(), uniq_fname.clone());

                let mut new_args = vec![];
                for arg in args {
                    let new_arg = Rc::new(get_unique_varname(arg));
                    new_args.push(new_arg.clone());
                    mapping.insert(arg.clone(), new_arg.clone());
                }

                Ast::Define(uniq_fname.clone(),
                            new_args,
                            box val.uniquify(mapping))
            },
            Ast::If(cond, thn, els) =>
                Ast::If(box (cond.uniquify(mapping)),
                        box (thn.uniquify(mapping)),
                        box (els.uniquify(mapping))),
            Ast::App(f, args) => {
                let new_args : Vec<_> = args.iter()
                    .map(|a| a.uniquify(mapping)).collect();
                Ast::App(box f.uniquify(mapping),
                         new_args)
            },
            Ast::Prog(defs, e) => {
                let new_defs : Vec<_> = defs.iter()
                    .map(|def| def.uniquify(mapping)).collect();
                Ast::Prog(new_defs, box e.uniquify(mapping))
            },
            _ => panic!("NYI"),
        }
    }

    fn get_free_variables(&self,
                          env: &HashSet<Rc<String>>,
                          parent_env: &HashSet<Rc<String>>) -> Vec<Rc<String>> {
        match self {
            Ast::Number(_) => vec![],
            Ast::Symbol(name) => {
                match env.get(name) {
                    Some(_) => vec![],
                    None => {
                        match parent_env.get(name) {
                            Some(_) => vec![name.clone()],
                            None => panic!("no binding found in parent env for free-variable {} env: {:?} parent-env: {:?}", name, env, parent_env),
                        }
                    }
                }
            },
            Ast::If(cnd, thn, els) => {
                let mut cnd_freevars =
                    cnd.get_free_variables(env, parent_env);
                let thn_freevars =
                    thn.get_free_variables(env, parent_env);
                let els_freevars =
                    els.get_free_variables(env, parent_env);

                cnd_freevars.extend_from_slice(&thn_freevars);
                cnd_freevars.extend_from_slice(&els_freevars);

                return cnd_freevars;
            },
            Ast::Define(_, args, body) |
            Ast::Lambda(args, body) => {
                let mut new_parent_env : HashSet<Rc<String>> = HashSet::new()
                    .union(&env).cloned().collect();
                new_parent_env = new_parent_env
                    .union(&parent_env).cloned().collect();

                let new_env : HashSet<Rc<String>> = args.iter().map(|a| a.clone()).collect();

                println!("[lambda] new_env: {:?} new_parent_env: {:?}",
                         new_env,
                         new_parent_env);

                body.get_free_variables(&new_env, &new_parent_env)
            },
            Ast::Let(bindings, body) => {
                let mut new_env = HashSet::new();
                let mut bindings_free_vars = vec![];
                for (k, v) in bindings {
                    let v_freevars : Vec<_> =
                        v.get_free_variables(env, parent_env);
                    new_env.insert(k.clone());
                    bindings_free_vars.extend_from_slice(&v_freevars);
                }

                new_env = new_env.union(&env).cloned().collect();
                let body_freevars : Vec<_> =
                    body.get_free_variables(&new_env,
                                            parent_env);
                bindings_free_vars.extend_from_slice(&body_freevars);

                return bindings_free_vars;
            },
            Ast::App(_, args) => {
                let mut args_freevars = vec![];
                for arg in args {
                    let arg_freevars : Vec<_> =
                        arg.get_free_variables(env,
                                               parent_env);
                    args_freevars.extend_from_slice(&arg_freevars);
                }

                return args_freevars;
            },
            _ => panic!("NYI: {:?}", self),
        }
    }

    fn symbol_is_primitive(sym: &str) -> bool {
        match sym {
            "+" | "-" | "tuple-ref" | "tuple" => true,
            _ => false,
        }
    }

    fn get_define_name(def: &Ast) -> Rc<String> {
        match def {
            Ast::Define(name, _, _) => name.clone(),
            _ => panic!("not a Define"),
        }
    }

    /// Converts a lambda into a top-level define'd function. For all
    /// functions, adds a closure arg, and updates function
    /// applications to pass the closure arg. The `clos` arg is a
    /// tuple (f, a1, ..., an) capturing free variables.
    pub fn convert_to_closures(&self, env: &HashSet<Rc<String>>, toplevel_funs: &HashSet<Rc<String>>)
                           -> (Ast, Vec<Ast>) {
        match self {
            Ast::Cmp(_, _, _) |
            Ast::Bool(_) |
            Ast::Symbol(_) |
            Ast::FuncName(_) |
            Ast::Number(_) => (self.clone(), vec![]),
            Ast::If(cnd, thn, els) => {
                let (converted_cnd, mut cnd_defines) =
                    cnd.convert_to_closures(env, toplevel_funs);
                let (converted_thn, thn_defines) =
                    thn.convert_to_closures(env, toplevel_funs);
                let (converted_els, els_defines) =
                    els.convert_to_closures(env, toplevel_funs);

                let converted = Ast::If(box converted_cnd,
                                        box converted_thn,
                                        box converted_els);

                cnd_defines.extend_from_slice(&thn_defines);
                cnd_defines.extend_from_slice(&els_defines);

                return (converted, cnd_defines);
            },
            Ast::Define(name, args, body) => {
                let mut new_args = args.clone();
                let mut new_env = env.clone();

                for arg in args {
                    new_env.insert(arg.clone());
                }
                let (converted_body, body_defines) =
                    body.convert_to_closures(&new_env, toplevel_funs);

                new_args.insert(0, Rc::new("clos".to_string()));

                let converted = Ast::Define(name.clone(),
                                            new_args,
                                            box converted_body);

                return (converted, body_defines);

            },
            Ast::Lambda(args, body) => {
                let mut new_env = HashSet::new();
                let mut new_args = args.clone();
                for arg in args {
                    new_env.insert(arg.clone());
                }

                let (converted_body, mut new_defines) =
                    body.convert_to_closures(&new_env, toplevel_funs);

                let lambda_name = Rc::new(get_unique_varname("lam"));
                let free_vars : Vec<_> = body.get_free_variables(&new_env,
                                                                 env);
                let mut load_free_vars = converted_body;
                for (i, fvar) in free_vars.iter().enumerate() {
                    let bindings = vec![(fvar.clone(),
                                         Ast::App(box Ast::Symbol(Rc::new("tuple-ref".to_string())),
                                                  vec![Ast::Symbol(Rc::new("clos".to_string())),
                                                       Ast::Number((i+1) as i64)]))];
                    load_free_vars =
                        Ast::Let(bindings,
                                 box load_free_vars);
                }

                new_args.insert(0, Rc::new("clos".to_string()));

                let mut closure_elts =
                    vec![Ast::FuncName(lambda_name.clone())];

                let free_vars : Vec<Ast> =
                    free_vars.iter().map(|fv| Ast::Symbol(fv.clone())).collect();
                closure_elts.extend_from_slice(&free_vars[..]);
                let closure = Ast::Tuple(closure_elts);

                new_defines.extend_from_slice(&[
                    Ast::Define(lambda_name.clone(),
                                new_args,
                                box load_free_vars)
                ]);

                return (closure, new_defines);
            },
            Ast::Tuple(elts) => {
                let mut converted_elts = vec![];
                let mut elts_defines = vec![];

                for elt in elts {
                    let (conv_elt, elt_defines) : (Ast, Vec<Ast>) =
                        elt.convert_to_closures(env, toplevel_funs);
                    converted_elts.push(conv_elt);
                    elts_defines.extend_from_slice(&elt_defines);
                }

                let converted = Ast::Tuple(converted_elts);
                return (converted, elts_defines);

            },
            Ast::App(box Ast::Symbol(f), ref args)
                if Self::symbol_is_primitive(f) => {
                    let mut converted_args = vec![];
                    let mut args_defines = vec![];

                    for arg in args.clone() {
                        let (conv_arg, arg_defines) : (Ast, Vec<Ast>) =
                            arg.convert_to_closures(env, toplevel_funs);
                        converted_args.push(conv_arg);
                        args_defines.extend_from_slice(&arg_defines);
                    }

                    let converted = Ast::App(box Ast::Symbol(f.clone()),
                                             converted_args);
                    return (converted, args_defines);
                },
            Ast::App(box Ast::Symbol(f), ref args)
                if !Self::symbol_is_primitive(f) => {
                    let fname = match toplevel_funs.get(f) {
                        Some(_) => Ast::Tuple(vec![Ast::FuncName(f.clone())]),
                        None => Ast::Symbol(f.clone()),
                    };

                    let (fclos, fdefines) : (Ast, Vec<Ast>) =
                        fname.convert_to_closures(env, toplevel_funs);
                    let f_temp = Rc::new(get_unique_varname("tmp"));

                    let mut converted_args =
                        vec![Ast::Symbol(f_temp.clone())];
                    let mut args_defines = vec![];

                    for arg in args {
                        let (conv_arg, arg_defines) : (Ast, Vec<Ast>) =
                            arg.convert_to_closures(env, toplevel_funs);
                        converted_args.push(conv_arg);
                        args_defines.extend_from_slice(&arg_defines);
                    }

                    args_defines.extend_from_slice(&fdefines);

                    let converted = Ast::Let(vec![(f_temp.clone(), fclos)],
                                               box Ast::App(
                                                   box Ast::App(box Ast::Symbol(Rc::new("tuple-ref".to_string())),
                                                                vec![Ast::Symbol(f_temp),
                                                                     Ast::Number(0)]),
                                                   converted_args));
                    return (converted, args_defines);
                },
            Ast::Let(bindings, body) => {
                let mut new_bindings = vec![];
                let mut bindings_defines = vec![];
                let mut new_env = env.clone();

                for (k, v) in bindings {
                    let (converted_v, v_defines) : (Ast, Vec<Ast>) =
                        v.convert_to_closures(env, toplevel_funs);

                    new_env.insert(k.clone());
                    new_bindings.push((k.clone(), converted_v));
                    bindings_defines.extend_from_slice(&v_defines);
                };

                let (converted_body, body_defines) : (Ast, Vec<Ast>) =
                    body.convert_to_closures(&new_env, toplevel_funs);

                bindings_defines.extend_from_slice(&body_defines);

                let converted = Ast::Let(new_bindings,
                                         box converted_body);
                return (converted, bindings_defines);
            },
            Ast::Prog(defines, main) => {
                let mut converted_defines = vec![];
                let mut defines_new_defines = vec![];
                let mut toplevel_funs = toplevel_funs.clone();

                for def in defines {
                    toplevel_funs.insert(Self::get_define_name(&def));
                    let (converted_define, new_defines) : (Ast, Vec<Ast>) =
                        def.convert_to_closures(env, &toplevel_funs);

                    converted_defines.push(converted_define);
                    defines_new_defines.extend_from_slice(&new_defines);
                }

                let (converted_main, main_defines) : (Ast, Vec<Ast>) =
                    main.convert_to_closures(env, &toplevel_funs);

                converted_defines.extend_from_slice(&defines_new_defines);
                converted_defines.extend_from_slice(&main_defines);

                let converted = Ast::Prog(converted_defines,
                                            box converted_main);

                return (converted, vec![]);
            },
            _ => panic!("NYI: {:?}", self),
        }
    }
}
<|endoftext|>


<commit_before>#[desc = "C64 emulator"];
#[copyright = "Andreas Neuhaus <info@zargony.com>"];
#[license = "MIT"];

extern crate native;

use cpu::Mos6510;
use mem::{Addressable, Ram, Rom, SharedMemory};

mod cpu;
mod mem;
mod ui;

#[start]
fn start (argc: int, argv: **u8) -> int {
	// Ensure that main is started on the native main os thread (required for SDL2)
	native::start(argc, argv, main)
}

fn main () {
	let mut c64 = C64::new();
	c64.run();
}

// General information on C64 : http://unusedino.de/ec64/technical/aay/c64/
// Useful emulator information: http://emudocs.org/?page=Commodore%2064
// C64 memory map overview: http://www.c64-wiki.com/index.php/Memory_Map
// Details about the PLA: http://www.c64-wiki.de/index.php/PLA_(C64-Chip)
// Even more PLA details: http://skoe.de/docs/c64-dissected/pla/c64_pla_dissected_r1.1_a4ss.pdf

/// Represents the memory as seen by the CPU (memory layout is based on the
/// settings of bits 2..0 of the processor port (/CHAREN, /HIRAM and /LORAM)
struct CpuMemory {
	ram: SharedMemory<Ram<u16>>,
	basic: Rom<u16>,
	characters: Rom<u16>,
	kernal: Rom<u16>,
	charen: bool,
	hiram: bool,
	loram: bool,
}

impl CpuMemory {
	fn new () -> CpuMemory {
		CpuMemory {
			ram: SharedMemory::new(Ram::new()),
			basic: Rom::new(&Path::new("c64/basic.rom")),
			characters: Rom::new(&Path::new("c64/characters.rom")),
			kernal: Rom::new(&Path::new("c64/kernal.rom")),
			charen: false,
			hiram: false,
			loram: false,
		}
	}
}

impl Addressable<u16> for CpuMemory {
	fn get (&self, addr: u16) -> u8 {
		// Switch memory access based on processor port lines:
		//
		//    /CHAREN /HIRAM /LORAM $A000-$BFFF $D000-$DFFF $E000-$FFFF
		// #1    1      1       1      BASIC        I/O        KERNAL
		// #6    1      1       0       RAM         I/O        KERNAL
		// #3    1      0       1       RAM         I/O         RAM
		// #5    X      0       0       RAM         RAM         RAM
		// #2    0      1       1      BASIC       CHARS       KERNAL
		// #7    0      1       0       RAM        CHARS       KERNAL
		// #4    0      0       1       RAM        CHARS        RAM
		// #5    X      0       0       RAM         RAM         RAM
		//
		// TODO: Hardware cartridges can as well use /GAME and /EXROM
		match (addr, self.charen, self.hiram, self.loram) {
			(0xa000..0xbfff,     _, false, false) => self.basic.get(addr - 0xa000),				// #1,2
			(0xd000..0xdfff, false, false,     _) => 0, // TODO: self.io.get(addr - 0xd000),	// #1,6
			(0xd000..0xdfff, false,  true, false) => 0, // TODO: self.io.get(addr - 0xd000),	// #3
			(0xd000..0xdfff,  true, false,     _) => self.characters.get(addr - 0xd000),		// #2,7
			(0xd000..0xdfff,  true,  true, false) => self.characters.get(addr - 0xd000),		// #4
			(0xe000..0xffff,     _, false,     _) => self.kernal.get(addr - 0xe000),			// #1,6,2,7
			_                                     => self.ram.get(addr),
		}
	}

	fn set (&mut self, addr: u16, data: u8) {
		// Writing to an address will always store the data to RAM,
		// no matter if an address is accessed that is mapped to ROM
		self.ram.set(addr, data);
	}
}

pub struct C64 {
	priv cpu: Mos6510<CpuMemory>,
}

impl C64 {
	pub fn new () -> C64 {
		let mem = CpuMemory::new();
		C64 {
			cpu: Mos6510::new(mem),
		}
	}

	pub fn run (&mut self) {
		// TODO
	}
}
<commit_msg>Add some doc strings<commit_after>#[desc = "C64 emulator"];
#[copyright = "Andreas Neuhaus <info@zargony.com>"];
#[license = "MIT"];

extern crate native;

use cpu::Mos6510;
use mem::{Addressable, Ram, Rom, SharedMemory};

mod cpu;
mod mem;
mod ui;

#[start]
fn start (argc: int, argv: **u8) -> int {
	// Ensure that main is started on the native main os thread (required for SDL2)
	native::start(argc, argv, main)
}

fn main () {
	let mut c64 = C64::new();
	c64.run();
}

// General information on C64 : http://unusedino.de/ec64/technical/aay/c64/
// Useful emulator information: http://emudocs.org/?page=Commodore%2064
// C64 memory map overview: http://www.c64-wiki.com/index.php/Memory_Map
// Details about the PLA: http://www.c64-wiki.de/index.php/PLA_(C64-Chip)
// Even more PLA details: http://skoe.de/docs/c64-dissected/pla/c64_pla_dissected_r1.1_a4ss.pdf

/// Represents the memory as seen by the CPU (memory layout is based on the
/// settings of bits 2..0 of the processor port (/CHAREN, /HIRAM and /LORAM)
struct CpuMemory {
	ram: SharedMemory<Ram<u16>>,
	basic: Rom<u16>,
	characters: Rom<u16>,
	kernal: Rom<u16>,
	charen: bool,
	hiram: bool,
	loram: bool,
}

impl CpuMemory {
	/// Create a new CPU memory
	fn new () -> CpuMemory {
		CpuMemory {
			ram: SharedMemory::new(Ram::new()),
			basic: Rom::new(&Path::new("c64/basic.rom")),
			characters: Rom::new(&Path::new("c64/characters.rom")),
			kernal: Rom::new(&Path::new("c64/kernal.rom")),
			charen: false,
			hiram: false,
			loram: false,
		}
	}
}

impl Addressable<u16> for CpuMemory {
	fn get (&self, addr: u16) -> u8 {
		// Switch memory access based on processor port lines:
		//
		//    /CHAREN /HIRAM /LORAM $A000-$BFFF $D000-$DFFF $E000-$FFFF
		// #1    1      1       1      BASIC        I/O        KERNAL
		// #6    1      1       0       RAM         I/O        KERNAL
		// #3    1      0       1       RAM         I/O         RAM
		// #5    X      0       0       RAM         RAM         RAM
		// #2    0      1       1      BASIC       CHARS       KERNAL
		// #7    0      1       0       RAM        CHARS       KERNAL
		// #4    0      0       1       RAM        CHARS        RAM
		// #5    X      0       0       RAM         RAM         RAM
		//
		// TODO: Hardware cartridges can as well use /GAME and /EXROM
		match (addr, self.charen, self.hiram, self.loram) {
			(0xa000..0xbfff,     _, false, false) => self.basic.get(addr - 0xa000),				// #1,2
			(0xd000..0xdfff, false, false,     _) |												// #1,6
			(0xd000..0xdfff, false,  true, false) => 0, // TODO: self.io.get(addr - 0xd000),	// #3
			(0xd000..0xdfff,  true, false,     _) |												// #2,7
			(0xd000..0xdfff,  true,  true, false) => self.characters.get(addr - 0xd000),		// #4
			(0xe000..0xffff,     _, false,     _) => self.kernal.get(addr - 0xe000),			// #1,6,2,7
			_                                     => self.ram.get(addr),
		}
	}

	fn set (&mut self, addr: u16, data: u8) {
		// Writing to an address will always store the data to RAM,
		// no matter if an address is accessed that is mapped to ROM
		match (addr, self.charen, self.hiram, self.loram) {
			(0xd000..0xdfff, false, false,     _) |												// #1,6
			(0xd000..0xdfff, false,  true, false) => (), // self.io.set(addr - 0xd000, data),	// #3
			_                                     => self.ram.set(addr, data),
		}
	}
}

pub struct C64 {
	priv cpu: Mos6510<CpuMemory>,
}

impl C64 {
	/// Create a new C64 emulator
	pub fn new () -> C64 {
		let mem = CpuMemory::new();
		C64 {
			cpu: Mos6510::new(mem),
		}
	}

	/// Run the C64 emulation
	pub fn run (&mut self) {
		// TODO
	}
}
<|endoftext|>


<commit_before>use pancurses::{Input, Window};
use errext::{ErrExt, PResult};
use command::run_expression;

fn print_buffer(screen: &Window, buffer: &str) -> PResult {
    let height = (screen.get_max_y() - 1) as usize;
    let width = screen.get_max_x() as usize;
    screen.mv(0, 0).as_err()?;
    for line in buffer.lines().take(height) {
        let max = ::std::cmp::min(width, line.len());
        screen.addstr(&line[..max]).as_err()?;
        screen.addch('\n').as_err()?;
    }
    Ok(())
}

fn print_command(screen: &Window, buffer: &str) -> PResult {
    let height = screen.get_max_y() - 1;
    let width = screen.get_max_x() - 1;
    screen.mv(height - 1, 0).as_err()?;
    screen.hline(0, width).as_err()?;
    screen.mv(height, 0).as_err()?;
    let max = ::std::cmp::min(width as usize, buffer.len());
    screen.addstr(&buffer[..max]).as_err()?;
    Ok(())
}

pub fn input_loop(screen: Window) -> PResult {
    let mut output_buffer = String::from("");
    let mut command_buffer = String::new();
    // let (mut x, mut y) = (0, 0);
    loop {
        screen.clear().as_err()?;
        print_buffer(&screen, &output_buffer)?;
        print_command(&screen, &command_buffer)?;
        screen.refresh().as_err()?;
        let next = screen.getch().unwrap();
        match next {
            Input::KeyBackspace |
            Input::Character('\x08') => {
                command_buffer.pop();
            }
            Input::Character('\n') => {
                output_buffer.push_str("$ ");
                let output = run_expression(&command_buffer)?;
                output_buffer.push_str(&output.command);
                output_buffer.push_str("\n");
                output_buffer.push_str(&output.interleaved);
                output_buffer.push_str("\n");
                command_buffer.clear();
            }
            Input::Character(chr) => {
                command_buffer.push(chr);
            }
            _ => {}
        };
    }
}
<commit_msg>for some reason, 0x7f is being generated when I hit backspace... handle that<commit_after>use pancurses::{Input, Window};
use errext::{ErrExt, PResult};
use command::run_expression;

fn print_buffer(screen: &Window, buffer: &str) -> PResult {
    let height = (screen.get_max_y() - 1) as usize;
    let width = screen.get_max_x() as usize;
    screen.mv(0, 0).as_err()?;
    for line in buffer.lines().take(height) {
        let max = ::std::cmp::min(width, line.len());
        screen.addstr(&line[..max]).as_err()?;
        screen.addch('\n').as_err()?;
    }
    Ok(())
}

fn print_command(screen: &Window, buffer: &str) -> PResult {
    let height = screen.get_max_y() - 1;
    let width = screen.get_max_x() - 1;
    screen.mv(height - 1, 0).as_err()?;
    screen.hline(0, width).as_err()?;
    screen.mv(height, 0).as_err()?;
    let max = ::std::cmp::min(width as usize, buffer.len());
    screen.addstr(&buffer[..max]).as_err()?;
    Ok(())
}

pub fn input_loop(screen: Window) -> PResult {
    let mut output_buffer = String::from("");
    let mut command_buffer = String::new();
    // let (mut x, mut y) = (0, 0);
    loop {
        screen.clear().as_err()?;
        print_buffer(&screen, &output_buffer)?;
        print_command(&screen, &command_buffer)?;
        screen.refresh().as_err()?;
        let next = screen.getch().unwrap();
        match next {
            Input::KeyBackspace |
            Input::Character('\x08') |
            Input::Character('\x7f') => {
                command_buffer.pop().unwrap();
            }
            Input::Character('\n') => {
                output_buffer.push_str("$ ");
                let output = run_expression(&command_buffer)?;
                output_buffer.push_str(&output.command);
                output_buffer.push_str("\n");
                output_buffer.push_str(&output.interleaved);
                output_buffer.push_str("\n");
                command_buffer.clear();
            }
            Input::Character(chr) => {
                println!("char: {:?}", chr);
                command_buffer.push(chr);
            }
            _ => {}
        };
    }
}
<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::ops::Deref;

use serde::de::{Deserialize, Deserializer, Error};
use serde::ser::{Serialize, Serializer};

use types::*;

/// Unique identifier for the target chat or username of the
/// target channel (in the format @channelusername)
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum ChatRef<'a> {
    Id(ChatId),
    #[doc(hidden)]
    ChannelUsername(Cow<'a, str>,),
}

impl<'a> ChatRef<'a> {
    pub fn from_chat_id(chat_id: ChatId) -> ChatRef<'a> {
        ChatRef::Id(chat_id)
    }
}

pub trait ToChatRef<'a> {
    fn to_chat_ref(&self) -> ChatRef<'a>;
}

impl<'a, S> ToChatRef<'a> for S where S: Deref, S::Target: ToChatRef<'a> {
    fn to_chat_ref(&self) -> ChatRef<'a> {
        self.deref().to_chat_ref()
    }
}

impl<'a> ToChatRef<'a> for Chat {
    fn to_chat_ref(&self) -> ChatRef<'a> {
        self.id().to_chat_ref()
    }
}

impl<'a> ToChatRef<'a> for User {
    fn to_chat_ref(&self) -> ChatRef<'a> {
        self.id.to_chat_ref()
    }
}

impl<'a> ToChatRef<'a> for ChatMember {
    fn to_chat_ref(&self) -> ChatRef<'a> {
        self.user.to_chat_ref()
    }
}

impl<'a> Serialize for ChatRef<'a> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        match *self {
            ChatRef::Id(id) => serializer.serialize_i64(id.into()),
            ChatRef::ChannelUsername(ref username) => serializer.serialize_str(&username),
        }
    }
}

macro_rules! chat_id_impls {
    ($name: ident) => {
        integer_id_impls!($name);

        impl<'a> ToChatRef<'a> for $name {
            fn to_chat_ref(&self) -> ChatRef<'a> {
                ChatRef::from_chat_id((*self).into())
            }
        }
    };
}

macro_rules! concrete_chat_id_impls {
    ($name: ident) => {
        chat_id_impls!($name);

        impl From<$name> for ChatId {
            fn from(c: $name) -> Self {
                ChatId::new(c.into())
            }
        }
    };
}

pub trait ToUserId {
    fn to_user_id(&self) -> UserId;
}

impl<S> ToUserId for S where S: Deref, S::Target: ToUserId {
    fn to_user_id(&self) -> UserId {
        self.deref().to_user_id()
    }
}

impl ToUserId for UserId {
    fn to_user_id(&self) -> UserId {
        *self
    }
}

impl ToUserId for ChatMember {
    fn to_user_id(&self) -> UserId {
        self.user.id
    }
}

impl ToUserId for User {
    fn to_user_id(&self) -> UserId {
        self.id
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct UserId(Integer);
concrete_chat_id_impls!(UserId);

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct GroupId(Integer);
concrete_chat_id_impls!(GroupId);

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SupergroupId(Integer);
concrete_chat_id_impls!(SupergroupId);

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ChannelId(Integer);
concrete_chat_id_impls!(ChannelId);

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ChatId(Integer);
chat_id_impls!(ChatId);

/// This object represents a Telegram user or bot.
#[derive(Debug, Clone, PartialEq, PartialOrd, Deserialize)]
pub struct User {
    /// Unique identifier for this user or bot.
    pub id: UserId,
    /// User‘s or bot’s first name.
    pub first_name: String,
    /// User‘s or bot’s last name.
    pub last_name: Option<String>,
    /// User‘s or bot’s username.
    pub username: Option<String>,
}

/// This object represents a group.
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Group {
    /// Unique identifier for this chat.
    pub id: GroupId,
    /// Title, for supergroups, channels and group chats.
    pub title: String,
    /// True if a group has ‘All Members Are Admins’ enabled.
    pub all_members_are_administrators: bool,
}

/// This object represents a supergroup.
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Supergroup {
    /// Unique identifier for this chat.
    pub id: SupergroupId,
    /// Title, for supergroups, channels and group chats.
    pub title: String,
    /// Username for supergroup.
    pub username: Option<String>,
}

/// This object represents a channel.
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Channel {
    /// Unique identifier for this chat.
    pub id: ChannelId,
    /// Title, for supergroups, channels and group chats.
    pub title: String,
    /// Username for channel.
    pub username: Option<String>,
}

/// This object represents a chat.
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum Chat {
    Private(User),
    Group(Group),
    Supergroup(Supergroup),
    Channel(Channel),
    #[doc(hidden)]
    Unknown(RawChat),
}

impl Chat {
    pub fn id(&self) -> ChatId {
        match *self {
            Chat::Private(ref x) => x.id.into(),
            Chat::Group(ref x) => x.id.into(),
            Chat::Supergroup(ref x) => x.id.into(),
            Chat::Channel(ref x) => x.id.into(),
            Chat::Unknown(ref x) => x.id.into(),
        }
    }
}

impl<'de> Deserialize<'de> for Chat {
    fn deserialize<D>(deserializer: D) -> Result<Chat, D::Error>
        where D: Deserializer<'de>
    {
        let raw: RawChat = Deserialize::deserialize(deserializer)?;

        macro_rules! required_field {
            ($name:ident) => {{
                match raw.$name {
                    Some(val) => val,
                    None => return Err(D::Error::missing_field(stringify!($name)))
                }
            }}
        }

        Ok(match raw.type_.as_ref() {
            "private" => {
                Chat::Private(User {
                    id: raw.id.into(),
                    username: raw.username,
                    first_name: required_field!(first_name),
                    last_name: raw.last_name,
                })
            }
            "group" => {
                Chat::Group(Group {
                    id: raw.id.into(),
                    title: required_field!(title),
                    all_members_are_administrators: required_field!(all_members_are_administrators),
                })
            }
            "supergroup" => {
                Chat::Supergroup(Supergroup {
                    id: raw.id.into(),
                    title: required_field!(title),
                    username: raw.username,
                })
            }
            "channel" => {
                Chat::Channel(Channel {
                    id: raw.id.into(),
                    title: required_field!(title),
                    username: raw.username,
                })
            }
            _ => Chat::Unknown(raw),
        })
    }
}

/// This object represents a chat, directly mapped.
#[derive(Debug, Clone, PartialEq, PartialOrd, Deserialize)]
pub struct RawChat {
    /// Unique identifier for this chat.
    pub id: Integer,
    /// Type of chat, can be either “private”, “group”, “supergroup” or “channel”
    #[serde(rename="type")]
    pub type_: String,
    /// Title, for supergroups, channels and group chats
    pub title: Option<String>,
    /// Username, for private chats, supergroups and channels if available
    pub username: Option<String>,
    /// First name of the other party in a private chat
    pub first_name: Option<String>,
    /// Last name of the other party in a private chat
    pub last_name: Option<String>,
    /// True if a group has ‘All Members Are Admins’ enabled.
    pub all_members_are_administrators: Option<bool>,
}
<commit_msg>feat: implement ToChatRef for all chat types<commit_after>use std::borrow::Cow;
use std::ops::Deref;

use serde::de::{Deserialize, Deserializer, Error};
use serde::ser::{Serialize, Serializer};

use types::*;

/// Unique identifier for the target chat or username of the
/// target channel (in the format @channelusername)
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum ChatRef<'a> {
    Id(ChatId),
    #[doc(hidden)]
    ChannelUsername(Cow<'a, str>,),
}

impl<'a> ChatRef<'a> {
    pub fn from_chat_id(chat_id: ChatId) -> ChatRef<'a> {
        ChatRef::Id(chat_id)
    }
}

pub trait ToChatRef<'a> {
    fn to_chat_ref(&self) -> ChatRef<'a>;
}

impl<'a, S> ToChatRef<'a> for S where S: Deref, S::Target: ToChatRef<'a> {
    fn to_chat_ref(&self) -> ChatRef<'a> {
        self.deref().to_chat_ref()
    }
}

impl<'a> ToChatRef<'a> for Chat {
    fn to_chat_ref(&self) -> ChatRef<'a> {
        self.id().to_chat_ref()
    }
}

impl<'a> ToChatRef<'a> for ChatMember {
    fn to_chat_ref(&self) -> ChatRef<'a> {
        self.user.to_chat_ref()
    }
}

impl<'a> Serialize for ChatRef<'a> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        match *self {
            ChatRef::Id(id) => serializer.serialize_i64(id.into()),
            ChatRef::ChannelUsername(ref username) => serializer.serialize_str(&username),
        }
    }
}

macro_rules! chat_id_impls {
    ($id: ident) => {
        integer_id_impls!($id);

        impl<'a> ToChatRef<'a> for $id {
            fn to_chat_ref(&self) -> ChatRef<'a> {
                ChatRef::from_chat_id((*self).into())
            }
        }
    };
}

macro_rules! concrete_chat_id_impls {
    ($id: ident, $typ: ident) => {
        chat_id_impls!($id);

        impl From<$id> for ChatId {
            fn from(c: $id) -> Self {
                ChatId::new(c.into())
            }
        }

        impl<'a> ToChatRef<'a> for $typ {
            fn to_chat_ref(&self) -> ChatRef<'a> {
                self.id.to_chat_ref()
            }
        }
    };
}

pub trait ToUserId {
    fn to_user_id(&self) -> UserId;
}

impl<S> ToUserId for S where S: Deref, S::Target: ToUserId {
    fn to_user_id(&self) -> UserId {
        self.deref().to_user_id()
    }
}

impl ToUserId for UserId {
    fn to_user_id(&self) -> UserId {
        *self
    }
}

impl ToUserId for ChatMember {
    fn to_user_id(&self) -> UserId {
        self.user.id
    }
}

impl ToUserId for User {
    fn to_user_id(&self) -> UserId {
        self.id
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct UserId(Integer);
concrete_chat_id_impls!(UserId, User);

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct GroupId(Integer);
concrete_chat_id_impls!(GroupId, Group);

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SupergroupId(Integer);
concrete_chat_id_impls!(SupergroupId, Supergroup);

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ChannelId(Integer);
concrete_chat_id_impls!(ChannelId, Channel);

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ChatId(Integer);
chat_id_impls!(ChatId);

/// This object represents a Telegram user or bot.
#[derive(Debug, Clone, PartialEq, PartialOrd, Deserialize)]
pub struct User {
    /// Unique identifier for this user or bot.
    pub id: UserId,
    /// User‘s or bot’s first name.
    pub first_name: String,
    /// User‘s or bot’s last name.
    pub last_name: Option<String>,
    /// User‘s or bot’s username.
    pub username: Option<String>,
}

/// This object represents a group.
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Group {
    /// Unique identifier for this chat.
    pub id: GroupId,
    /// Title, for supergroups, channels and group chats.
    pub title: String,
    /// True if a group has ‘All Members Are Admins’ enabled.
    pub all_members_are_administrators: bool,
}

/// This object represents a supergroup.
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Supergroup {
    /// Unique identifier for this chat.
    pub id: SupergroupId,
    /// Title, for supergroups, channels and group chats.
    pub title: String,
    /// Username for supergroup.
    pub username: Option<String>,
}

/// This object represents a channel.
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Channel {
    /// Unique identifier for this chat.
    pub id: ChannelId,
    /// Title, for supergroups, channels and group chats.
    pub title: String,
    /// Username for channel.
    pub username: Option<String>,
}

/// This object represents a chat.
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum Chat {
    Private(User),
    Group(Group),
    Supergroup(Supergroup),
    Channel(Channel),
    #[doc(hidden)]
    Unknown(RawChat),
}

impl Chat {
    pub fn id(&self) -> ChatId {
        match *self {
            Chat::Private(ref x) => x.id.into(),
            Chat::Group(ref x) => x.id.into(),
            Chat::Supergroup(ref x) => x.id.into(),
            Chat::Channel(ref x) => x.id.into(),
            Chat::Unknown(ref x) => x.id.into(),
        }
    }
}

impl<'de> Deserialize<'de> for Chat {
    fn deserialize<D>(deserializer: D) -> Result<Chat, D::Error>
        where D: Deserializer<'de>
    {
        let raw: RawChat = Deserialize::deserialize(deserializer)?;

        macro_rules! required_field {
            ($name:ident) => {{
                match raw.$name {
                    Some(val) => val,
                    None => return Err(D::Error::missing_field(stringify!($name)))
                }
            }}
        }

        Ok(match raw.type_.as_ref() {
            "private" => {
                Chat::Private(User {
                    id: raw.id.into(),
                    username: raw.username,
                    first_name: required_field!(first_name),
                    last_name: raw.last_name,
                })
            }
            "group" => {
                Chat::Group(Group {
                    id: raw.id.into(),
                    title: required_field!(title),
                    all_members_are_administrators: required_field!(all_members_are_administrators),
                })
            }
            "supergroup" => {
                Chat::Supergroup(Supergroup {
                    id: raw.id.into(),
                    title: required_field!(title),
                    username: raw.username,
                })
            }
            "channel" => {
                Chat::Channel(Channel {
                    id: raw.id.into(),
                    title: required_field!(title),
                    username: raw.username,
                })
            }
            _ => Chat::Unknown(raw),
        })
    }
}

/// This object represents a chat, directly mapped.
#[derive(Debug, Clone, PartialEq, PartialOrd, Deserialize)]
pub struct RawChat {
    /// Unique identifier for this chat.
    pub id: Integer,
    /// Type of chat, can be either “private”, “group”, “supergroup” or “channel”
    #[serde(rename="type")]
    pub type_: String,
    /// Title, for supergroups, channels and group chats
    pub title: Option<String>,
    /// Username, for private chats, supergroups and channels if available
    pub username: Option<String>,
    /// First name of the other party in a private chat
    pub first_name: Option<String>,
    /// Last name of the other party in a private chat
    pub last_name: Option<String>,
    /// True if a group has ‘All Members Are Admins’ enabled.
    pub all_members_are_administrators: Option<bool>,
}
<|endoftext|>


<commit_before>use std::mem;
use std::any::TypeId;
use std::marker::PhantomData;
use std::collections::{HashSet, HashMap};
use std::os::raw::c_void;
use std::panic::UnwindSafe;
use cslice::CMutSlice;
use neon_runtime;
use neon_runtime::raw;
use internal::scope::{Scope, RootScope, RootScopeInternal};
use internal::js::{JsValue, Value, Object, JsObject, JsFunction};
use internal::js::class::ClassMetadata;
use internal::js::error::{JsError, Kind};
use internal::mem::{Handle, HandleInternal, Managed};

pub struct Throw;
pub type VmResult<T> = Result<T, Throw>;
pub type JsResult<'b, T> = VmResult<Handle<'b, T>>;

#[repr(C)]
#[derive(Clone, Copy)]
pub struct Isolate(*mut raw::Isolate);

pub trait IsolateInternal {
    fn to_raw(self) -> *mut raw::Isolate;
    fn from_raw(ptr: *mut raw::Isolate) -> Self;
    fn class_map(&mut self) -> &mut ClassMap;
}

pub struct ClassMap {
    map: HashMap<TypeId, ClassMetadata>
}

impl ClassMap {
    fn new() -> ClassMap {
        ClassMap {
            map: HashMap::new()
        }
    }

    pub fn get(&self, key: &TypeId) -> Option<&ClassMetadata> {
        self.map.get(key)
    }

    pub fn set(&mut self, key: TypeId, val: ClassMetadata) {
        self.map.insert(key, val);
    }
}

impl IsolateInternal for Isolate {
    fn to_raw(self) -> *mut raw::Isolate {
        let Isolate(ptr) = self;
        ptr
    }

    fn from_raw(ptr: *mut raw::Isolate) -> Self {
        Isolate(ptr)
    }

    fn class_map(&mut self) -> &mut ClassMap {
        let mut ptr: *mut c_void = unsafe { neon_runtime::class::get_class_map(self.to_raw()) };
        if ptr.is_null() {
            let b: Box<ClassMap> = Box::new(ClassMap::new());
            let raw = Box::into_raw(b);
            ptr = unsafe { mem::transmute(raw) };
            let free_map: *mut c_void = unsafe { mem::transmute(drop_class_map as usize) };
            unsafe {
                neon_runtime::class::set_class_map(self.to_raw(), ptr, free_map);
            }
        }
        unsafe { mem::transmute(ptr) }
    }
}

extern "C" fn drop_class_map(map: Box<ClassMap>) {
    mem::drop(map);
}

#[repr(C)]
pub struct CallbackInfo {
    info: raw::FunctionCallbackInfo
}

impl CallbackInfo {
    pub fn data<'a>(&self) -> Handle<'a, JsValue> {
        unsafe {
            let mut local: raw::Local = mem::zeroed();
            neon_runtime::call::data(&self.info, &mut local);
            Handle::new(JsValue::from_raw(local))
        }
    }

    pub fn scope(&self) -> RootScope {
        RootScope::new(unsafe {
            mem::transmute(neon_runtime::call::get_isolate(mem::transmute(self)))
        })
    }

    pub fn set_return<'a, 'b, T: Value>(&'a self, value: Handle<'b, T>) {
        unsafe {
            neon_runtime::call::set_return(&self.info, value.to_raw())
        }
    }

    pub fn as_call<'a, T: This>(&'a self, scope: &'a mut RootScope<'a>) -> FunctionCall<'a, T> {
        FunctionCall {
            info: self,
            scope: scope,
            arguments: Arguments {
                info: &self,
                phantom: PhantomData
            }
        }
    }

    fn kind(&self) -> CallKind {
        if unsafe { neon_runtime::call::is_construct(mem::transmute(self)) } {
            CallKind::Construct
        } else {
            CallKind::Call
        }
    }

    pub fn len(&self) -> i32 {
        unsafe {
            neon_runtime::call::len(&self.info)
        }
    }

    pub fn get<'b, T: Scope<'b>>(&self, _: &mut T, i: i32) -> Option<Handle<'b, JsValue>> {
        if i < 0 || i >= self.len() {
            return None;
        }
        unsafe {
            let mut local: raw::Local = mem::zeroed();
            neon_runtime::call::get(&self.info, i, &mut local);
            Some(Handle::new(JsValue::from_raw(local)))
        }
    }

    pub fn require<'b, T: Scope<'b>>(&self, _: &mut T, i: i32) -> JsResult<'b, JsValue> {
        if i < 0 || i >= self.len() {
            return JsError::throw(Kind::TypeError, "not enough arguments");
        }
        unsafe {
            let mut local: raw::Local = mem::zeroed();
            neon_runtime::call::get(&self.info, i, &mut local);
            Ok(Handle::new(JsValue::from_raw(local)))
        }
    }

    pub fn this<'b, T: Scope<'b>>(&self, _: &mut T) -> raw::Local {
        unsafe {
            let mut local: raw::Local = mem::zeroed();
            neon_runtime::call::this(mem::transmute(&self.info), &mut local);
            local
        }
    }

    pub fn callee<'a, T: Scope<'a>>(&self, _: &mut T) -> Handle<'a, JsFunction> {
        unsafe {
            let mut local: raw::Local = mem::zeroed();
            neon_runtime::call::callee(mem::transmute(&self.info), &mut local);
            Handle::new(JsFunction::from_raw(local))
        }
    }
}

pub struct Module<'a> {
    pub exports: Handle<'a, JsObject>,
    pub scope: &'a mut RootScope<'a>
}

impl<'a> Module<'a> {
    pub fn initialize(exports: Handle<JsObject>, init: fn(Module) -> VmResult<()>) {
        let mut scope = RootScope::new(unsafe { mem::transmute(neon_runtime::object::get_isolate(exports.to_raw())) });
        unsafe {
            let kernel: *mut c_void = mem::transmute(init);
            let callback: extern "C" fn(*mut c_void, *mut c_void, *mut c_void) = mem::transmute(module_callback as usize);
            let exports: raw::Local = exports.to_raw();
            let scope: *mut c_void = mem::transmute(&mut scope);
            neon_runtime::module::exec_kernel(kernel, callback, exports, scope);
        }
    }
}

impl<'a> Module<'a> {
    pub fn export<T: Value>(&mut self, key: &str, f: fn(Call) -> JsResult<T>) -> VmResult<()> {
        let value = try!(JsFunction::new(self.scope, f)).upcast::<JsValue>();
        try!(self.exports.set(key, value));
        Ok(())
    }
}

extern "C" fn module_callback<'a>(kernel: fn(Module) -> VmResult<()>, exports: Handle<'a, JsObject>, scope: &'a mut RootScope<'a>) {
    let _ = kernel(Module {
        exports: exports,
        scope: scope
    });
}

/// A type that may be the type of a function's `this` binding.
pub unsafe trait This: Managed {
    fn as_this(h: raw::Local) -> Self;
}

pub struct FunctionCall<'a, T: This> {
    info: &'a CallbackInfo,
    pub scope: &'a mut RootScope<'a>,
    pub arguments: Arguments<'a, T>
}

impl<'a, T: This> UnwindSafe for FunctionCall<'a, T> { }

pub type Call<'a> = FunctionCall<'a, JsObject>;

#[derive(Clone, Copy, Debug)]
pub enum CallKind {
    Construct,
    Call
}

impl<'a, T: This> FunctionCall<'a, T> {
    pub fn kind(&self) -> CallKind { self.info.kind() }
}

#[repr(C)]
pub struct Arguments<'a, T> {
    info: &'a CallbackInfo,
    phantom: PhantomData<T>
}

impl<'a, T: This> Arguments<'a, T> {
    pub fn len(&self) -> i32 { self.info.len() }

    pub fn get<'b, U: Scope<'b>>(&self, scope: &mut U, i: i32) -> Option<Handle<'b, JsValue>> {
        self.info.get(scope, i)
    }

    pub fn require<'b, U: Scope<'b>>(&self, scope: &mut U, i: i32) -> JsResult<'b, JsValue> {
        self.info.require(scope, i)
    }

    pub fn this<'b, U: Scope<'b>>(&self, scope: &mut U) -> Handle<'b, T> {
        Handle::new(T::as_this(self.info.this(scope)))
    }

    pub fn callee<'b, U: Scope<'b>>(&self, scope: &mut U) -> Handle<'b, JsFunction> {
        self.info.callee(scope)
    }
}

/// A kernel of callable code exported to JS. A kernel function can be exported
/// to the Neon runtime as a raw pointer coupled with an `extern "C"` callback
/// function pointer.
pub trait Kernel<T: Clone + Copy + Sized>: Sized {

    /// The static callback function that can be passed to the Neon runtime to
    /// be called by V8 when the callable code is invoked. The Neon runtime
    /// ensures that the kernel will be provided as the extra data field,
    /// wrapped as a V8 External, in the `CallbackInfo` argument.
    extern "C" fn callback(info: &CallbackInfo) -> T;

    /// Extracts the kernel from the V8 External value pointed to by the given
    /// handle.
    unsafe fn from_wrapper(raw::Local) -> Self;

    /// Converts the kernel function to a raw void pointer.
    fn as_ptr(self) -> *mut c_void;

    /// Exports the kernel as a pair consisting of the static callback function
    /// and the kernel function, both converted to raw void pointers.
    fn export(self) -> (*mut c_void, *mut c_void) {
        unsafe {
            (mem::transmute(Self::callback as usize), self.as_ptr())
        }
    }
}

pub struct LockState {
    buffers: HashSet<usize>
}

impl LockState {
    pub fn use_buffer(&mut self, buf: CMutSlice<u8>) {
        let p = buf.as_ptr() as usize;
        if !self.buffers.insert(p) {
            panic!("attempt to lock heap with duplicate buffers (0x{:x})", p);
        }
    }
}

pub trait Lock: Sized {
    type Internals;

    fn grab<F, T>(self, f: F) -> T
        where F: FnOnce(Self::Internals) -> T + Send
    {
        let mut state = LockState { buffers: HashSet::new() };
        let internals = unsafe { self.expose(&mut state) };
        f(internals)
    }

    unsafe fn expose(self, state: &mut LockState) -> Self::Internals;
}

impl<T, U> Lock for (T, U)
    where T: Lock, U: Lock
{
    type Internals = (T::Internals, U::Internals);

    unsafe fn expose(self, state: &mut LockState) -> Self::Internals {
        (self.0.expose(state), self.1.expose(state))
    }
}

impl<T> Lock for Vec<T>
    where T: Lock
{
    type Internals = Vec<T::Internals>;

    unsafe fn expose(self, state: &mut LockState) -> Self::Internals {
        self.into_iter()
            .map(|x| x.expose(state))
            .collect()
    }
}
<commit_msg>Add impl std::error::Error for Throw.<commit_after>use std::mem;
use std::any::TypeId;
use std::error::Error;
use std::fmt::{Display, Formatter, Result as FmtResult};
use std::marker::PhantomData;
use std::collections::{HashSet, HashMap};
use std::os::raw::c_void;
use std::panic::UnwindSafe;
use cslice::CMutSlice;
use neon_runtime;
use neon_runtime::raw;
use internal::scope::{Scope, RootScope, RootScopeInternal};
use internal::js::{JsValue, Value, Object, JsObject, JsFunction};
use internal::js::class::ClassMetadata;
use internal::js::error::{JsError, Kind};
use internal::mem::{Handle, HandleInternal, Managed};

#[derive(Debug)]
pub struct Throw;

impl Display for Throw {
    fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
        fmt.write_str("JavaScript Error")
    }
}

impl Error for Throw {
    fn description(&self) -> &str {
        "javascript error"
    }
}

pub type VmResult<T> = Result<T, Throw>;
pub type JsResult<'b, T> = VmResult<Handle<'b, T>>;

#[repr(C)]
#[derive(Clone, Copy)]
pub struct Isolate(*mut raw::Isolate);

pub trait IsolateInternal {
    fn to_raw(self) -> *mut raw::Isolate;
    fn from_raw(ptr: *mut raw::Isolate) -> Self;
    fn class_map(&mut self) -> &mut ClassMap;
}

pub struct ClassMap {
    map: HashMap<TypeId, ClassMetadata>
}

impl ClassMap {
    fn new() -> ClassMap {
        ClassMap {
            map: HashMap::new()
        }
    }

    pub fn get(&self, key: &TypeId) -> Option<&ClassMetadata> {
        self.map.get(key)
    }

    pub fn set(&mut self, key: TypeId, val: ClassMetadata) {
        self.map.insert(key, val);
    }
}

impl IsolateInternal for Isolate {
    fn to_raw(self) -> *mut raw::Isolate {
        let Isolate(ptr) = self;
        ptr
    }

    fn from_raw(ptr: *mut raw::Isolate) -> Self {
        Isolate(ptr)
    }

    fn class_map(&mut self) -> &mut ClassMap {
        let mut ptr: *mut c_void = unsafe { neon_runtime::class::get_class_map(self.to_raw()) };
        if ptr.is_null() {
            let b: Box<ClassMap> = Box::new(ClassMap::new());
            let raw = Box::into_raw(b);
            ptr = unsafe { mem::transmute(raw) };
            let free_map: *mut c_void = unsafe { mem::transmute(drop_class_map as usize) };
            unsafe {
                neon_runtime::class::set_class_map(self.to_raw(), ptr, free_map);
            }
        }
        unsafe { mem::transmute(ptr) }
    }
}

extern "C" fn drop_class_map(map: Box<ClassMap>) {
    mem::drop(map);
}

#[repr(C)]
pub struct CallbackInfo {
    info: raw::FunctionCallbackInfo
}

impl CallbackInfo {
    pub fn data<'a>(&self) -> Handle<'a, JsValue> {
        unsafe {
            let mut local: raw::Local = mem::zeroed();
            neon_runtime::call::data(&self.info, &mut local);
            Handle::new(JsValue::from_raw(local))
        }
    }

    pub fn scope(&self) -> RootScope {
        RootScope::new(unsafe {
            mem::transmute(neon_runtime::call::get_isolate(mem::transmute(self)))
        })
    }

    pub fn set_return<'a, 'b, T: Value>(&'a self, value: Handle<'b, T>) {
        unsafe {
            neon_runtime::call::set_return(&self.info, value.to_raw())
        }
    }

    pub fn as_call<'a, T: This>(&'a self, scope: &'a mut RootScope<'a>) -> FunctionCall<'a, T> {
        FunctionCall {
            info: self,
            scope: scope,
            arguments: Arguments {
                info: &self,
                phantom: PhantomData
            }
        }
    }

    fn kind(&self) -> CallKind {
        if unsafe { neon_runtime::call::is_construct(mem::transmute(self)) } {
            CallKind::Construct
        } else {
            CallKind::Call
        }
    }

    pub fn len(&self) -> i32 {
        unsafe {
            neon_runtime::call::len(&self.info)
        }
    }

    pub fn get<'b, T: Scope<'b>>(&self, _: &mut T, i: i32) -> Option<Handle<'b, JsValue>> {
        if i < 0 || i >= self.len() {
            return None;
        }
        unsafe {
            let mut local: raw::Local = mem::zeroed();
            neon_runtime::call::get(&self.info, i, &mut local);
            Some(Handle::new(JsValue::from_raw(local)))
        }
    }

    pub fn require<'b, T: Scope<'b>>(&self, _: &mut T, i: i32) -> JsResult<'b, JsValue> {
        if i < 0 || i >= self.len() {
            return JsError::throw(Kind::TypeError, "not enough arguments");
        }
        unsafe {
            let mut local: raw::Local = mem::zeroed();
            neon_runtime::call::get(&self.info, i, &mut local);
            Ok(Handle::new(JsValue::from_raw(local)))
        }
    }

    pub fn this<'b, T: Scope<'b>>(&self, _: &mut T) -> raw::Local {
        unsafe {
            let mut local: raw::Local = mem::zeroed();
            neon_runtime::call::this(mem::transmute(&self.info), &mut local);
            local
        }
    }

    pub fn callee<'a, T: Scope<'a>>(&self, _: &mut T) -> Handle<'a, JsFunction> {
        unsafe {
            let mut local: raw::Local = mem::zeroed();
            neon_runtime::call::callee(mem::transmute(&self.info), &mut local);
            Handle::new(JsFunction::from_raw(local))
        }
    }
}

pub struct Module<'a> {
    pub exports: Handle<'a, JsObject>,
    pub scope: &'a mut RootScope<'a>
}

impl<'a> Module<'a> {
    pub fn initialize(exports: Handle<JsObject>, init: fn(Module) -> VmResult<()>) {
        let mut scope = RootScope::new(unsafe { mem::transmute(neon_runtime::object::get_isolate(exports.to_raw())) });
        unsafe {
            let kernel: *mut c_void = mem::transmute(init);
            let callback: extern "C" fn(*mut c_void, *mut c_void, *mut c_void) = mem::transmute(module_callback as usize);
            let exports: raw::Local = exports.to_raw();
            let scope: *mut c_void = mem::transmute(&mut scope);
            neon_runtime::module::exec_kernel(kernel, callback, exports, scope);
        }
    }
}

impl<'a> Module<'a> {
    pub fn export<T: Value>(&mut self, key: &str, f: fn(Call) -> JsResult<T>) -> VmResult<()> {
        let value = try!(JsFunction::new(self.scope, f)).upcast::<JsValue>();
        try!(self.exports.set(key, value));
        Ok(())
    }
}

extern "C" fn module_callback<'a>(kernel: fn(Module) -> VmResult<()>, exports: Handle<'a, JsObject>, scope: &'a mut RootScope<'a>) {
    let _ = kernel(Module {
        exports: exports,
        scope: scope
    });
}

/// A type that may be the type of a function's `this` binding.
pub unsafe trait This: Managed {
    fn as_this(h: raw::Local) -> Self;
}

pub struct FunctionCall<'a, T: This> {
    info: &'a CallbackInfo,
    pub scope: &'a mut RootScope<'a>,
    pub arguments: Arguments<'a, T>
}

impl<'a, T: This> UnwindSafe for FunctionCall<'a, T> { }

pub type Call<'a> = FunctionCall<'a, JsObject>;

#[derive(Clone, Copy, Debug)]
pub enum CallKind {
    Construct,
    Call
}

impl<'a, T: This> FunctionCall<'a, T> {
    pub fn kind(&self) -> CallKind { self.info.kind() }
}

#[repr(C)]
pub struct Arguments<'a, T> {
    info: &'a CallbackInfo,
    phantom: PhantomData<T>
}

impl<'a, T: This> Arguments<'a, T> {
    pub fn len(&self) -> i32 { self.info.len() }

    pub fn get<'b, U: Scope<'b>>(&self, scope: &mut U, i: i32) -> Option<Handle<'b, JsValue>> {
        self.info.get(scope, i)
    }

    pub fn require<'b, U: Scope<'b>>(&self, scope: &mut U, i: i32) -> JsResult<'b, JsValue> {
        self.info.require(scope, i)
    }

    pub fn this<'b, U: Scope<'b>>(&self, scope: &mut U) -> Handle<'b, T> {
        Handle::new(T::as_this(self.info.this(scope)))
    }

    pub fn callee<'b, U: Scope<'b>>(&self, scope: &mut U) -> Handle<'b, JsFunction> {
        self.info.callee(scope)
    }
}

/// A kernel of callable code exported to JS. A kernel function can be exported
/// to the Neon runtime as a raw pointer coupled with an `extern "C"` callback
/// function pointer.
pub trait Kernel<T: Clone + Copy + Sized>: Sized {

    /// The static callback function that can be passed to the Neon runtime to
    /// be called by V8 when the callable code is invoked. The Neon runtime
    /// ensures that the kernel will be provided as the extra data field,
    /// wrapped as a V8 External, in the `CallbackInfo` argument.
    extern "C" fn callback(info: &CallbackInfo) -> T;

    /// Extracts the kernel from the V8 External value pointed to by the given
    /// handle.
    unsafe fn from_wrapper(raw::Local) -> Self;

    /// Converts the kernel function to a raw void pointer.
    fn as_ptr(self) -> *mut c_void;

    /// Exports the kernel as a pair consisting of the static callback function
    /// and the kernel function, both converted to raw void pointers.
    fn export(self) -> (*mut c_void, *mut c_void) {
        unsafe {
            (mem::transmute(Self::callback as usize), self.as_ptr())
        }
    }
}

pub struct LockState {
    buffers: HashSet<usize>
}

impl LockState {
    pub fn use_buffer(&mut self, buf: CMutSlice<u8>) {
        let p = buf.as_ptr() as usize;
        if !self.buffers.insert(p) {
            panic!("attempt to lock heap with duplicate buffers (0x{:x})", p);
        }
    }
}

pub trait Lock: Sized {
    type Internals;

    fn grab<F, T>(self, f: F) -> T
        where F: FnOnce(Self::Internals) -> T + Send
    {
        let mut state = LockState { buffers: HashSet::new() };
        let internals = unsafe { self.expose(&mut state) };
        f(internals)
    }

    unsafe fn expose(self, state: &mut LockState) -> Self::Internals;
}

impl<T, U> Lock for (T, U)
    where T: Lock, U: Lock
{
    type Internals = (T::Internals, U::Internals);

    unsafe fn expose(self, state: &mut LockState) -> Self::Internals {
        (self.0.expose(state), self.1.expose(state))
    }
}

impl<T> Lock for Vec<T>
    where T: Lock
{
    type Internals = Vec<T::Internals>;

    unsafe fn expose(self, state: &mut LockState) -> Self::Internals {
        self.into_iter()
            .map(|x| x.expose(state))
            .collect()
    }
}
<|endoftext|>


<commit_before>
//! A 3D camera.

pub type Vector3 = [f64, ..3];

pub struct Camera {
    pub position: Vector3,
    pub target: Vector3,
    pub right: Vector3,
    pub up: Vector3,
}

<commit_msg>Added `CameraSettings`<commit_after>
//! A 3D camera.

pub type Vector3 = [f64, ..3];

pub struct Camera {
    pub position: Vector3,
    pub target: Vector3,
    pub right: Vector3,
    pub up: Vector3,
}

pub struct CameraSettings {
    pub fov_rad: f64,
    pub near_clip: f64,
    pub far_clip: f64,
    pub aspect_ratio: f64,
}

<|endoftext|>


<commit_before>
use gfx_device_gl::Factory;
use piston_window::*;

use game::asset_factory::AssetFactory;
use game::config::Config;
use game::scene::{Scene, SceneResult};
use game::window::GameWindow;

pub struct MainMenu {
    asset_factory: AssetFactory,
    selected_item: SelectedMenuItem,
    selection: Option<SelectedMenuItem>,

    // Menu items
    new_game_label: ::game::text::Text,
    quit_label: ::game::text::Text,
}

#[derive(Copy, Clone)]
enum SelectedMenuItem {
    NewGame,
    Quit,
}

impl Scene for MainMenu {
    fn process(&mut self, e: &Event) -> SceneResult {
        match *e {
            Event::Input(ref input_event) => {
                if let Input::Press(ref button) = *input_event {
                    match *button {
                        Button::Keyboard(Key::Up) => self.up(),
                        Button::Keyboard(Key::Down) => self.down(),
                        Button::Keyboard(Key::Return) => self.make_selection(),
                        _ => (),
                    }

                    self.handle_selected_item();
                }
            }
            _ => (),
        }

        if let Some(ref selected_item) = self.selection {
            match *selected_item {
                SelectedMenuItem::NewGame => SceneResult::NewGame,
                SelectedMenuItem::Quit => SceneResult::Quit,
            }
        } else {
            SceneResult::None
        }
    }

    fn render(&mut self, window: &mut GameWindow, e: &Event) {
        window.draw_2d(e, |mut c, g| {
            clear([0.0, 0.0, 0.0, 1.0], g);

            self.new_game_label.render(self.asset_factory.font.as_mut().unwrap(), c, g);
            self.quit_label.render(self.asset_factory.font.as_mut().unwrap(), c, g);
        });
    }
}

impl MainMenu {
    pub fn new(config: &Config, gfx_factory: Factory) -> MainMenu {
        MainMenu {
            asset_factory: AssetFactory::new(gfx_factory),
            selected_item: SelectedMenuItem::NewGame,
            selection: None,
            new_game_label: ::game::text::Text::new("New Game", 24, 50, 200, config.ui_color),
            quit_label: ::game::text::Text::new("Quit", 16, 50, 250, config.ui_color),
        }
    }

    /// Move the selection up
    fn up(&mut self) {
        match self.selected_item {
            SelectedMenuItem::NewGame => self.selected_item = SelectedMenuItem::Quit,
            SelectedMenuItem::Quit => self.selected_item = SelectedMenuItem::NewGame,
        }
    }

    /// Move the selection down
    fn down(&mut self) {
        match self.selected_item {
            SelectedMenuItem::NewGame => self.selected_item = SelectedMenuItem::Quit,
            SelectedMenuItem::Quit => self.selected_item = SelectedMenuItem::NewGame,
        }
    }

    /// Make the final selection
    fn make_selection(&mut self) {
        self.selection = Some(self.selected_item.clone());
    }

    fn handle_selected_item(&mut self) {
        match self.selected_item {
            SelectedMenuItem::NewGame => {
                self.new_game_label.set_font_size(24);
                self.quit_label.set_font_size(16);
            }
            SelectedMenuItem::Quit => {
                self.new_game_label.set_font_size(16);
                self.quit_label.set_font_size(24);
            }
        }
    }
}<commit_msg>Cleaned up the menu item selection<commit_after>
use gfx_device_gl::Factory;
use piston_window::*;

use game::asset_factory::AssetFactory;
use game::config::Config;
use game::scene::{Scene, SceneResult};
use game::window::GameWindow;

pub struct MainMenu {
    asset_factory: AssetFactory,
    selected_item: SelectedMenuItem,
    selection: Option<SelectedMenuItem>,

    // Menu items
    new_game_label: ::game::text::Text,
    quit_label: ::game::text::Text,
}

#[derive(Copy, Clone)]
enum SelectedMenuItem {
    NewGame,
    Quit,
}

impl Scene for MainMenu {
    fn process(&mut self, e: &Event) -> SceneResult {
        match *e {
            Event::Input(ref input_event) => {
                if let Input::Press(ref button) = *input_event {
                    match *button {
                        Button::Keyboard(Key::Up) => self.up(),
                        Button::Keyboard(Key::Down) => self.down(),
                        Button::Keyboard(Key::Return) => {
                            match self.selected_item {
                                SelectedMenuItem::NewGame => SceneResult::NewGame,
                                SelectedMenuItem::Quit => SceneResult::Quit,
                            }
                        }
                        _ => SceneResult::None,
                    }
                } else {
                    SceneResult::None
                }
            }
            _ => SceneResult::None,
        }
    }

    fn render(&mut self, window: &mut GameWindow, e: &Event) {
        window.draw_2d(e, |mut c, g| {
            clear([0.0, 0.0, 0.0, 1.0], g);

            self.new_game_label.render(self.asset_factory.font.as_mut().unwrap(), c, g);
            self.quit_label.render(self.asset_factory.font.as_mut().unwrap(), c, g);
        });
    }
}

impl MainMenu {
    pub fn new(config: &Config, gfx_factory: Factory) -> MainMenu {
        MainMenu {
            asset_factory: AssetFactory::new(gfx_factory),
            selected_item: SelectedMenuItem::NewGame,
            selection: None,
            new_game_label: ::game::text::Text::new("New Game", 24, 50, 200, config.ui_color),
            quit_label: ::game::text::Text::new("Quit", 16, 50, 250, config.ui_color),
        }
    }

    /// Move the selection up
    fn up(&mut self) -> SceneResult {
        match self.selected_item {
            SelectedMenuItem::NewGame => self.selected_item = SelectedMenuItem::Quit,
            SelectedMenuItem::Quit => self.selected_item = SelectedMenuItem::NewGame,
        }

        self.handle_selected_item();

        SceneResult::None
    }

    /// Move the selection down
    fn down(&mut self) -> SceneResult {
        match self.selected_item {
            SelectedMenuItem::NewGame => self.selected_item = SelectedMenuItem::Quit,
            SelectedMenuItem::Quit => self.selected_item = SelectedMenuItem::NewGame,
        }

        self.handle_selected_item();

        SceneResult::None
    }

    /// Make the final selection
    fn make_selection(&mut self) {
        self.selection = Some(self.selected_item.clone());
    }

    fn handle_selected_item(&mut self) {
        match self.selected_item {
            SelectedMenuItem::NewGame => {
                self.new_game_label.set_font_size(24);
                self.quit_label.set_font_size(16);
            }
            SelectedMenuItem::Quit => {
                self.new_game_label.set_font_size(16);
                self.quit_label.set_font_size(24);
            }
        }
    }
}<|endoftext|>


<commit_before>use serde_derive::Deserialize;
use serde_yaml;
use state_processing::{
    per_block_processing, per_block_processing_without_verifying_block_signature,
    per_slot_processing,
};
use std::{fs::File, io::prelude::*, path::PathBuf};
use types::*;
#[allow(unused_imports)]
use yaml_utils;

#[derive(Debug, Deserialize)]
pub struct TestCase {
    pub name: String,
    pub config: ChainSpec,
    pub verify_signatures: bool,
    pub initial_state: BeaconState,
    pub blocks: Vec<BeaconBlock>,
}

#[derive(Debug, Deserialize)]
pub struct TestDoc {
    pub title: String,
    pub summary: String,
    pub fork: String,
    pub test_cases: Vec<TestCase>,
}

#[test]
fn test_read_yaml() {
    // Test sanity-check_small-config_32-vals.yaml
    let mut file = {
        let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
        file_path_buf.push("yaml_utils/specs/sanity-check_small-config_32-vals.yaml");

        File::open(file_path_buf).unwrap()
    };

    let mut yaml_str = String::new();

    file.read_to_string(&mut yaml_str).unwrap();

    yaml_str = yaml_str.to_lowercase();

    let _doc: TestDoc = serde_yaml::from_str(&yaml_str.as_str()).unwrap();

    // Test sanity-check_default-config_100-vals.yaml
    file = {
        let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
        file_path_buf.push("yaml_utils/specs/sanity-check_default-config_100-vals.yaml");

        File::open(file_path_buf).unwrap()
    };

    yaml_str = String::new();

    file.read_to_string(&mut yaml_str).unwrap();

    yaml_str = yaml_str.to_lowercase();

    let _doc: TestDoc = serde_yaml::from_str(&yaml_str.as_str()).unwrap();
}

#[test]
fn run_state_transition_tests_small() {
    // Test sanity-check_small-config_32-vals.yaml
    let mut file = {
        let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
        file_path_buf.push("yaml_utils/specs/sanity-check_small-config_32-vals.yaml");

        File::open(file_path_buf).unwrap()
    };
    let mut yaml_str = String::new();
    file.read_to_string(&mut yaml_str).unwrap();
    yaml_str = yaml_str.to_lowercase();

    let doc: TestDoc = serde_yaml::from_str(&yaml_str.as_str()).unwrap();

    // Run Tests
    for (i, test_case) in doc.test_cases.iter().enumerate() {
        let mut state = test_case.initial_state.clone();
        for block in test_case.blocks.iter() {
            while block.slot > state.slot {
                let latest_block_header = state.latest_block_header.clone();
                per_slot_processing(&mut state, &latest_block_header, &test_case.config).unwrap();
            }
            if test_case.verify_signatures {
                let res = per_block_processing(&mut state, &block, &test_case.config);
                if res.is_err() {
                    println!("{:?}", i);
                    println!("{:?}", res);
                };
            } else {
                let res = per_block_processing_without_verifying_block_signature(
                    &mut state,
                    &block,
                    &test_case.config,
                );
                if res.is_err() {
                    println!("{:?}", i);
                    println!("{:?}", res);
                }
            }
        }
    }
}
<commit_msg>Skip long-running tests in debug<commit_after>use serde_derive::Deserialize;
use serde_yaml;
#[cfg(not(debug_assertions))]
use state_processing::{
    per_block_processing, per_block_processing_without_verifying_block_signature,
    per_slot_processing,
};
use std::{fs::File, io::prelude::*, path::PathBuf};
use types::*;
#[allow(unused_imports)]
use yaml_utils;

#[derive(Debug, Deserialize)]
pub struct TestCase {
    pub name: String,
    pub config: ChainSpec,
    pub verify_signatures: bool,
    pub initial_state: BeaconState,
    pub blocks: Vec<BeaconBlock>,
}

#[derive(Debug, Deserialize)]
pub struct TestDoc {
    pub title: String,
    pub summary: String,
    pub fork: String,
    pub test_cases: Vec<TestCase>,
}

#[test]
fn test_read_yaml() {
    // Test sanity-check_small-config_32-vals.yaml
    let mut file = {
        let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
        file_path_buf.push("yaml_utils/specs/sanity-check_small-config_32-vals.yaml");

        File::open(file_path_buf).unwrap()
    };

    let mut yaml_str = String::new();

    file.read_to_string(&mut yaml_str).unwrap();

    yaml_str = yaml_str.to_lowercase();

    let _doc: TestDoc = serde_yaml::from_str(&yaml_str.as_str()).unwrap();

    // Test sanity-check_default-config_100-vals.yaml
    file = {
        let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
        file_path_buf.push("yaml_utils/specs/sanity-check_default-config_100-vals.yaml");

        File::open(file_path_buf).unwrap()
    };

    yaml_str = String::new();

    file.read_to_string(&mut yaml_str).unwrap();

    yaml_str = yaml_str.to_lowercase();

    let _doc: TestDoc = serde_yaml::from_str(&yaml_str.as_str()).unwrap();
}

#[test]
#[cfg(not(debug_assertions))]
fn run_state_transition_tests_small() {
    // Test sanity-check_small-config_32-vals.yaml
    let mut file = {
        let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
        file_path_buf.push("yaml_utils/specs/sanity-check_small-config_32-vals.yaml");

        File::open(file_path_buf).unwrap()
    };
    let mut yaml_str = String::new();
    file.read_to_string(&mut yaml_str).unwrap();
    yaml_str = yaml_str.to_lowercase();

    let doc: TestDoc = serde_yaml::from_str(&yaml_str.as_str()).unwrap();

    // Run Tests
    for (i, test_case) in doc.test_cases.iter().enumerate() {
        let mut state = test_case.initial_state.clone();
        for block in test_case.blocks.iter() {
            while block.slot > state.slot {
                let latest_block_header = state.latest_block_header.clone();
                per_slot_processing(&mut state, &latest_block_header, &test_case.config).unwrap();
            }
            if test_case.verify_signatures {
                let res = per_block_processing(&mut state, &block, &test_case.config);
                if res.is_err() {
                    println!("{:?}", i);
                    println!("{:?}", res);
                };
            } else {
                let res = per_block_processing_without_verifying_block_signature(
                    &mut state,
                    &block,
                    &test_case.config,
                );
                if res.is_err() {
                    println!("{:?}", i);
                    println!("{:?}", res);
                }
            }
        }
    }
}
<|endoftext|>