<commit_before>//! The core module contains the core data structures and traits used by all other modules.

#[cfg(feature = "with-constraint")]
use constraints;

use serde::{Deserialize, Serialize};
use std::collections::{BTreeSet, HashMap};
use std::fmt::{Debug, Display, Formatter, Result};
use std::iter::{Extend, FromIterator};

/// A type must implement BindingsValue in order to be used as the value for some variable.
pub trait BindingsValue
    : Clone + Debug + Default + Deserialize + Display + Eq + PartialEq + PartialOrd + Serialize
    {
    /// Construct a BindingsValue variable using the specified string as it's name
    fn variable(_s: &String) -> Option<Self> {
        None
    }
    /// Extract the name of this BindingsValue variable (if it is a variable)
    fn to_variable(&self) -> Option<String> {
        None
    }
}

/// Bindings is used for storing variables and operating on variables and their bindings.
#[derive(Debug, Deserialize, Clone, Serialize)]
pub struct Bindings<T: BindingsValue> {
    #[serde(default)]
    data: HashMap<String, T>,
    #[serde(default)]
    equivalences: HashMap<String, BTreeSet<String>>,
}

impl<T: BindingsValue> PartialEq for Bindings<T> {
    fn eq(&self, other: &Bindings<T>) -> bool {
        self.data.eq(&other.data) && self.equivalences.eq(&other.equivalences)
    }
}
impl<T: BindingsValue> Eq for Bindings<T> {}

impl<T: BindingsValue> Default for Bindings<T> {
    fn default() -> Self {
        Bindings {
            data: HashMap::new(),
            equivalences: HashMap::new(),
        }
    }
}

impl<T: BindingsValue> Bindings<T> {
    pub fn new() -> Bindings<T> {
        Bindings::default()
    }

    pub fn len(&self) -> usize {
        self.data.len()
    }

    pub fn has_binding(&self, variable: &String) -> bool {
        self.data.contains_key(variable)
    }

    pub fn set_binding(&self, variable: &String, val: T) -> Bindings<T> {
        let mut bindings_copy = self.clone();

        bindings_copy.set_binding_mut(variable, val);

        bindings_copy
    }

    fn set_binding_mut(&mut self, variable: &String, val: T) {
        self.ensure_equivalence_exists_mut(variable);

        if let Some(variable2) = val.to_variable() {
            self.add_equivalence(variable, &variable2);
        } else {
            for equivalent_variable in self.equivalences.get(variable).unwrap().iter() {
                self.data.insert(equivalent_variable.clone(), val.clone());
            }
        }
    }

    fn add_equivalence(&mut self, variable: &String, variable2: &String) {
        self.ensure_equivalence_exists_mut(&variable2);
        self.merge_equivalences_mut(variable, &variable2);
    }

    fn ensure_equivalence_exists_mut(&mut self, variable: &String) {
        if !self.equivalences.contains_key(variable) {
            self.equivalences.insert(variable.clone(),
                                     vec![variable.clone()].into_iter().collect());
        }
    }

    fn merge_equivalences_mut(&mut self, variable: &String, variable2: &String) {
        let mut merge = self.equivalences.get(variable).cloned().unwrap();
        merge.extend(self.equivalences.get(variable2).cloned().unwrap());

        self.equivalences.insert(variable.clone(), merge.clone());
        self.equivalences.insert(variable2.clone(), merge);
    }

    pub fn get_binding(&self, variable: &String) -> Option<T> {
        match self.data.get(variable) {
            Some(val) => Some(val.clone()),
            None => None,
        }
    }

    pub fn update_bindings(&self, variable: &String, value: &T) -> Option<Self> {
        // If we are setting a variable to itself, then do nothing
        if Some(variable.clone()) == value.to_variable() {
            return Some(self.clone());
        }
        match self.get_binding(&variable) {
            Some(ref val) if val == value => Some(self.clone()),
            Some(_) => None,
            None => Some(self.set_binding(variable, value.clone())),
        }
    }

    pub fn merge(&self, other: &Self) -> Self {
        let mut bindings = self.clone();

        // Merge in equivalences
        for (ref key, ref equivalences) in other.equivalences.iter() {
            for equivalent_key in equivalences.iter() {
                bindings.ensure_equivalence_exists_mut(key);
                bindings.add_equivalence(key, equivalent_key);
            }
        }

        // Merge in values
        for (key, value) in other.data.iter() {
            bindings.set_binding_mut(&key, value.clone())
        }

        bindings
    }

    pub fn equivalences_string(&self) -> String {
        let equivalent_v: Vec<String> = self.equivalences.iter().map(|(key, value)| format!("{} => {:?}", key, value)).collect();
        equivalent_v.join(",")
    }
}

impl<T: BindingsValue> FromIterator<(String, T)> for Bindings<T> {
    fn from_iter<I: IntoIterator<Item = (String, T)>>(iter: I) -> Bindings<T> {
        let mut bindings: Bindings<T> = Bindings::new();
        for (key, value) in iter {
            bindings.set_binding_mut(&key, value);
        }
        bindings
    }
}

impl<T: BindingsValue> Extend<(String, T)> for Bindings<T> {
    fn extend<It>(&mut self, iter: It)
        where It: IntoIterator<Item = (String, T)>
    {
        for (key, value) in iter {
            self.set_binding_mut(&key, value);
        }
    }
}

impl<T: BindingsValue> Display for Bindings<T> {
    fn fmt(&self, f: &mut Formatter) -> Result {
        try!(write!(f, "("));
        let mut sorted_keys: Vec<String> = self.data.keys().cloned().collect();
        sorted_keys.sort();
        for key in sorted_keys.into_iter() {
            let ref val = self.data[&key];
            try!(write!(f, "{} => {}, ", key, val));
        }
        try!(write!(f, "Equivalences: {}", self.equivalences_string()));
        write!(f, ")")
    }
}

/// A type must implement the Unify trait for it to be unifiable -  this only requirement for a data structure
/// that the algorithms in this library operate on.
pub trait Unify<T: BindingsValue>
    : Clone + Debug + Display + Eq + Serialize + Deserialize + PartialEq {
    /// Check if this structure can be unified with another of the same type.
    fn unify(&self, &Self, &Bindings<T>) -> Option<Bindings<T>>;

    /// Given some bindings, construct a new instance with any variables replaced by their values
    fn apply_bindings(&self, &Bindings<T>) -> Option<Self>;

    /// Return all variables in this tructure
    fn variables(&self) -> Vec<String>;

    /// Rename any variables in this structure with another variable name
    fn rename_variables(&self, &HashMap<String, String>) -> Self;

    /// Return a 'nil' sentinel value unique to this type of structure
    fn nil() -> Self;
}

/// A type that implements Operation constructs new Unifys from existing Unifys that match it's input patterns.
pub trait Operation<T: BindingsValue, U: Unify<T>>
    : Clone + Debug + Display + Eq + PartialEq + Deserialize + Serialize {
    // NOTE: replace constraints with validate_bindings?
    #[cfg(feature = "with-constraint")]
    fn constraints<'a>(&'a self) -> Vec<&'a constraints::Constraint>;

    /// Creates a new instance of this Operation where all variables are unique
    fn snowflake(&self, String) -> Self;

    /// Return a vector of input patterns that must be unified with in order to apply this Operation.
    fn input_patterns(&self) -> Vec<U> {
        Vec::new()
    }

    /// Given some bindings, construct a set of output patterns
    fn apply_match(&self, _bindings: &Bindings<T>) -> Option<Vec<U>>;

    /// Given some bindings, construct a set of input patterns that would match
    fn r_apply_match(&self, _fact: &U) -> Option<(Vec<U>, Bindings<T>)>;
}

#[cfg(test)]
mod tests;
<commit_msg>Fixed a typo in a comment<commit_after>//! The core module contains the core data structures and traits used by all other modules.

#[cfg(feature = "with-constraint")]
use constraints;

use serde::{Deserialize, Serialize};
use std::collections::{BTreeSet, HashMap};
use std::fmt::{Debug, Display, Formatter, Result};
use std::iter::{Extend, FromIterator};

/// A type must implement BindingsValue in order to be used as the value for some variable.
pub trait BindingsValue
    : Clone + Debug + Default + Deserialize + Display + Eq + PartialEq + PartialOrd + Serialize
    {
    /// Construct a BindingsValue variable using the specified string as it's name
    fn variable(_s: &String) -> Option<Self> {
        None
    }
    /// Extract the name of this BindingsValue variable (if it is a variable)
    fn to_variable(&self) -> Option<String> {
        None
    }
}

/// Bindings is used for storing variables and operating on variables and their bindings.
#[derive(Debug, Deserialize, Clone, Serialize)]
pub struct Bindings<T: BindingsValue> {
    #[serde(default)]
    data: HashMap<String, T>,
    #[serde(default)]
    equivalences: HashMap<String, BTreeSet<String>>,
}

impl<T: BindingsValue> PartialEq for Bindings<T> {
    fn eq(&self, other: &Bindings<T>) -> bool {
        self.data.eq(&other.data) && self.equivalences.eq(&other.equivalences)
    }
}
impl<T: BindingsValue> Eq for Bindings<T> {}

impl<T: BindingsValue> Default for Bindings<T> {
    fn default() -> Self {
        Bindings {
            data: HashMap::new(),
            equivalences: HashMap::new(),
        }
    }
}

impl<T: BindingsValue> Bindings<T> {
    pub fn new() -> Bindings<T> {
        Bindings::default()
    }

    pub fn len(&self) -> usize {
        self.data.len()
    }

    pub fn has_binding(&self, variable: &String) -> bool {
        self.data.contains_key(variable)
    }

    pub fn set_binding(&self, variable: &String, val: T) -> Bindings<T> {
        let mut bindings_copy = self.clone();

        bindings_copy.set_binding_mut(variable, val);

        bindings_copy
    }

    fn set_binding_mut(&mut self, variable: &String, val: T) {
        self.ensure_equivalence_exists_mut(variable);

        if let Some(variable2) = val.to_variable() {
            self.add_equivalence(variable, &variable2);
        } else {
            for equivalent_variable in self.equivalences.get(variable).unwrap().iter() {
                self.data.insert(equivalent_variable.clone(), val.clone());
            }
        }
    }

    fn add_equivalence(&mut self, variable: &String, variable2: &String) {
        self.ensure_equivalence_exists_mut(&variable2);
        self.merge_equivalences_mut(variable, &variable2);
    }

    fn ensure_equivalence_exists_mut(&mut self, variable: &String) {
        if !self.equivalences.contains_key(variable) {
            self.equivalences.insert(variable.clone(),
                                     vec![variable.clone()].into_iter().collect());
        }
    }

    fn merge_equivalences_mut(&mut self, variable: &String, variable2: &String) {
        let mut merge = self.equivalences.get(variable).cloned().unwrap();
        merge.extend(self.equivalences.get(variable2).cloned().unwrap());

        self.equivalences.insert(variable.clone(), merge.clone());
        self.equivalences.insert(variable2.clone(), merge);
    }

    pub fn get_binding(&self, variable: &String) -> Option<T> {
        match self.data.get(variable) {
            Some(val) => Some(val.clone()),
            None => None,
        }
    }

    pub fn update_bindings(&self, variable: &String, value: &T) -> Option<Self> {
        // If we are setting a variable to itself, then do nothing
        if Some(variable.clone()) == value.to_variable() {
            return Some(self.clone());
        }
        match self.get_binding(&variable) {
            Some(ref val) if val == value => Some(self.clone()),
            Some(_) => None,
            None => Some(self.set_binding(variable, value.clone())),
        }
    }

    pub fn merge(&self, other: &Self) -> Self {
        let mut bindings = self.clone();

        // Merge in equivalences
        for (ref key, ref equivalences) in other.equivalences.iter() {
            for equivalent_key in equivalences.iter() {
                bindings.ensure_equivalence_exists_mut(key);
                bindings.add_equivalence(key, equivalent_key);
            }
        }

        // Merge in values
        for (key, value) in other.data.iter() {
            bindings.set_binding_mut(&key, value.clone())
        }

        bindings
    }

    pub fn equivalences_string(&self) -> String {
        let equivalent_v: Vec<String> = self.equivalences.iter().map(|(key, value)| format!("{} => {:?}", key, value)).collect();
        equivalent_v.join(",")
    }
}

impl<T: BindingsValue> FromIterator<(String, T)> for Bindings<T> {
    fn from_iter<I: IntoIterator<Item = (String, T)>>(iter: I) -> Bindings<T> {
        let mut bindings: Bindings<T> = Bindings::new();
        for (key, value) in iter {
            bindings.set_binding_mut(&key, value);
        }
        bindings
    }
}

impl<T: BindingsValue> Extend<(String, T)> for Bindings<T> {
    fn extend<It>(&mut self, iter: It)
        where It: IntoIterator<Item = (String, T)>
    {
        for (key, value) in iter {
            self.set_binding_mut(&key, value);
        }
    }
}

impl<T: BindingsValue> Display for Bindings<T> {
    fn fmt(&self, f: &mut Formatter) -> Result {
        try!(write!(f, "("));
        let mut sorted_keys: Vec<String> = self.data.keys().cloned().collect();
        sorted_keys.sort();
        for key in sorted_keys.into_iter() {
            let ref val = self.data[&key];
            try!(write!(f, "{} => {}, ", key, val));
        }
        try!(write!(f, "Equivalences: {}", self.equivalences_string()));
        write!(f, ")")
    }
}

/// A type must implement the Unify trait for it to be unifiable -  this only requirement for a data structure
/// that the algorithms in this library operate on.
pub trait Unify<T: BindingsValue>
    : Clone + Debug + Display + Eq + Serialize + Deserialize + PartialEq {
    /// Check if this structure can be unified with another of the same type.
    fn unify(&self, &Self, &Bindings<T>) -> Option<Bindings<T>>;

    /// Given some bindings, construct a new instance with any variables replaced by their values
    fn apply_bindings(&self, &Bindings<T>) -> Option<Self>;

    /// Return all variables in this structure
    fn variables(&self) -> Vec<String>;

    /// Rename any variables in this structure with another variable name
    fn rename_variables(&self, &HashMap<String, String>) -> Self;

    /// Return a 'nil' sentinel value unique to this type of structure
    fn nil() -> Self;
}

/// A type that implements Operation constructs new Unifys from existing Unifys that match it's input patterns.
pub trait Operation<T: BindingsValue, U: Unify<T>>
    : Clone + Debug + Display + Eq + PartialEq + Deserialize + Serialize {
    // NOTE: replace constraints with validate_bindings?
    #[cfg(feature = "with-constraint")]
    fn constraints<'a>(&'a self) -> Vec<&'a constraints::Constraint>;

    /// Creates a new instance of this Operation where all variables are unique
    fn snowflake(&self, String) -> Self;

    /// Return a vector of input patterns that must be unified with in order to apply this Operation.
    fn input_patterns(&self) -> Vec<U> {
        Vec::new()
    }

    /// Given some bindings, construct a set of output patterns
    fn apply_match(&self, _bindings: &Bindings<T>) -> Option<Vec<U>>;

    /// Given some bindings, construct a set of input patterns that would match
    fn r_apply_match(&self, _fact: &U) -> Option<(Vec<U>, Bindings<T>)>;
}

#[cfg(test)]
mod tests;
<|endoftext|>


<commit_before>#[macro_use]
mod macros;

use coerce::{AsBool,AsNumber};

use french_press::ScopeManager;
use french_press::alloc::AllocBox;
use js_types::binding::Binding;
use js_types::js_fn::JsFnStruct;
use js_types::js_obj::JsObjStruct;
use js_types::js_str::JsStrStruct;
use js_types::js_var::{JsVar, JsType, JsPtrEnum, JsKey, JsKeyEnum};
use js_types::js_var::JsType::*;

use jsrs_parser::lalr::parse_Stmt;
use jsrs_common::ast::*;
use jsrs_common::ast::Exp::*;
use jsrs_common::ast::BinOp::*;
use jsrs_common::ast::Stmt::*;

type VarWithPtr = (JsVar, Option<JsPtrEnum>);

// Helper to avoid repeating this everywhere
fn scalar(v: JsType) -> (JsVar, Option<JsPtrEnum>) {
    (JsVar::new(v), None)
}

/// Evaluate a string containing some JavaScript statements (or sequences of statements).
/// Returns a JsVar which is the return value of those statements.
pub fn eval_string(string: &str, state: &mut ScopeManager) -> JsVar {
    match parse_Stmt(string) {
        Ok(stmt) => {
            eval_stmt(&stmt, state).0
        }
        Err(e) => panic!("parse error: {:?}", e),
    }
}

/// Evaluate a single JS statement (which may be a block or sequence of statements).
/// Returns tuple of (evaluated final value, return value), where return value requires that
/// `return` be used to generate it.
pub fn eval_stmt(s: &Stmt, mut state: &mut ScopeManager) -> (JsVar, Option<JsVar>) {
    match *s {
        // var_string = exp;
        Assign(ref var_string, ref exp) => {
            let (mut js_var, js_ptr) = eval_exp(exp, state);
            js_var.binding = Binding::new(var_string.clone());

            // Clone the js_var to store into the ScopeManager
            let cloned = js_var.clone();
            match state.alloc(cloned, js_ptr) {
                Ok(_) => (),
                e @ Err(_) => println!("{:?}", e),
            }

            (js_var, None)
        },

        // exp;
        BareExp(ref exp) => (eval_exp(exp, &mut state).0, None),

        // var var_string = exp
        Decl(ref var_string, ref exp) => {
            let (mut js_var, js_ptr) = eval_exp(exp, state);
            js_var.binding = Binding::new(var_string.clone());
            match state.alloc(js_var.clone(), js_ptr) {
                Ok(_) => (js_var, None),
                e @ Err(_) => panic!("{:?}", e),
            }
        },

        // if (condition) { if_block } else { else_block }
        If(ref condition, ref if_block, ref else_block) => {
            // evaluate expression
            if eval_exp(&condition, state).0.as_bool() {
                // condition = true, evaluate if-block.
                eval_stmt(&*if_block, state)
            } else {
                // condition = false
                // evaluate else-block if it exists, otherwise return undefined.
                if let Some(ref block) = *else_block {
                    eval_stmt(&*block, state)
                } else {
                    (JsVar::new(JsUndef), None)
                }
            }
        },

        // return exp
        Ret(ref exp) => {
            let js_var = eval_exp(&exp, &mut state).0;
            (js_var.clone(), Some(js_var))
        }

        // a sequence of any two expressions
        Seq(ref s1, ref s2) => {
            eval_stmt(&*s1, &mut state);
            eval_stmt(&*s2, &mut state)
        },

        // while (condition) { block }
        While(ref condition, ref block) => {
            let mut ret_val = None;
            loop {
                if eval_exp(&condition, state).0.as_bool() {
                    // TODO: check to see if a return stmt has been reached.
                    let (_, v) = eval_stmt(&*block, state);
                    ret_val = v;
                } else {
                    // condition is no longer true, return a return value
                    return (JsVar::new(JsUndef), ret_val);
                }
            }
        }
    }
}

/// Evaluate an expression into a JsVar.
pub fn eval_exp(e: &Exp, mut state: &mut ScopeManager) -> (JsVar, Option<JsPtrEnum>) {
    match e {
        // e1 [op] e2
        &BinExp(ref e1, ref op, ref e2) => {
            let val1 = eval_exp(e1, state).0;
            let val2 = eval_exp(e2, state).0;

            match *op {
                And => scalar(JsBool(val1.as_bool() && val2.as_bool())),
                Or  => scalar(JsBool(val1.as_bool() || val2.as_bool())),

                Ge  => scalar(JsBool(val1.as_bool() >= val2.as_bool())),
                Gt  => scalar(JsBool(val1.as_bool() >  val2.as_bool())),
                Le  => scalar(JsBool(val1.as_bool() <= val2.as_bool())),
                Lt  => scalar(JsBool(val1.as_bool() <  val2.as_bool())),
                Neq => scalar(JsBool(val1.as_bool() != val2.as_bool())),
                Eql => scalar(JsBool(val1.as_bool() == val2.as_bool())),

                Minus => scalar(JsNum(val1.as_number() - val2.as_number())),
                Plus  => scalar(JsNum(val1.as_number() + val2.as_number())),
                Slash => scalar(JsNum(val1.as_number() / val2.as_number())),
                Star  => scalar(JsNum(val1.as_number() * val2.as_number())),
            }
        }
        &Bool(b) => scalar(JsBool(b)),

        // fun_name([arg_exp1, arg_exps])
        &Call(ref fun_name, ref arg_exps) => {
            let fun_binding = eval_exp(fun_name, state).0;

            // Create vector of arguments, evaluated to JsVars.
            let mut args = Vec::new();
            for exp in arg_exps {
                args.push(eval_exp(exp, state));
            }

            match state.load(&fun_binding.binding) {
                Ok((_, Some(JsPtrEnum::JsFn(js_fn_struct)))) => {
                    state.push_scope();

                    for param in js_fn_struct.params {
                        let mut arg = if args.is_empty() {
                            scalar(JsUndef)
                        } else {
                            args.remove(0)
                        };

                        arg.0.binding = Binding::new(param.to_owned());
                        state.alloc(arg.0, arg.1)
                            .expect("Unable to store function argument in scope");
                    }

                    let (_, v) = eval_stmt(&js_fn_struct.stmt, state);

                    // Should we yield here? Not sure, so for now it doesn't
                    state.pop_scope(false).expect("Unable to clear scope for function");
                    // TODO handle obj
                    v.map(|x| (x, None)).unwrap_or(scalar(JsUndef))
                }
                Ok(_) => panic!("Invalid call object"),
                _ => panic!("ReferenceError: {} is not defined")
            }
        },

        // function([param1, params]) { body }
        // function opt_binding([param1, params]) { body }
        &Defun(ref opt_binding, ref params, ref body) => {
            if let &Some(ref binding) = opt_binding {
                let js_fun = JsFnStruct::new(opt_binding, params, &**body);
                state.alloc(JsVar::bind(binding.to_owned(), JsPtr),
                    Some(JsPtrEnum::JsFn(js_fun.clone())))
                    .expect("Error storing function into state");
                (JsVar::bind(binding.to_owned(), JsPtr), Some(JsPtrEnum::JsFn(js_fun)))
            } else {
                panic!("functions without bindings are not yet supported.")
            }
        },
        &Float(f) => scalar(JsType::JsNum(f)),
        &Neg(ref exp) => scalar(JsNum(-eval_exp(exp, state).0.as_number())),
        &Pos(ref exp) => scalar(JsNum(eval_exp(exp, state).0.as_number())),

        &PostDec(ref exp) => (eval_float_post_op!(exp, f, f - 1.0, state), None),
        &PostInc(ref exp) => (eval_float_post_op!(exp, f, f + 1.0, state), None),
        &PreDec(ref exp)  => (eval_float_pre_op!(exp, f, f - 1.0, state),  None),
        &PreInc(ref exp)  => (eval_float_pre_op!(exp, f, f + 1.0, state),  None),

        &NewObject(_, _) => unimplemented!(),
        &Object(ref fields) => {
            let mut kv_tuples = Vec::new();
            for f in fields {
                let f_key = JsKey::new(JsKeyEnum::JsStr(JsStrStruct::new(&f.0)));
                // TODO: handle obj as key/value pair
                let f_exp = eval_exp(&*f.1, state).0;
                kv_tuples.push((f_key, f_exp, None));
            }
            let obj = JsObjStruct::new(None, "", kv_tuples, &mut AllocBox::new());
            (JsVar::new(JsPtr), Some(JsPtrEnum::JsObj(obj)))
        },

        &Undefined => scalar(JsUndef),
        &Var(ref var_binding) => {
            state.load(&Binding::new(var_binding.clone()))
                .expect("ReferenceError: {} is not defined")
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::collections::hash_set::HashSet;
    use french_press::init_gc;
    use js_types::js_var::JsType;
    use js_types::binding::Binding;

    #[test]
    fn test_eval_literals() {
        let mut state = init_gc();
        assert_eq!(JsType::JsNum(5.0f64), eval_string("5.0;\n", &mut state).t);
        assert_eq!(JsType::JsNum(0.0f64), eval_string("0.0;\n", &mut state).t);
        assert_eq!(JsType::JsUndef, eval_string("undefined;\n", &mut state).t);
    }

    //// TODO: handle `var` and no `var` separately
    //#[test]
    //fn test_store_state() {
    //    let mut state = HashMap::new();
    //    assert_eq!(JsUndefined, eval_string("var a = 1;\n", &mut state));
    //    assert_eq!(JsNumber(2.0f64), eval_string("a = 2;\n", &mut state));
    //    assert_eq!(JsUndefined, eval_string("var b = 3;\n", &mut state));
    //    assert_eq!(JsNumber(4.0f64), eval_string("c = 4;\n", &mut state));
    //}

    #[test]
    fn test_inc_dec() {
        let mut state = init_gc();
        //assert_eq!(JsType::JsNum(1.0f64), eval_string("var a = 1;\n", &mut state).t);
        //assert_eq!(&JsType::JsNum(1.0), state.load(&Binding::new("a")).unwrap());

        //assert_eq!(JsType::JsNum(1.0f64), eval_string("a++;\n", &mut state));
        //assert_eq!(&JsNumber(2.0f64), state.get("a").unwrap());

        //assert_eq!(JsNumber(3.0f64), eval_string("++a;\n", &mut state));
        //assert_eq!(&JsNumber(3.0f64), state.get("a").unwrap());

        //assert_eq!(JsNumber(3.0f64), eval_string("a--;\n", &mut state));
        //assert_eq!(&JsNumber(2.0f64), state.get("a").unwrap());

        //assert_eq!(JsNumber(1.0f64), eval_string("--a;\n", &mut state));
        //assert_eq!(&JsNumber(1.0f64), state.get("a").unwrap());
    }

    #[test]
    fn test_binexp() {
        let mut state = init_gc();
        assert_eq!(JsType::JsNum(6.0f64),  eval_string("2.0 + 4.0;\n", &mut state).t);
        assert_eq!(JsType::JsNum(0.5f64),  eval_string("2.0 / 4.0;\n", &mut state).t);
        assert_eq!(JsType::JsNum(-2.0f64), eval_string("2.0 - 4.0;\n", &mut state).t);
        assert_eq!(JsType::JsNum(8.0f64),  eval_string("2.0 * 4.0;\n", &mut state).t);
    }
}
<commit_msg>Output var name on error<commit_after>#[macro_use]
mod macros;

use coerce::{AsBool,AsNumber};

use french_press::ScopeManager;
use french_press::alloc::AllocBox;
use js_types::binding::Binding;
use js_types::js_fn::JsFnStruct;
use js_types::js_obj::JsObjStruct;
use js_types::js_str::JsStrStruct;
use js_types::js_var::{JsVar, JsType, JsPtrEnum, JsKey, JsKeyEnum};
use js_types::js_var::JsType::*;

use jsrs_parser::lalr::parse_Stmt;
use jsrs_common::ast::*;
use jsrs_common::ast::Exp::*;
use jsrs_common::ast::BinOp::*;
use jsrs_common::ast::Stmt::*;

type VarWithPtr = (JsVar, Option<JsPtrEnum>);

// Helper to avoid repeating this everywhere
fn scalar(v: JsType) -> (JsVar, Option<JsPtrEnum>) {
    (JsVar::new(v), None)
}

/// Evaluate a string containing some JavaScript statements (or sequences of statements).
/// Returns a JsVar which is the return value of those statements.
pub fn eval_string(string: &str, state: &mut ScopeManager) -> JsVar {
    match parse_Stmt(string) {
        Ok(stmt) => {
            eval_stmt(&stmt, state).0
        }
        Err(e) => panic!("parse error: {:?}", e),
    }
}

/// Evaluate a single JS statement (which may be a block or sequence of statements).
/// Returns tuple of (evaluated final value, return value), where return value requires that
/// `return` be used to generate it.
pub fn eval_stmt(s: &Stmt, mut state: &mut ScopeManager) -> (JsVar, Option<JsVar>) {
    match *s {
        // var_string = exp;
        Assign(ref var_string, ref exp) => {
            let (mut js_var, js_ptr) = eval_exp(exp, state);
            js_var.binding = Binding::new(var_string.clone());

            // Clone the js_var to store into the ScopeManager
            let cloned = js_var.clone();
            match state.alloc(cloned, js_ptr) {
                Ok(_) => (),
                e @ Err(_) => println!("{:?}", e),
            }

            (js_var, None)
        },

        // exp;
        BareExp(ref exp) => (eval_exp(exp, &mut state).0, None),

        // var var_string = exp
        Decl(ref var_string, ref exp) => {
            let (mut js_var, js_ptr) = eval_exp(exp, state);
            js_var.binding = Binding::new(var_string.clone());
            match state.alloc(js_var.clone(), js_ptr) {
                Ok(_) => (js_var, None),
                e @ Err(_) => panic!("{:?}", e),
            }
        },

        // if (condition) { if_block } else { else_block }
        If(ref condition, ref if_block, ref else_block) => {
            // evaluate expression
            if eval_exp(&condition, state).0.as_bool() {
                // condition = true, evaluate if-block.
                eval_stmt(&*if_block, state)
            } else {
                // condition = false
                // evaluate else-block if it exists, otherwise return undefined.
                if let Some(ref block) = *else_block {
                    eval_stmt(&*block, state)
                } else {
                    (JsVar::new(JsUndef), None)
                }
            }
        },

        // return exp
        Ret(ref exp) => {
            let js_var = eval_exp(&exp, &mut state).0;
            (js_var.clone(), Some(js_var))
        }

        // a sequence of any two expressions
        Seq(ref s1, ref s2) => {
            eval_stmt(&*s1, &mut state);
            eval_stmt(&*s2, &mut state)
        },

        // while (condition) { block }
        While(ref condition, ref block) => {
            let mut ret_val = None;
            loop {
                if eval_exp(&condition, state).0.as_bool() {
                    // TODO: check to see if a return stmt has been reached.
                    let (_, v) = eval_stmt(&*block, state);
                    ret_val = v;
                } else {
                    // condition is no longer true, return a return value
                    return (JsVar::new(JsUndef), ret_val);
                }
            }
        }
    }
}

/// Evaluate an expression into a JsVar.
pub fn eval_exp(e: &Exp, mut state: &mut ScopeManager) -> (JsVar, Option<JsPtrEnum>) {
    match e {
        // e1 [op] e2
        &BinExp(ref e1, ref op, ref e2) => {
            let val1 = eval_exp(e1, state).0;
            let val2 = eval_exp(e2, state).0;

            match *op {
                And => scalar(JsBool(val1.as_bool() && val2.as_bool())),
                Or  => scalar(JsBool(val1.as_bool() || val2.as_bool())),

                Ge  => scalar(JsBool(val1.as_bool() >= val2.as_bool())),
                Gt  => scalar(JsBool(val1.as_bool() >  val2.as_bool())),
                Le  => scalar(JsBool(val1.as_bool() <= val2.as_bool())),
                Lt  => scalar(JsBool(val1.as_bool() <  val2.as_bool())),
                Neq => scalar(JsBool(val1.as_bool() != val2.as_bool())),
                Eql => scalar(JsBool(val1.as_bool() == val2.as_bool())),

                Minus => scalar(JsNum(val1.as_number() - val2.as_number())),
                Plus  => scalar(JsNum(val1.as_number() + val2.as_number())),
                Slash => scalar(JsNum(val1.as_number() / val2.as_number())),
                Star  => scalar(JsNum(val1.as_number() * val2.as_number())),
            }
        }
        &Bool(b) => scalar(JsBool(b)),

        // fun_name([arg_exp1, arg_exps])
        &Call(ref fun_name, ref arg_exps) => {
            let fun_binding = eval_exp(fun_name, state).0;

            // Create vector of arguments, evaluated to JsVars.
            let mut args = Vec::new();
            for exp in arg_exps {
                args.push(eval_exp(exp, state));
            }

            match state.load(&fun_binding.binding) {
                Ok((_, Some(JsPtrEnum::JsFn(js_fn_struct)))) => {
                    state.push_scope();

                    for param in js_fn_struct.params {
                        let mut arg = if args.is_empty() {
                            scalar(JsUndef)
                        } else {
                            args.remove(0)
                        };

                        arg.0.binding = Binding::new(param.to_owned());
                        state.alloc(arg.0, arg.1)
                            .expect("Unable to store function argument in scope");
                    }

                    let (_, v) = eval_stmt(&js_fn_struct.stmt, state);

                    // Should we yield here? Not sure, so for now it doesn't
                    state.pop_scope(false).expect("Unable to clear scope for function");
                    // TODO handle obj
                    v.map(|x| (x, None)).unwrap_or(scalar(JsUndef))
                }
                Ok(_) => panic!("Invalid call object"),
                _ => panic!("ReferenceError: {:?} is not defined", fun_name)
            }
        },

        // function([param1, params]) { body }
        // function opt_binding([param1, params]) { body }
        &Defun(ref opt_binding, ref params, ref body) => {
            if let &Some(ref binding) = opt_binding {
                let js_fun = JsFnStruct::new(opt_binding, params, &**body);
                state.alloc(JsVar::bind(binding.to_owned(), JsPtr),
                    Some(JsPtrEnum::JsFn(js_fun.clone())))
                    .expect("Error storing function into state");
                (JsVar::bind(binding.to_owned(), JsPtr), Some(JsPtrEnum::JsFn(js_fun)))
            } else {
                panic!("functions without bindings are not yet supported.")
            }
        },
        &Float(f) => scalar(JsType::JsNum(f)),
        &Neg(ref exp) => scalar(JsNum(-eval_exp(exp, state).0.as_number())),
        &Pos(ref exp) => scalar(JsNum(eval_exp(exp, state).0.as_number())),

        &PostDec(ref exp) => (eval_float_post_op!(exp, f, f - 1.0, state), None),
        &PostInc(ref exp) => (eval_float_post_op!(exp, f, f + 1.0, state), None),
        &PreDec(ref exp)  => (eval_float_pre_op!(exp, f, f - 1.0, state),  None),
        &PreInc(ref exp)  => (eval_float_pre_op!(exp, f, f + 1.0, state),  None),

        &NewObject(_, _) => unimplemented!(),
        &Object(ref fields) => {
            let mut kv_tuples = Vec::new();
            for f in fields {
                let f_key = JsKey::new(JsKeyEnum::JsStr(JsStrStruct::new(&f.0)));
                // TODO: handle obj as key/value pair
                let f_exp = eval_exp(&*f.1, state).0;
                kv_tuples.push((f_key, f_exp, None));
            }
            let obj = JsObjStruct::new(None, "", kv_tuples, &mut AllocBox::new());
            (JsVar::new(JsPtr), Some(JsPtrEnum::JsObj(obj)))
        },

        &Undefined => scalar(JsUndef),
        &Var(ref var_binding) => {
            state.load(&Binding::new(var_binding.clone()))
                .expect("ReferenceError: {} is not defined")
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::collections::hash_set::HashSet;
    use french_press::init_gc;
    use js_types::js_var::JsType;
    use js_types::binding::Binding;

    #[test]
    fn test_eval_literals() {
        let mut state = init_gc();
        assert_eq!(JsType::JsNum(5.0f64), eval_string("5.0;\n", &mut state).t);
        assert_eq!(JsType::JsNum(0.0f64), eval_string("0.0;\n", &mut state).t);
        assert_eq!(JsType::JsUndef, eval_string("undefined;\n", &mut state).t);
    }

    //// TODO: handle `var` and no `var` separately
    //#[test]
    //fn test_store_state() {
    //    let mut state = HashMap::new();
    //    assert_eq!(JsUndefined, eval_string("var a = 1;\n", &mut state));
    //    assert_eq!(JsNumber(2.0f64), eval_string("a = 2;\n", &mut state));
    //    assert_eq!(JsUndefined, eval_string("var b = 3;\n", &mut state));
    //    assert_eq!(JsNumber(4.0f64), eval_string("c = 4;\n", &mut state));
    //}

    #[test]
    fn test_inc_dec() {
        let mut state = init_gc();
        //assert_eq!(JsType::JsNum(1.0f64), eval_string("var a = 1;\n", &mut state).t);
        //assert_eq!(&JsType::JsNum(1.0), state.load(&Binding::new("a")).unwrap());

        //assert_eq!(JsType::JsNum(1.0f64), eval_string("a++;\n", &mut state));
        //assert_eq!(&JsNumber(2.0f64), state.get("a").unwrap());

        //assert_eq!(JsNumber(3.0f64), eval_string("++a;\n", &mut state));
        //assert_eq!(&JsNumber(3.0f64), state.get("a").unwrap());

        //assert_eq!(JsNumber(3.0f64), eval_string("a--;\n", &mut state));
        //assert_eq!(&JsNumber(2.0f64), state.get("a").unwrap());

        //assert_eq!(JsNumber(1.0f64), eval_string("--a;\n", &mut state));
        //assert_eq!(&JsNumber(1.0f64), state.get("a").unwrap());
    }

    #[test]
    fn test_binexp() {
        let mut state = init_gc();
        assert_eq!(JsType::JsNum(6.0f64),  eval_string("2.0 + 4.0;\n", &mut state).t);
        assert_eq!(JsType::JsNum(0.5f64),  eval_string("2.0 / 4.0;\n", &mut state).t);
        assert_eq!(JsType::JsNum(-2.0f64), eval_string("2.0 - 4.0;\n", &mut state).t);
        assert_eq!(JsType::JsNum(8.0f64),  eval_string("2.0 * 4.0;\n", &mut state).t);
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The GLFW-RS Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[cfg(feature = "glfw-sys")]
#[link(name = "glfw3", kind = "static")]
extern {}

#[cfg(not(feature = "glfw-sys"))]
// leaving off `kind = static` allows for the specification of a dynamic library if desired
#[cfg(target_family = "unix")]
#[link(name = "glfw")]
extern {}

#[cfg(not(feature = "glfw-sys"))]
#[cfg(target_family = "windows")]
#[link(name = "glfw3")]
extern {}

#[cfg(target_os="windows")]
#[link(name = "opengl32")]
#[link(name = "gdi32")]
#[link(name = "user32")]
extern {}

#[cfg(any(target_os="linux", target_os="freebsd", target_os="dragonfly"))]
#[link(name = "X11")]
#[link(name = "GL")]
#[link(name = "Xxf86vm")]
#[link(name = "Xrandr")]
#[link(name = "Xi")]
#[link(name = "Xcursor")]
#[link(name = "Xinerama")]
extern {}

#[cfg(target_os="macos")]
#[link(name = "Cocoa", kind = "framework")]
#[link(name = "OpenGL", kind = "framework")]
#[link(name = "IOKit", kind = "framework")]
#[link(name = "CoreFoundation", kind = "framework")]
#[link(name = "QuartzCore", kind = "framework")]
extern {}
<commit_msg>Link shell32 on windows<commit_after>// Copyright 2014 The GLFW-RS Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[cfg(feature = "glfw-sys")]
#[link(name = "glfw3", kind = "static")]
extern {}

#[cfg(not(feature = "glfw-sys"))]
// leaving off `kind = static` allows for the specification of a dynamic library if desired
#[cfg(target_family = "unix")]
#[link(name = "glfw")]
extern {}

#[cfg(not(feature = "glfw-sys"))]
#[cfg(target_family = "windows")]
#[link(name = "glfw3")]
extern {}

#[cfg(target_os="windows")]
#[link(name = "opengl32")]
#[link(name = "gdi32")]
#[link(name = "user32")]
#[link(name = "shell32")]
extern {}

#[cfg(any(target_os="linux", target_os="freebsd", target_os="dragonfly"))]
#[link(name = "X11")]
#[link(name = "GL")]
#[link(name = "Xxf86vm")]
#[link(name = "Xrandr")]
#[link(name = "Xi")]
#[link(name = "Xcursor")]
#[link(name = "Xinerama")]
extern {}

#[cfg(target_os="macos")]
#[link(name = "Cocoa", kind = "framework")]
#[link(name = "OpenGL", kind = "framework")]
#[link(name = "IOKit", kind = "framework")]
#[link(name = "CoreFoundation", kind = "framework")]
#[link(name = "QuartzCore", kind = "framework")]
extern {}
<|endoftext|>


<commit_before>#![feature(path_ext)]
extern crate rustc_serialize;
extern crate getopts;
extern crate xml;

use rustc_serialize::json::Json;
use getopts::Options;

mod lib;
use lib::*;

mod crc32;
use crc32::Crc32;

fn print_metatag(json: &Json) -> Result<(), Option<String>> {
    let event_name = json.as_array().ok_or(None)?[0].as_string().ok_or(None)?;
    let obj = &json.as_array().ok_or(None)?[1];
    let times = obj.find_path(&["keyframes", "times"]).ok_or(None)?.as_array().ok_or(None)?;
    let times: Vec<f64> = times.iter().map(|val: &Json| {
        val.as_f64().unwrap()
    }).collect();
    let filepositions = obj.find_path(&["keyframes", "filepositions"]).ok_or(None)?.as_array().ok_or(None)?;
    let filepositions: Vec<u64> = filepositions.iter().map(|val: &Json| {
        val.as_f64().unwrap() as u64
    }).collect();

    println!("metadata: {}", event_name);
    println!("{}", rustc_serialize::json::as_pretty_json(&obj));
    for (i, (t, p)) in (0u32..).zip(times.iter().zip(filepositions.iter())) {
        println!("{:3} {} {:8}", i, format_seconds_ms((t * 1000f64) as u64), p);
    }
    Ok(())
}

fn flv_info(path: &String, show_meta: bool, all_frame: bool) {
    use std::fs::File;
    use std::path::Path;
    use std::fs;

    let path = Path::new(path);
    if fs::metadata(path).is_err() {
        panic!(format!("file dosen't exist: {}", path.display()));
    }
    else {
        println!("show info for {}", path.display());
    }
    let mut file = File::open(path).unwrap();
    let file_meta = file.metadata().unwrap();
    let file_size = file_meta.len();
    println!("file size: {}", file_size);
    let mut parser = FLVTagRead::new(&mut file);//header has read

    println!("\r\ntags:", );
    let mut i = 0;
    loop {
        let position = parser.get_position();
        let tag = parser.next();
        if tag.is_none() {
            break;
        }
        let tag = tag.unwrap();
        match tag.get_tag_type() {
            FLVTagType::TAG_TYPE_VIDEO => {
                if tag.get_frame_type() == 1 {//key frames
                    println!("{:?}", (i, format_seconds_ms(tag.get_timestamp()), tag.get_tag_type(), tag.get_frame_type(), tag.get_codec_id(), tag.get_avc_packet_type(), position));
                    i += 1;
                }
                else if all_frame {
                    println!("{:?}", (i, format_seconds_ms(tag.get_timestamp()), tag.get_tag_type(), tag.get_frame_type(), tag.get_codec_id(), tag.get_avc_packet_type(), position));
                    i += 1;
                }
            },
            FLVTagType::TAG_TYPE_AUDIO => {
                if tag.is_acc_sequence_header() {
                    println!("{:?}", (i, format_seconds_ms(tag.get_timestamp()), tag.get_tag_type(), tag.get_data_size(), position));
                    i += 1;
                }
                else if all_frame {
                    println!("{:?}", (i, format_seconds_ms(tag.get_timestamp()), tag.get_tag_type(), tag.get_data_size(), position));
                    i += 1;
                }
            },
            FLVTagType::TAG_TYPE_SCRIPTDATAOBJECT => {
                if show_meta {
                    print_metatag(&Json::Array(tag.get_objects()));
                } else {
                    println!("metatag");
                }
                i += 1;
            }
        };
    }
}

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} FILE [options]", program);
    print!("{}", opts.usage(&brief));
}

fn main() {
    let args: Vec<String> = std::env::args().collect();
    let program = args[0].clone();

    let mut opts = Options::new();
    opts.optflag("m", "meta", "show metadata");
    opts.optflag("a", "all", "print all frames");
    opts.optflag("h", "help", "print this help menu");
    opts.optflag("c", "crc32", "calculate crc32 of tags");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => {
            panic!(f.to_string())
        }
    };
    if matches.opt_present("h") {
        print_usage(&program, opts);
        return;
    }
    let input = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        print_usage(&program, opts);
        return;
    };
    let show_meta = matches.opt_present("m");
    let all_frame = matches.opt_present("a");
    let crc32_file = matches.opt_present("c");
    if crc32_file {
        flv_crc32(&input);
    } else {
        flv_info(&input, show_meta, all_frame);
    }
}

fn flv_crc32(path: &String) {
    use std::fs::File;
    use std::io::Write;

    let mut file = File::open(&path).unwrap();
    let mut parser = FLVTagRead::new(&mut file);

    let mut i = 0;
    let mut key_time: f64 = 0f64;
    let mut key_pos: u64 = 0;
    let mut tmp: Vec<u32> = Vec::new();
    let mut ret: Vec<Json> = Vec::new();
    loop {
        let position = parser.get_position();
        let tag = parser.next();
        if tag.is_none() {
            break;
        }

        let tag = tag.unwrap();
        let mut bytes: Vec<u8> = Vec::with_capacity(tag.get_tag_size() as usize);
        tag.write(&mut bytes);
        let mut hash = Crc32::new();
        hash.update(&bytes);
        let crc32_hash: u32 = hash.finish();
        if tag.get_tag_type() == FLVTagType::TAG_TYPE_VIDEO && tag.get_frame_type() == 1 {
            if tmp.len() > 0 {
                ret.push(output_info(key_pos, key_time, &mut tmp));
            }
            key_pos = position;
            key_time = tag.get_timestamp() as f64 / 1000f64;
        }
        tmp.push(crc32_hash);
    }
    if tmp.len() > 0 {
        ret.push(output_info(key_pos, key_time, &mut tmp));
    }

    // println!("{}", rustc_serialize::json::as_pretty_json(&Json::Array(ret)));
    let output_path = format!("{}{}", path, ".crc32.json");
    let mut output_file = File::create(output_path).unwrap();
    write!(output_file, "{}", rustc_serialize::json::as_pretty_json(&Json::Array(ret)));
}

fn output_info(key_pos: u64, key_time: f64, crc_list: &mut Vec<u32>) -> Json {
    use std::collections::BTreeMap;

    let mut obj: BTreeMap<String, Json> = BTreeMap::new();
    obj.insert("offset".to_string(), Json::U64(key_pos));
    obj.insert("time".to_string(), Json::F64(key_time));
    obj.insert("tags".to_string(), Json::Array(crc_list.iter().map(|i| Json::U64(*i as u64)).collect()));
    crc_list.clear();
    Json::Object(obj)
}<commit_msg>change crc output format<commit_after>#![feature(path_ext)]
extern crate rustc_serialize;
extern crate getopts;
extern crate xml;

use rustc_serialize::json::Json;
use getopts::Options;

mod lib;
use lib::*;

mod crc32;
use crc32::Crc32;

fn print_metatag(json: &Json) -> Result<(), Option<String>> {
    let event_name = json.as_array().ok_or(None)?[0].as_string().ok_or(None)?;
    let obj = &json.as_array().ok_or(None)?[1];
    let times = obj.find_path(&["keyframes", "times"]).ok_or(None)?.as_array().ok_or(None)?;
    let times: Vec<f64> = times.iter().map(|val: &Json| {
        val.as_f64().unwrap()
    }).collect();
    let filepositions = obj.find_path(&["keyframes", "filepositions"]).ok_or(None)?.as_array().ok_or(None)?;
    let filepositions: Vec<u64> = filepositions.iter().map(|val: &Json| {
        val.as_f64().unwrap() as u64
    }).collect();

    println!("metadata: {}", event_name);
    println!("{}", rustc_serialize::json::as_pretty_json(&obj));
    for (i, (t, p)) in (0u32..).zip(times.iter().zip(filepositions.iter())) {
        println!("{:3} {} {:8}", i, format_seconds_ms((t * 1000f64) as u64), p);
    }
    Ok(())
}

fn flv_info(path: &String, show_meta: bool, all_frame: bool) {
    use std::fs::File;
    use std::path::Path;
    use std::fs;

    let path = Path::new(path);
    if fs::metadata(path).is_err() {
        panic!(format!("file dosen't exist: {}", path.display()));
    }
    else {
        println!("show info for {}", path.display());
    }
    let mut file = File::open(path).unwrap();
    let file_meta = file.metadata().unwrap();
    let file_size = file_meta.len();
    println!("file size: {}", file_size);
    let mut parser = FLVTagRead::new(&mut file);//header has read

    println!("\r\ntags:", );
    let mut i = 0;
    loop {
        let position = parser.get_position();
        let tag = parser.next();
        if tag.is_none() {
            break;
        }
        let tag = tag.unwrap();
        match tag.get_tag_type() {
            FLVTagType::TAG_TYPE_VIDEO => {
                if tag.get_frame_type() == 1 {//key frames
                    println!("{:?}", (i, format_seconds_ms(tag.get_timestamp()), tag.get_tag_type(), tag.get_frame_type(), tag.get_codec_id(), tag.get_avc_packet_type(), position));
                    i += 1;
                }
                else if all_frame {
                    println!("{:?}", (i, format_seconds_ms(tag.get_timestamp()), tag.get_tag_type(), tag.get_frame_type(), tag.get_codec_id(), tag.get_avc_packet_type(), position));
                    i += 1;
                }
            },
            FLVTagType::TAG_TYPE_AUDIO => {
                if tag.is_acc_sequence_header() {
                    println!("{:?}", (i, format_seconds_ms(tag.get_timestamp()), tag.get_tag_type(), tag.get_data_size(), position));
                    i += 1;
                }
                else if all_frame {
                    println!("{:?}", (i, format_seconds_ms(tag.get_timestamp()), tag.get_tag_type(), tag.get_data_size(), position));
                    i += 1;
                }
            },
            FLVTagType::TAG_TYPE_SCRIPTDATAOBJECT => {
                if show_meta {
                    print_metatag(&Json::Array(tag.get_objects()));
                } else {
                    println!("metatag");
                }
                i += 1;
            }
        };
    }
}

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} FILE [options]", program);
    print!("{}", opts.usage(&brief));
}

fn main() {
    let args: Vec<String> = std::env::args().collect();
    let program = args[0].clone();

    let mut opts = Options::new();
    opts.optflag("m", "meta", "show metadata");
    opts.optflag("a", "all", "print all frames");
    opts.optflag("h", "help", "print this help menu");
    opts.optflag("c", "crc32", "calculate crc32 of tags");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => {
            panic!(f.to_string())
        }
    };
    if matches.opt_present("h") {
        print_usage(&program, opts);
        return;
    }
    let input = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        print_usage(&program, opts);
        return;
    };
    let show_meta = matches.opt_present("m");
    let all_frame = matches.opt_present("a");
    let crc32_file = matches.opt_present("c");
    if crc32_file {
        flv_crc32(&input);
    } else {
        flv_info(&input, show_meta, all_frame);
    }
}

fn flv_crc32(path: &String) {
    use std::fs::File;
    use std::io::Write;

    let mut file = File::open(&path).unwrap();
    let mut parser = FLVTagRead::new(&mut file);

    let mut i = 0;
    let mut key_time: f64 = 0f64;
    let mut key_pos: u64 = 0;
    let mut tmp: Vec<u32> = Vec::new();
    let mut ret: Vec<Json> = Vec::new();
    loop {
        let position = parser.get_position();
        let tag = parser.next();
        if tag.is_none() {
            break;
        }

        let tag = tag.unwrap();
        let mut bytes: Vec<u8> = Vec::with_capacity(tag.get_tag_size() as usize);
        tag.write(&mut bytes);
        let mut hash = Crc32::new();
        hash.update(&bytes);
        let crc32_hash: u32 = hash.finish();
        if tag.get_tag_type() == FLVTagType::TAG_TYPE_VIDEO && tag.get_frame_type() == 1 {
            if tmp.len() > 0 {
                ret.push(output_info(key_pos, key_time, &mut tmp));
            }
            key_pos = position;
            key_time = tag.get_timestamp() as f64 / 1000f64;
        }
        tmp.push(crc32_hash);
    }
    if tmp.len() > 0 {
        ret.push(output_info(key_pos, key_time, &mut tmp));
    }

    // println!("{}", rustc_serialize::json::as_pretty_json(&Json::Array(ret)));
    let output_path = format!("{}{}", path, ".crc32.json");
    let mut output_file = File::create(output_path).unwrap();
    write!(output_file, "{}", rustc_serialize::json::as_pretty_json(&Json::Array(ret)));
}

fn output_info(key_pos: u64, key_time: f64, crc_list: &mut Vec<u32>) -> Json {
    use std::collections::BTreeMap;
    let mut arr: Vec<Json> =
        vec![("time"  , Json::F64(key_time)),
             ("offset", Json::U64(key_pos)),
             ("tags"  , Json::Array(crc_list.iter().map(|i| Json::U64(*i as u64)).collect()))]
            .into_iter().map(|(key, json)| {
                let mut obj: BTreeMap<String, Json> = BTreeMap::new();
                obj.insert(key.to_string(), json);
                Json::Object(obj)
            }).collect();

    crc_list.clear();
    Json::Array(arr)
}<|endoftext|>


<commit_before>//! This module is for everything about the rules of chess.

pub use self::color::{Color, White, Black};
pub use self::piece::Piece;
pub use self::piece::Type as PieceType;
pub use self::piece::{WP,WK,WQ,WB,WN,WR};
pub use self::piece::{BP,BK,BQ,BB,BN,BR};
pub use self::piece::Type::{Pawn,King,Queen,Bishop,Knight,Rook};
pub use self::moves::{Move, FromTo};
pub use self::pos::Position;
pub use self::fen::{fen_to_position, start_pos};
pub use self::legal::receive_legal;
pub use self::make_move::{make_move};
pub use self::mate::{is_checkmated, is_stalemated};
pub use self::mate::{is_checkmate, is_stalemate};

mod color;
mod piece;
mod square;
mod moves;

mod bitboard;
mod board;
mod castle;
mod pos;

mod fen;
mod gen;

mod legal;
mod make_move;

mod mate;

#[cfg(test)]
mod tests;
<commit_msg>Make game::pos public<commit_after>//! This module is for everything about the rules of chess.

pub use self::color::{Color, White, Black};
pub use self::piece::Piece;
pub use self::piece::Type as PieceType;
pub use self::piece::{WP,WK,WQ,WB,WN,WR};
pub use self::piece::{BP,BK,BQ,BB,BN,BR};
pub use self::piece::Type::{Pawn,King,Queen,Bishop,Knight,Rook};
pub use self::moves::{Move, FromTo};
pub use self::pos::Position;
pub use self::fen::{fen_to_position, start_pos};
pub use self::legal::receive_legal;
pub use self::make_move::{make_move};
pub use self::mate::{is_checkmated, is_stalemated};
pub use self::mate::{is_checkmate, is_stalemate};

mod color;
mod piece;
mod square;
mod moves;

mod bitboard;
mod board;
mod castle;
pub mod pos;

mod fen;
mod gen;

mod legal;
mod make_move;

mod mate;

#[cfg(test)]
mod tests;
<|endoftext|>


<commit_before>pub type Row = [Player; 3];

pub type Field = [Row; 3];

pub type Coords = (usize, usize);

/// Must return `Coords` or `None` if a player chooses to surrender.
pub type PlayerController = fn(game: &Game) -> Option<Coords>;

#[derive(Copy, Clone, PartialEq)]
pub enum Player {
    Nobody,
    X,
    O,
}

pub struct Game {
    current_player: Player,
    field: Field,
    player1: PlayerController,
    player2: PlayerController,
}

impl Game {
    pub fn new(player1: PlayerController, player2: PlayerController) -> Game {
        Game {
            field: [[Player::Nobody; 3]; 3],
            current_player: Player::X,
            player1: player1,
            player2: player2,
        }
    }

    pub fn field(&self) -> &Field {
        &self.field
    }

    pub fn current_player(&self) -> Player {
        self.current_player
    }

    pub fn play(&mut self) -> Player {
        loop {
            match self.current_player_coords() {
                Some((row, col)) => {
                    if !self.cell_is_empty((row, col)) {
                        panic!("player tries to set occupied cell - cheating!")
                    }
                    self.field[row][col] = self.current_player;
                },
                _ => { self.switch_player(); return self.current_player },
            };

            match self.winner() {
                Some(winner) => return winner,
                _ => self.switch_player(),
            }
        }
    }

    pub fn cell_is_empty(&self, coords: Coords) -> bool {
        let (row, col) = coords;
        self.field[row][col] == Player::Nobody
    }

    fn current_player_coords(&self) -> Option<Coords> {
        match self.current_player {
            Player::X => (self.player1)(&self),
            Player::O => (self.player2)(&self),
            _ => panic!("current player can't be Nobody"),
        }
    }

    fn switch_player(&mut self) {
        if self.current_player == Player::X {
            self.current_player = Player::O
        } else if self.current_player == Player::O {
            self.current_player = Player::X
        }
    }

    /// Returns `Player` if it is already defined, otherwise `None`.
    fn winner(&self) -> Option<Player> {
        self.row_winner(self.row(0))
            .or( self.row_winner(self.row(1)) )
            .or( self.row_winner(self.row(2)) )
            .or( self.row_winner(self.col(0)) )
            .or( self.row_winner(self.col(1)) )
            .or( self.row_winner(self.col(2)) )
            .or( self.row_winner(self.diagonal()) )
            .or( self.row_winner(self.reverse_diagonal()) )
            .or( if self.has_empty_cell() { None } else { Some(Player::Nobody) } )
    }

    fn has_empty_cell(&self) -> bool {
        for row in &self.field {
            for col in row {
                if *col == Player::Nobody {
                    return true;
                }
            }
        }
        false
    }

    /// Returns `Player` if it is already defined, otherwise `None`.
    fn row_winner(&self, row: Vec<Player>) -> Option<Player> {
        if row[0] != Player::Nobody && row[0] == row[1] && row[1] == row[2] {
            Some(row[0])
        } else {
            None
        }
    }

    fn row(&self, number: usize) -> Vec<Player> {
        self.field[number].to_vec()
    }

    fn col(&self, number: usize) -> Vec<Player> {
        self.field.iter().map(|row| row[number]).collect()
    }

    fn diagonal(&self) -> Vec<Player> {
        self.field.iter().enumerate().map(|(i, row)| row[0 + i]).collect()
    }

    fn reverse_diagonal(&self) -> Vec<Player> {
        self.field.iter().enumerate().map(|(i, row)| row[2 - i]).collect()
    }

}
<commit_msg>Make Game::winner function public and static<commit_after>pub type Row = [Player; 3];

pub type Field = [Row; 3];

pub type Coords = (usize, usize);

/// Must return `Coords` or `None` if a player chooses to surrender.
pub type PlayerController = fn(game: &Game) -> Option<Coords>;

#[derive(Copy, Clone, PartialEq)]
pub enum Player {
    Nobody,
    X,
    O,
}

pub struct Game {
    current_player: Player,
    field: Field,
    player1: PlayerController,
    player2: PlayerController,
}

impl Game {
    pub fn new(player1: PlayerController, player2: PlayerController) -> Game {
        Game {
            field: [[Player::Nobody; 3]; 3],
            current_player: Player::X,
            player1: player1,
            player2: player2,
        }
    }

    pub fn field(&self) -> &Field {
        &self.field
    }

    pub fn current_player(&self) -> Player {
        self.current_player
    }

    pub fn play(&mut self) -> Player {
        loop {
            match self.current_player_coords() {
                Some((row, col)) => {
                    if !self.cell_is_empty((row, col)) {
                        panic!("player tries to set occupied cell - cheating!")
                    }
                    self.field[row][col] = self.current_player;
                },
                _ => { self.switch_player(); return self.current_player },
            };

            match Self::winner(&self.field) {
                Some(winner) => return winner,
                _ => self.switch_player(),
            }
        }
    }

    pub fn cell_is_empty(&self, coords: Coords) -> bool {
        let (row, col) = coords;
        self.field[row][col] == Player::Nobody
    }

    fn current_player_coords(&self) -> Option<Coords> {
        match self.current_player {
            Player::X => (self.player1)(&self),
            Player::O => (self.player2)(&self),
            _ => panic!("current player can't be Nobody"),
        }
    }

    fn switch_player(&mut self) {
        if self.current_player == Player::X {
            self.current_player = Player::O
        } else if self.current_player == Player::O {
            self.current_player = Player::X
        }
    }

    /// Returns `Player` if it is already defined, otherwise `None`.
    pub fn winner(field: &Field) -> Option<Player> {
        Self::row_winner(Self::row(&field, 0))
            .or( Self::row_winner(Self::row(&field, 1)) )
            .or( Self::row_winner(Self::row(&field, 2)) )
            .or( Self::row_winner(Self::col(&field, 0)) )
            .or( Self::row_winner(Self::col(&field, 1)) )
            .or( Self::row_winner(Self::col(&field, 2)) )
            .or( Self::row_winner(Self::diagonal(&field)) )
            .or( Self::row_winner(Self::reverse_diagonal(&field)) )
            .or( if Self::has_empty_cell(&field) { None } else { Some(Player::Nobody) } )
    }

    fn has_empty_cell(field: &Field) -> bool {
        for row in field {
            for col in row {
                if *col == Player::Nobody {
                    return true;
                }
            }
        }
        false
    }

    /// Returns `Player` if it is already defined, otherwise `None`.
    fn row_winner(row: Vec<Player>) -> Option<Player> {
        if row[0] != Player::Nobody && row[0] == row[1] && row[1] == row[2] {
            Some(row[0])
        } else {
            None
        }
    }

    fn row(field: &Field, number: usize) -> Vec<Player> {
        field[number].to_vec()
    }

    fn col(field: &Field, number: usize) -> Vec<Player> {
        field.iter().map(|row| row[number]).collect()
    }

    fn diagonal(field: &Field) -> Vec<Player> {
        field.iter().enumerate().map(|(i, row)| row[0 + i]).collect()
    }

    fn reverse_diagonal(field: &Field) -> Vec<Player> {
        field.iter().enumerate().map(|(i, row)| row[2 - i]).collect()
    }

}
<|endoftext|>


<commit_before>use enum_primitive::FromPrimitive;

use map;
use room::Room;
use platform::random_i32;
use direction::Direction::*;

use self::RoomId::*;
use self::RoomContents::*;

const DEBUG: bool = false;
const NUM_ROOMS: usize = 19;
const NUM_MONSTERS: usize = 4;
const NUM_ROOMS_WITH_TREASURE: usize = 4;
const NUM_ROOMS_WITH_TERROR: usize = 4;
const MIN_TREASURE_AMOUNT: u8 = 10;
const MAX_TREASURE_AMOUNT: u8 = 110;

enum_from_primitive! {
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum RoomId {
  Hallway = 0,
  AudienceChamber = 1,
  GreatHall = 2,
  PrivateMeeting = 3,
  InnerHallway = 4,
  Entrance = 5,
  Kitchen = 6,
  StoreRoom = 7,
  Lift = 8,
  RearVestibule = 9,
  Exit = 10,
  Dungeon = 11,
  Guardroom = 12,
  MasterBedroom = 13,
  UpperHallway = 14,
  Treasury = 15,
  ChambermaidsBedroom = 16,
  DressingChamber = 17,
  SmallRoom = 18,
}
}

enum_from_primitive! {
#[derive(Debug, Copy, Clone)]
pub enum MonsterId {
  Werewolf = 0,
  Fleshgorger = 1,
  Maldemer = 2,
  Dragon = 3,
}
}

#[derive(Debug, Copy, Clone)]
pub enum RoomContents {
  Treasure(u8),
  Terror(MonsterId),
}

pub type GameMap<'a> = map::Map<'a, RoomId, RoomContents>;

impl<'a> GameMap<'a> {
  pub fn create_rooms() -> [Room<RoomId, RoomContents>; NUM_ROOMS] {
    [Room::new(); NUM_ROOMS]
  }

  pub fn populate(&mut self) {
    self.describe_and_connect();
    self.allot_treasure();
    self.allot_terror();
    self.ensure_treasure();
  }

  fn allot<F>(&mut self, num_rooms: usize, allotter: F)
    where F: Fn() -> RoomContents
  {
    for _ in 0..num_rooms {
      loop {
        let room_id = random_room_id();
        if room_id != Entrance && room_id != Exit {
          let room = self.room(room_id);
          if room.contents.is_none() {
            let contents = allotter();
            if DEBUG {
              println!("DEBUG: Placing {:?} in {:?}.", contents, room_id);
            }
            room.contents = Some(contents);
            break;
          }
        }
      }
    }
  }

  fn allot_terror(&mut self) {
    self.allot(NUM_ROOMS_WITH_TERROR, || Terror(random_monster_id()))
  }

  fn allot_treasure(&mut self) {
    self.allot(NUM_ROOMS_WITH_TREASURE,
               || Treasure(random_treasure_amount()))
  }

  fn ensure_treasure(&mut self) {
    for &room_id in [Treasury, PrivateMeeting].iter() {
      let amount = random_treasure_amount();
      if DEBUG {
        println!("DEBUG: Placing ${} in {:?}.", amount, room_id);
      }
      self.room(room_id).contents = Some(Treasure(amount));
    }
  }

  fn describe_and_connect(&mut self) {
    self.room(Entrance).describe(
      "Entrance",
      "You are at the entrance to a forbidding-looking \
       stone castle. You are facing east."
    );

    self.room(Hallway).describe(
      "Hallway",
      "You are in the hallway. \
       There is a door to the south. \
       Through the windows to the north you can see a secret herb garden."
    );

    self.room(AudienceChamber).describe(
      "Audience Chamber",
      "This is the audience chamber. \
       There is a window to the west. By looking to the right \
       through it you can see the entrance to the castle. \
       Doors leave this room to the north, east, and south."
    );

    self.connect(Entrance, East, Hallway);
    self.connect(Hallway, South, AudienceChamber);
  }
}

fn random_enum<T: FromPrimitive>(size: usize) -> T {
  loop {
    let r = random_i32(0, size as i32);
    match T::from_i32(r) {
      Some(t) => { return t; },
      None => {}
    }
  }
}

fn random_room_id() -> RoomId {
  random_enum(NUM_ROOMS)
}

fn random_monster_id() -> MonsterId {
  random_enum(NUM_MONSTERS)
}

fn random_treasure_amount() -> u8 {
  random_i32(MIN_TREASURE_AMOUNT as i32, MAX_TREASURE_AMOUNT as i32) as u8
}

// Ideally we'd actually just get rid of MapRoomId and add a constraint
// to Map<T> requiring that T be type-castable as usize, but I don't
// know how to do that, so...
impl map::MapRoomId for RoomId {
  fn room_id(self) -> usize { self as usize }
}
<commit_msg>Add SizedEnum trait.<commit_after>use enum_primitive::FromPrimitive;

use map;
use room::Room;
use platform::random_i32;
use direction::Direction::*;

use self::RoomId::*;
use self::RoomContents::*;

const DEBUG: bool = false;
const NUM_ROOMS: usize = 19;
const NUM_MONSTERS: usize = 4;
const NUM_ROOMS_WITH_TREASURE: usize = 4;
const NUM_ROOMS_WITH_TERROR: usize = 4;
const MIN_TREASURE_AMOUNT: u8 = 10;
const MAX_TREASURE_AMOUNT: u8 = 110;

// There doesn't seem to be a convenient way to get the "size" or
// "range" of an enum's possible values, so we'll make a trait for
// that here.
//
// Ideally we could populate it automatically through a macro, but
// for now we'll just implement it manually for all our enums.
trait SizedEnum {
  fn size() -> usize;
}

enum_from_primitive! {
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum RoomId {
  Hallway = 0,
  AudienceChamber = 1,
  GreatHall = 2,
  PrivateMeeting = 3,
  InnerHallway = 4,
  Entrance = 5,
  Kitchen = 6,
  StoreRoom = 7,
  Lift = 8,
  RearVestibule = 9,
  Exit = 10,
  Dungeon = 11,
  Guardroom = 12,
  MasterBedroom = 13,
  UpperHallway = 14,
  Treasury = 15,
  ChambermaidsBedroom = 16,
  DressingChamber = 17,
  SmallRoom = 18,
}
}

impl SizedEnum for RoomId {
  fn size() -> usize { NUM_ROOMS }
}

enum_from_primitive! {
#[derive(Debug, Copy, Clone)]
pub enum MonsterId {
  Werewolf = 0,
  Fleshgorger = 1,
  Maldemer = 2,
  Dragon = 3,
}
}

impl SizedEnum for MonsterId {
  fn size() -> usize { NUM_MONSTERS }
}

#[derive(Debug, Copy, Clone)]
pub enum RoomContents {
  Treasure(u8),
  Terror(MonsterId),
}

pub type GameMap<'a> = map::Map<'a, RoomId, RoomContents>;

impl<'a> GameMap<'a> {
  pub fn create_rooms() -> [Room<RoomId, RoomContents>; NUM_ROOMS] {
    [Room::new(); NUM_ROOMS]
  }

  pub fn populate(&mut self) {
    self.describe_and_connect();
    self.allot_treasure();
    self.allot_terror();
    self.ensure_treasure();
  }

  fn allot<F>(&mut self, num_rooms: usize, allotter: F)
    where F: Fn() -> RoomContents
  {
    for _ in 0..num_rooms {
      loop {
        let room_id = random_enum::<RoomId>();
        if room_id != Entrance && room_id != Exit {
          let room = self.room(room_id);
          if room.contents.is_none() {
            let contents = allotter();
            if DEBUG {
              println!("DEBUG: Placing {:?} in {:?}.", contents, room_id);
            }
            room.contents = Some(contents);
            break;
          }
        }
      }
    }
  }

  fn allot_terror(&mut self) {
    self.allot(NUM_ROOMS_WITH_TERROR, || Terror(random_enum::<MonsterId>()))
  }

  fn allot_treasure(&mut self) {
    self.allot(NUM_ROOMS_WITH_TREASURE,
               || Treasure(random_treasure_amount()))
  }

  fn ensure_treasure(&mut self) {
    for &room_id in [Treasury, PrivateMeeting].iter() {
      let amount = random_treasure_amount();
      if DEBUG {
        println!("DEBUG: Placing ${} in {:?}.", amount, room_id);
      }
      self.room(room_id).contents = Some(Treasure(amount));
    }
  }

  fn describe_and_connect(&mut self) {
    self.room(Entrance).describe(
      "Entrance",
      "You are at the entrance to a forbidding-looking \
       stone castle. You are facing east."
    );

    self.room(Hallway).describe(
      "Hallway",
      "You are in the hallway. \
       There is a door to the south. \
       Through the windows to the north you can see a secret herb garden."
    );

    self.room(AudienceChamber).describe(
      "Audience Chamber",
      "This is the audience chamber. \
       There is a window to the west. By looking to the right \
       through it you can see the entrance to the castle. \
       Doors leave this room to the north, east, and south."
    );

    self.connect(Entrance, East, Hallway);
    self.connect(Hallway, South, AudienceChamber);
  }
}

fn random_enum<T: FromPrimitive + SizedEnum>() -> T {
  loop {
    let r = random_i32(0, T::size() as i32);
    match T::from_i32(r) {
      Some(t) => { return t; },
      None => {}
    }
  }
}

fn random_treasure_amount() -> u8 {
  random_i32(MIN_TREASURE_AMOUNT as i32, MAX_TREASURE_AMOUNT as i32) as u8
}

// Ideally we'd actually just get rid of MapRoomId and add a constraint
// to Map<T> requiring that T be type-castable as usize, but I don't
// know how to do that, so...
impl map::MapRoomId for RoomId {
  fn room_id(self) -> usize { self as usize }
}
<|endoftext|>


<commit_before>use rand::{thread_rng, Rng};
use itertools::Zip;
use std::ops::BitXor;
use std::cmp::{PartialOrd, Ordering};

/// Hash length in bits. Generally 160 for Kademlia variants.
pub const HASH_SIZE : usize = 160;
pub const HASH_SIZE_BYTES : usize = HASH_SIZE / 8;

/// Light wrapper over a little endian `HASH_SIZE` bit hash
///
/// We aren't interested in strong cryptography, but rather
/// a simple way to generate `HASH_SIZE` bit key identifiers.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Hash {
   pub raw : [u8; HASH_SIZE_BYTES],
}

impl Hash {
   /// Generates a blank hash (every bit set to 0).
   pub fn blank() -> Hash {
      Hash { raw : [0; HASH_SIZE_BYTES] }
   }

   /// Generates a random hash via kernel supplied entropy.
   pub fn random() -> Hash {
      let mut hash = Hash::blank();
      thread_rng().fill_bytes(&mut hash.raw);
      hash
   }

   /// Provides an iterator through the indices
   /// of each of its "0" bits.
   pub fn zeroes(&self) -> Zeroes {
      Zeroes {
         hash  : self,
         index : 0,
         rev   : HASH_SIZE
      }
   }

   /// Provides an iterator through the indices
   /// of each of its "1" bits.
   pub fn ones(&self) -> Ones {
      Ones {
         hash  : self,
         index : 0,
         rev   : HASH_SIZE
      }
   }

   /// Computes the bit index of the highest "1". Returns None for a blank hash.
   pub fn height(&self) -> Option<usize> {
      let last_nonzero_byte = self.raw.iter().enumerate().rev().find(|&pair| *pair.1 != 0);
      if let Some((index, byte)) = last_nonzero_byte {
         for bit in (0..8).rev() {
            if (byte & (1 << bit)) != 0 {
               return Some((8 * index + bit) as usize)
            }
         }
      }
      None
   }

   /// Flips a random bit somewhere in the hash.
   pub fn flip_bit(&mut self, position : usize) {
      if position >= HASH_SIZE { return; }
      let byte = &mut self.raw[position / 8];
      *byte ^= 1 << (position % 8);
   }
}

/// Iterator through the indices of each '0' in a hash.
pub struct Zeroes<'a> {
   hash  : &'a Hash,
   index : usize,
   rev   : usize
}

/// Iterator through the indices of each '1' in a hash.
pub struct Ones<'a> {
   hash  : &'a Hash,
   index : usize,
   rev   : usize,
}

impl<'a> Iterator for Zeroes<'a> {
   type Item = usize;

   fn next(&mut self) -> Option<usize> {
      while self.index < self.rev {
         let value_at_index = self.hash.raw[self.index / 8] & (1 << (self.index % 8));
         self.index += 1;
         if value_at_index == 0 {
            return Some(self.index - 1);
         }
      }
      None
   }
}

impl<'a> Iterator for Ones<'a> {
   type Item = usize;

   fn next(&mut self) -> Option<usize> {
      while self.index < self.rev {
         let value_at_index = self.hash.raw[self.index / 8] & (1 << (self.index % 8));
         self.index += 1;
         if value_at_index != 0 {
            return Some(self.index - 1);
         }
      }
      None
   }
}

impl<'a> DoubleEndedIterator for Zeroes<'a> {
   fn next_back(&mut self) -> Option<usize> {
      while self.index < self.rev {
         let value_at_rev = self.hash.raw[(self.rev-1) / 8] & (1 << ((self.rev-1) % 8));
         self.rev -= 1;
         if value_at_rev == 0 {
            return Some(self.rev);
         }
      }
      None
   }
}

impl<'a> DoubleEndedIterator for Ones<'a> {
   fn next_back(&mut self) -> Option<usize> {
      while self.index < self.rev {
         let value_at_rev = self.hash.raw[(self.rev-1) / 8] & (1 << ((self.rev-1) % 8));
         self.rev -= 1;
         if value_at_rev != 0 {
            return Some(self.rev);
         }
      }
      None
   }
}

impl PartialOrd for Hash {
   fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
      for (a,b) in self.raw.iter().rev().zip(other.raw.iter().rev()) {
         match a.cmp(b) {
            Ordering::Less => return Some(Ordering::Less),
            Ordering::Greater => return Some(Ordering::Greater),
            Ordering::Equal => ()
         }
      }
      None
   }
}

impl Ord for Hash {
   fn cmp(&self, other: &Self) -> Ordering {
      match self.partial_cmp(other) {
         Some(order) => order,
         None => Ordering::Equal
      }
   }
}

impl<'a, 'b> BitXor<&'b Hash> for &'a Hash {
   type Output = Hash;

   fn bitxor (self, rhs: &'b Hash) -> Hash {
      let mut result = Hash::blank();
      for (d, a, b) in Zip::new((&mut result.raw, &self.raw, &rhs.raw)) {
         *d = a^b;
      }
      result
   }
}

impl BitXor for Hash {
   type Output = Hash;

   fn bitxor (self, rhs: Self) -> Hash {
      let mut raw = self.raw;
      for (a, b) in raw.iter_mut().zip(rhs.raw.iter()) {
         *a ^= *b;
      }
      self
   }
}

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

    #[test]
    fn random_generation() {
       assert!(Hash::random() != Hash::random());
    }

    #[test]
    fn computing_height() {
       let mut test_hash = Hash::blank();
       assert!(test_hash.height().is_none());

       // First bit
       test_hash.raw[0] = 1;
       assert_eq!(test_hash.height(), Some(0));

       // Fourth bit (index 3)
       test_hash.raw[0] = test_hash.raw[0] | (1 << 3);
       assert_eq!(test_hash.height(), Some(3));

       // Last bit (index 159)
       test_hash.raw[19] = 1 << 7;
       assert_eq!(test_hash.height(), Some(159));
    }

    #[test]
    fn bit_flipping() {
       let mut test_hash = Hash::blank();
       test_hash.flip_bit(9);
       assert_eq!(test_hash.raw[1], 2);
       test_hash.flip_bit(9);
       assert_eq!(test_hash.raw[1], 0);
    }

    #[test]
    fn iterating_over_ones() {
       let mut test_hash = Hash::blank();
       let bits = vec![5usize,20,40];

       for bit in &bits {
          test_hash.flip_bit(*bit);
       }

       println!("{:?}",test_hash);

       for (actual, expected) in test_hash.ones().zip(bits) {
          assert_eq!(actual, expected);
       }
    }
}
<commit_msg>Hash display<commit_after>use rand::{thread_rng, Rng};
use itertools::Zip;
use std::ops::BitXor;
use std::fmt;
use std::fmt::Write;
use std::cmp::{PartialOrd, Ordering};

/// Hash length in bits. Generally 160 for Kademlia variants.
pub const HASH_SIZE : usize = 160;
pub const HASH_SIZE_BYTES : usize = HASH_SIZE / 8;

/// Light wrapper over a little endian `HASH_SIZE` bit hash
///
/// We aren't interested in strong cryptography, but rather
/// a simple way to generate `HASH_SIZE` bit key identifiers.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Hash {
   pub raw : [u8; HASH_SIZE_BYTES],
}

impl Hash {
   /// Generates a blank hash (every bit set to 0).
   pub fn blank() -> Hash {
      Hash { raw : [0; HASH_SIZE_BYTES] }
   }

   /// Generates a random hash via kernel supplied entropy.
   pub fn random() -> Hash {
      let mut hash = Hash::blank();
      thread_rng().fill_bytes(&mut hash.raw);
      hash
   }

   /// Provides an iterator through the indices
   /// of each of its "0" bits.
   pub fn zeroes(&self) -> Zeroes {
      Zeroes {
         hash  : self,
         index : 0,
         rev   : HASH_SIZE
      }
   }

   /// Provides an iterator through the indices
   /// of each of its "1" bits.
   pub fn ones(&self) -> Ones {
      Ones {
         hash  : self,
         index : 0,
         rev   : HASH_SIZE
      }
   }

   /// Computes the bit index of the highest "1". Returns None for a blank hash.
   pub fn height(&self) -> Option<usize> {
      let last_nonzero_byte = self.raw.iter().enumerate().rev().find(|&pair| *pair.1 != 0);
      if let Some((index, byte)) = last_nonzero_byte {
         for bit in (0..8).rev() {
            if (byte & (1 << bit)) != 0 {
               return Some((8 * index + bit) as usize)
            }
         }
      }
      None
   }

   /// Flips a random bit somewhere in the hash.
   pub fn flip_bit(&mut self, position : usize) {
      if position >= HASH_SIZE { return; }
      let byte = &mut self.raw[position / 8];
      *byte ^= 1 << (position % 8);
   }
}

impl fmt::Display for Hash {
   fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
      let mut leftpad_over = false;
      let mut hex = String::new();
      hex.push_str("0x[");
      for byte in self.raw.iter().rev() {
         if *byte > 0u8 {
            leftpad_over = true;
         }

         if leftpad_over {
            write!(&mut hex, "{:01$X}", byte, 2).unwrap();
         }
      }
      hex.push_str("]");
      write!(f, "{}", hex)
   }
}

/// Iterator through the indices of each '0' in a hash.
pub struct Zeroes<'a> {
   hash  : &'a Hash,
   index : usize,
   rev   : usize
}

/// Iterator through the indices of each '1' in a hash.
pub struct Ones<'a> {
   hash  : &'a Hash,
   index : usize,
   rev   : usize,
}

impl<'a> Iterator for Zeroes<'a> {
   type Item = usize;

   fn next(&mut self) -> Option<usize> {
      while self.index < self.rev {
         let value_at_index = self.hash.raw[self.index / 8] & (1 << (self.index % 8));
         self.index += 1;
         if value_at_index == 0 {
            return Some(self.index - 1);
         }
      }
      None
   }
}

impl<'a> Iterator for Ones<'a> {
   type Item = usize;

   fn next(&mut self) -> Option<usize> {
      while self.index < self.rev {
         let value_at_index = self.hash.raw[self.index / 8] & (1 << (self.index % 8));
         self.index += 1;
         if value_at_index != 0 {
            return Some(self.index - 1);
         }
      }
      None
   }
}

impl<'a> DoubleEndedIterator for Zeroes<'a> {
   fn next_back(&mut self) -> Option<usize> {
      while self.index < self.rev {
         let value_at_rev = self.hash.raw[(self.rev-1) / 8] & (1 << ((self.rev-1) % 8));
         self.rev -= 1;
         if value_at_rev == 0 {
            return Some(self.rev);
         }
      }
      None
   }
}

impl<'a> DoubleEndedIterator for Ones<'a> {
   fn next_back(&mut self) -> Option<usize> {
      while self.index < self.rev {
         let value_at_rev = self.hash.raw[(self.rev-1) / 8] & (1 << ((self.rev-1) % 8));
         self.rev -= 1;
         if value_at_rev != 0 {
            return Some(self.rev);
         }
      }
      None
   }
}

impl PartialOrd for Hash {
   fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
      for (a,b) in self.raw.iter().rev().zip(other.raw.iter().rev()) {
         match a.cmp(b) {
            Ordering::Less => return Some(Ordering::Less),
            Ordering::Greater => return Some(Ordering::Greater),
            Ordering::Equal => ()
         }
      }
      None
   }
}

impl Ord for Hash {
   fn cmp(&self, other: &Self) -> Ordering {
      match self.partial_cmp(other) {
         Some(order) => order,
         None => Ordering::Equal
      }
   }
}

impl<'a, 'b> BitXor<&'b Hash> for &'a Hash {
   type Output = Hash;

   fn bitxor (self, rhs: &'b Hash) -> Hash {
      let mut result = Hash::blank();
      for (d, a, b) in Zip::new((&mut result.raw, &self.raw, &rhs.raw)) {
         *d = a^b;
      }
      result
   }
}

impl BitXor for Hash {
   type Output = Hash;

   fn bitxor (self, rhs: Self) -> Hash {
      let mut raw = self.raw;
      for (a, b) in raw.iter_mut().zip(rhs.raw.iter()) {
         *a ^= *b;
      }
      self
   }
}

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

    #[test]
    fn random_generation() {
       assert!(Hash::random() != Hash::random());
    }

    #[test]
    fn computing_height() {
       let mut test_hash = Hash::blank();
       assert!(test_hash.height().is_none());

       // First bit
       test_hash.raw[0] = 1;
       assert_eq!(test_hash.height(), Some(0));

       // Fourth bit (index 3)
       test_hash.raw[0] = test_hash.raw[0] | (1 << 3);
       assert_eq!(test_hash.height(), Some(3));

       // Last bit (index 159)
       test_hash.raw[19] = 1 << 7;
       assert_eq!(test_hash.height(), Some(159));
    }

    #[test]
    fn bit_flipping() {
       let mut test_hash = Hash::blank();
       test_hash.flip_bit(9);
       assert_eq!(test_hash.raw[1], 2);
       test_hash.flip_bit(9);
       assert_eq!(test_hash.raw[1], 0);
    }

    #[test]
    fn iterating_over_ones() {
       let mut test_hash = Hash::blank();
       let bits = vec![5usize,20,40];

       for bit in &bits {
          test_hash.flip_bit(*bit);
       }

       for (actual, expected) in test_hash.ones().zip(bits) {
          assert_eq!(actual, expected);
       }
    }
}
<|endoftext|>