<commit_before>#[macro_use]
mod macros;

use coerce::{AsBool,AsNumber};

use french_press::ScopeManager;
use js_types::binding::Binding;
use js_types::js_fn::JsFnStruct;
use js_types::js_var::{JsVar, JsType, JsPtrEnum};
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::*;

/// 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) => {
            let (v, _) = eval_stmt(&stmt, state);
            v
        }
        Err(_) => panic!("parse error"),
    }
}

/// 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 = 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, None) {
                Ok(_) => (),
                e @ Err(_) => println!("{:?}", e),
            }

            (js_var, None)
        },

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

        // var var_string = exp
        Decl(ref var_string, ref exp) => {
            let mut js_var = eval_exp(exp, state);
            js_var.binding = Binding::new(var_string.clone());
            // TODO: must handle JsPtrEnum here.
            match state.alloc(js_var.clone(), None) {
                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).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);
            (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).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 {
    match e {
        &BinExp(ref e1, ref op, ref e2) => {
            let val1 = eval_exp(e1, state);
            let val2 = eval_exp(e2, state);

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

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

                Minus => JsVar::new(JsNum(val1.as_number() - val2.as_number())),
                Plus  => JsVar::new(JsNum(val1.as_number() + val2.as_number())),
                Slash => JsVar::new(JsNum(val1.as_number() / val2.as_number())),
                Star  => JsVar::new(JsNum(val1.as_number() * val2.as_number())),
            }
        }
        &Bool(b) => JsVar::new(JsBool(b)),
        &Call(ref fun_name, ref arg_exps) => {
            let fun_binding = eval_exp(fun_name, state);

            // 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.iter() {
                        let mut arg = if args.is_empty() {
                            JsVar::new(JsUndef)
                        } else {
                            args.remove(0)
                        };

                        arg.binding = Binding::new(param.to_owned());
                        state.alloc(arg, None).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");
                    v.unwrap_or(JsVar::new(JsUndef))
                }
                Ok(_) => panic!("Invalid call object"),
                _ => panic!("ReferenceError: {} is not defined")
            }
        },
        &Defun(ref opt_binding, ref params, ref body) => {
            if let &Some(ref binding) = opt_binding {
                let js_fun = JsFnStruct::new(opt_binding, params, &**body);
                let mut var = JsVar::new(JsPtr);
                var.binding = Binding::new(binding.clone());
                if let Err(_) = state.alloc(var, Some(JsPtrEnum::JsFn(js_fun))) {
                    panic!("error storing function into state");
                }
                JsVar::new(JsPtr) // Doesn't store any information anyway
            } else {
                panic!("functions without bindings are not yet supported.")
            }
        },
        &Float(f) => JsVar::new(JsType::JsNum(f)),
        &Neg(ref exp) => JsVar::new(JsNum(-eval_exp(exp, state).as_number())),
        &Pos(ref exp) => JsVar::new(JsNum(eval_exp(exp, state).as_number())),

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

        &NewObject(_, _) => unimplemented!(),
        &Object(_) => unimplemented!(),
        &Undefined => JsVar::new(JsUndef),
        &Var(ref var_binding) => {
            match state.load(&Binding::new(var_binding.clone())) {
                Ok((var, _)) => var,
                _ => panic!(format!("ReferenceError: {} is not defined", var_binding))
            }
        }
    }
}

#[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>More comments, simplify match.<commit_after>#[macro_use]
mod macros;

use coerce::{AsBool,AsNumber};

use french_press::ScopeManager;
use js_types::binding::Binding;
use js_types::js_fn::JsFnStruct;
use js_types::js_var::{JsVar, JsType, JsPtrEnum};
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::*;

/// 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(_) => panic!("parse error"),
    }
}

/// 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 = 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, None) {
                Ok(_) => (),
                e @ Err(_) => println!("{:?}", e),
            }

            (js_var, None)
        },

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

        // var var_string = exp
        Decl(ref var_string, ref exp) => {
            let mut js_var = eval_exp(exp, state);
            js_var.binding = Binding::new(var_string.clone());
            // TODO: must handle JsPtrEnum here.
            match state.alloc(js_var.clone(), None) {
                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).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);
            (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).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 {
    match e {
        // e1 [op] e2
        &BinExp(ref e1, ref op, ref e2) => {
            let val1 = eval_exp(e1, state);
            let val2 = eval_exp(e2, state);

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

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

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

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

            // 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.iter() {
                        let mut arg = if args.is_empty() {
                            JsVar::new(JsUndef)
                        } else {
                            args.remove(0)
                        };

                        arg.binding = Binding::new(param.to_owned());
                        state.alloc(arg, None).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");
                    v.unwrap_or(JsVar::new(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);
                let mut var = JsVar::new(JsPtr);
                var.binding = Binding::new(binding.clone());
                if let Err(_) = state.alloc(var, Some(JsPtrEnum::JsFn(js_fun))) {
                    panic!("error storing function into state");
                }
                JsVar::new(JsPtr) // Doesn't store any information anyway
            } else {
                panic!("functions without bindings are not yet supported.")
            }
        },
        &Float(f) => JsVar::new(JsType::JsNum(f)),
        &Neg(ref exp) => JsVar::new(JsNum(-eval_exp(exp, state).as_number())),
        &Pos(ref exp) => JsVar::new(JsNum(eval_exp(exp, state).as_number())),

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

        &NewObject(_, _) => unimplemented!(),
        &Object(_) => unimplemented!(),

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

#[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>mod emit;
mod line_info;

use crate::prelude::*;

use cranelift_codegen::ir::{StackSlots, ValueLabel, ValueLoc};
use cranelift_codegen::isa::TargetIsa;
use cranelift_codegen::ValueLocRange;

use gimli::write::{
    self, Address, AttributeValue, DwarfUnit, Expression, LineProgram, LineString, Location,
    LocationList, Range, RangeList, UnitEntryId, Writer,
};
use gimli::{Encoding, Format, LineEncoding, RunTimeEndian, X86_64};

pub(crate) use emit::{DebugReloc, DebugRelocName};

fn target_endian(tcx: TyCtxt<'_>) -> RunTimeEndian {
    use rustc_target::abi::Endian;

    match tcx.data_layout.endian {
        Endian::Big => RunTimeEndian::Big,
        Endian::Little => RunTimeEndian::Little,
    }
}

pub(crate) struct DebugContext<'tcx> {
    tcx: TyCtxt<'tcx>,

    endian: RunTimeEndian,
    symbols: indexmap::IndexMap<FuncId, String>,

    dwarf: DwarfUnit,
    unit_range_list: RangeList,

    types: FxHashMap<Ty<'tcx>, UnitEntryId>,
}

impl<'tcx> DebugContext<'tcx> {
    pub(crate) fn new(tcx: TyCtxt<'tcx>, address_size: u8) -> Self {
        let encoding = Encoding {
            format: Format::Dwarf32,
            // TODO: this should be configurable
            // macOS doesn't seem to support DWARF > 3
            version: 3,
            address_size,
        };

        let mut dwarf = DwarfUnit::new(encoding);

        // FIXME: how to get version when building out of tree?
        // Normally this would use option_env!("CFG_VERSION").
        let producer = format!("cg_clif (rustc {})", "unknown version");
        let comp_dir = tcx.sess.working_dir.0.to_string_lossy().into_owned();
        let name = match tcx.sess.local_crate_source_file {
            Some(ref path) => path.to_string_lossy().into_owned(),
            None => tcx.crate_name(LOCAL_CRATE).to_string(),
        };

        let line_program = LineProgram::new(
            encoding,
            LineEncoding::default(),
            LineString::new(comp_dir.as_bytes(), encoding, &mut dwarf.line_strings),
            LineString::new(name.as_bytes(), encoding, &mut dwarf.line_strings),
            None,
        );
        dwarf.unit.line_program = line_program;

        {
            let name = dwarf.strings.add(name);
            let comp_dir = dwarf.strings.add(comp_dir);

            let root = dwarf.unit.root();
            let root = dwarf.unit.get_mut(root);
            root.set(
                gimli::DW_AT_producer,
                AttributeValue::StringRef(dwarf.strings.add(producer)),
            );
            root.set(
                gimli::DW_AT_language,
                AttributeValue::Language(gimli::DW_LANG_Rust),
            );
            root.set(gimli::DW_AT_name, AttributeValue::StringRef(name));
            root.set(gimli::DW_AT_comp_dir, AttributeValue::StringRef(comp_dir));
            root.set(
                gimli::DW_AT_low_pc,
                AttributeValue::Address(Address::Constant(0)),
            );
        }

        DebugContext {
            tcx,

            endian: target_endian(tcx),
            symbols: indexmap::IndexMap::new(),

            dwarf,
            unit_range_list: RangeList(Vec::new()),

            types: FxHashMap::default(),
        }
    }

    fn dwarf_ty(&mut self, ty: Ty<'tcx>) -> UnitEntryId {
        if let Some(type_id) = self.types.get(ty) {
            return *type_id;
        }

        let new_entry = |dwarf: &mut DwarfUnit, tag| dwarf.unit.add(dwarf.unit.root(), tag);

        let primitive = |dwarf: &mut DwarfUnit, ate| {
            let type_id = new_entry(dwarf, gimli::DW_TAG_base_type);
            let type_entry = dwarf.unit.get_mut(type_id);
            type_entry.set(gimli::DW_AT_encoding, AttributeValue::Encoding(ate));
            type_id
        };

        let name = format!("{}", ty);
        let layout = self.tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap();

        let type_id = match ty.kind {
            ty::Bool => primitive(&mut self.dwarf, gimli::DW_ATE_boolean),
            ty::Char => primitive(&mut self.dwarf, gimli::DW_ATE_UTF),
            ty::Uint(_) => primitive(&mut self.dwarf, gimli::DW_ATE_unsigned),
            ty::Int(_) => primitive(&mut self.dwarf, gimli::DW_ATE_signed),
            ty::Float(_) => primitive(&mut self.dwarf, gimli::DW_ATE_float),
            ty::Ref(_, pointee_ty, _mutbl)
            | ty::RawPtr(ty::TypeAndMut {
                ty: pointee_ty,
                mutbl: _mutbl,
            }) => {
                let type_id = new_entry(&mut self.dwarf, gimli::DW_TAG_pointer_type);

                // Ensure that type is inserted before recursing to avoid duplicates
                self.types.insert(ty, type_id);

                let pointee = self.dwarf_ty(pointee_ty);

                let type_entry = self.dwarf.unit.get_mut(type_id);

                //type_entry.set(gimli::DW_AT_mutable, AttributeValue::Flag(mutbl == rustc_hir::Mutability::Mut));
                type_entry.set(gimli::DW_AT_type, AttributeValue::ThisUnitEntryRef(pointee));

                type_id
            }
            ty::Adt(adt_def, _substs) if adt_def.is_struct() && !layout.is_unsized() => {
                let type_id = new_entry(&mut self.dwarf, gimli::DW_TAG_structure_type);

                // Ensure that type is inserted before recursing to avoid duplicates
                self.types.insert(ty, type_id);

                let variant = adt_def.non_enum_variant();

                for (field_idx, field_def) in variant.fields.iter().enumerate() {
                    let field_offset = layout.fields.offset(field_idx);
                    let field_layout = layout.field(&layout::LayoutCx {
                        tcx: self.tcx,
                        param_env: ParamEnv::reveal_all(),
                    }, field_idx).unwrap();

                    let field_type = self.dwarf_ty(field_layout.ty);

                    let field_id = self.dwarf.unit.add(type_id, gimli::DW_TAG_member);
                    let field_entry = self.dwarf.unit.get_mut(field_id);

                    field_entry.set(gimli::DW_AT_name, AttributeValue::String(field_def.ident.as_str().to_string().into_bytes()));
                    field_entry.set(gimli::DW_AT_data_member_location, AttributeValue::Udata(field_offset.bytes()));
                    field_entry.set(gimli::DW_AT_type, AttributeValue::ThisUnitEntryRef(field_type));
                }

                type_id
            }
            _ => new_entry(&mut self.dwarf, gimli::DW_TAG_structure_type),
        };

        let type_entry = self.dwarf.unit.get_mut(type_id);

        type_entry.set(gimli::DW_AT_name, AttributeValue::String(name.into_bytes()));
        type_entry.set(
            gimli::DW_AT_byte_size,
            AttributeValue::Udata(layout.size.bytes()),
        );

        self.types.insert(ty, type_id);

        type_id
    }
}

pub(crate) struct FunctionDebugContext<'a, 'tcx> {
    debug_context: &'a mut DebugContext<'tcx>,
    entry_id: UnitEntryId,
    symbol: usize,
    instance: Instance<'tcx>,
    mir: &'tcx mir::Body<'tcx>,
}

impl<'a, 'tcx> FunctionDebugContext<'a, 'tcx> {
    pub(crate) fn new(
        debug_context: &'a mut DebugContext<'tcx>,
        instance: Instance<'tcx>,
        func_id: FuncId,
        name: &str,
    ) -> Self {
        let mir = *debug_context.tcx.instance_mir(instance.def);

        let (symbol, _) = debug_context.symbols.insert_full(func_id, name.to_string());

        // FIXME: add to appropriate scope intead of root
        let scope = debug_context.dwarf.unit.root();

        let entry_id = debug_context
            .dwarf
            .unit
            .add(scope, gimli::DW_TAG_subprogram);
        let entry = debug_context.dwarf.unit.get_mut(entry_id);
        let name_id = debug_context.dwarf.strings.add(name);
        entry.set(
            gimli::DW_AT_linkage_name,
            AttributeValue::StringRef(name_id),
        );

        FunctionDebugContext {
            debug_context,
            entry_id,
            symbol,
            instance,
            mir,
        }
    }

    fn define_local(&mut self, name: String, ty: Ty<'tcx>) -> UnitEntryId {
        let ty = self.debug_context.tcx.subst_and_normalize_erasing_regions(
            self.instance.substs,
            ty::ParamEnv::reveal_all(),
            &ty,
        );
        let dw_ty = self.debug_context.dwarf_ty(ty);

        let var_id = self
            .debug_context
            .dwarf
            .unit
            .add(self.entry_id, gimli::DW_TAG_variable);
        let var_entry = self.debug_context.dwarf.unit.get_mut(var_id);

        var_entry.set(gimli::DW_AT_name, AttributeValue::String(name.into_bytes()));
        var_entry.set(gimli::DW_AT_type, AttributeValue::ThisUnitEntryRef(dw_ty));

        var_id
    }

    pub(crate) fn define(
        &mut self,
        context: &Context,
        isa: &dyn TargetIsa,
        source_info_set: &indexmap::IndexSet<SourceInfo>,
        local_map: FxHashMap<mir::Local, CPlace<'tcx>>,
    ) {
        let end = self.create_debug_lines(context, isa, source_info_set);

        self.debug_context
            .unit_range_list
            .0
            .push(Range::StartLength {
                begin: Address::Symbol {
                    symbol: self.symbol,
                    addend: 0,
                },
                length: end as u64,
            });

        // FIXME make it more reliable and implement scopes before re-enabling this.
        if false {
            let value_labels_ranges = context.build_value_labels_ranges(isa).unwrap();

            for (local, _local_decl) in self.mir.local_decls.iter_enumerated() {
                let var_id = self.define_local(format!("{:?}", local), &self.mir.local_decls[local].ty);

                let location = place_location(
                    self,
                    isa,
                    context,
                    &local_map,
                    &value_labels_ranges,
                    Place {
                        local,
                        projection: ty::List::empty(),
                    },
                );

                let var_entry = self.debug_context.dwarf.unit.get_mut(var_id);
                var_entry.set(gimli::DW_AT_location, location);
            }
        }

        // FIXME create locals for all entries in mir.var_debug_info
    }
}

fn place_location<'a, 'tcx>(
    func_debug_ctx: &mut FunctionDebugContext<'a, 'tcx>,
    isa: &dyn TargetIsa,
    context: &Context,
    local_map: &FxHashMap<mir::Local, CPlace<'tcx>>,
    #[allow(rustc::default_hash_types)]
    value_labels_ranges: &std::collections::HashMap<ValueLabel, Vec<ValueLocRange>>,
    place: Place<'tcx>,
) -> AttributeValue {
    assert!(place.projection.is_empty()); // FIXME implement them

    match local_map[&place.local].inner() {
        CPlaceInner::Var(local) => {
            let value_label = cranelift_codegen::ir::ValueLabel::from_u32(local.as_u32());
            if let Some(value_loc_ranges) = value_labels_ranges.get(&value_label) {
                let loc_list = LocationList(
                    value_loc_ranges
                        .iter()
                        .map(|value_loc_range| Location::StartEnd {
                            begin: Address::Symbol {
                                symbol: func_debug_ctx.symbol,
                                addend: i64::from(value_loc_range.start),
                            },
                            end: Address::Symbol {
                                symbol: func_debug_ctx.symbol,
                                addend: i64::from(value_loc_range.end),
                            },
                            data: Expression(
                                translate_loc(isa, value_loc_range.loc, &context.func.stack_slots).unwrap(),
                            ),
                        })
                        .collect(),
                );
                let loc_list_id = func_debug_ctx.debug_context.dwarf.unit.locations.add(loc_list);

                AttributeValue::LocationListRef(loc_list_id)
            } else {
                // FIXME set value labels for unused locals

                AttributeValue::Exprloc(Expression(vec![]))
            }
        }
        CPlaceInner::Addr(_, _) => {
            // FIXME implement this (used by arguments and returns)

            AttributeValue::Exprloc(Expression(vec![]))

            // For PointerBase::Stack:
            //AttributeValue::Exprloc(Expression(translate_loc(ValueLoc::Stack(*stack_slot), &context.func.stack_slots).unwrap()))
        }
    }
}

// Adapted from https://github.com/CraneStation/wasmtime/blob/5a1845b4caf7a5dba8eda1fef05213a532ed4259/crates/debug/src/transform/expression.rs#L59-L137
fn translate_loc(isa: &dyn TargetIsa, loc: ValueLoc, stack_slots: &StackSlots) -> Option<Vec<u8>> {
    match loc {
        ValueLoc::Reg(reg) => {
            let machine_reg = isa.map_dwarf_register(reg).unwrap();
            assert!(machine_reg <= 32); // FIXME
            Some(vec![gimli::constants::DW_OP_reg0.0 + machine_reg as u8])
        }
        ValueLoc::Stack(ss) => {
            if let Some(ss_offset) = stack_slots[ss].offset {
                let endian = gimli::RunTimeEndian::Little;
                let mut writer = write::EndianVec::new(endian);
                writer
                    .write_u8(gimli::constants::DW_OP_breg0.0 + X86_64::RBP.0 as u8)
                    .expect("bp wr");
                writer.write_sleb128(ss_offset as i64 + 16).expect("ss wr");
                let buf = writer.into_vec();
                return Some(buf);
            }
            None
        }
        _ => None,
    }
}
<commit_msg>Disable line debuginfo for the AArch64 backend<commit_after>mod emit;
mod line_info;

use crate::prelude::*;

use cranelift_codegen::ir::{StackSlots, ValueLabel, ValueLoc};
use cranelift_codegen::isa::TargetIsa;
use cranelift_codegen::ValueLocRange;

use gimli::write::{
    self, Address, AttributeValue, DwarfUnit, Expression, LineProgram, LineString, Location,
    LocationList, Range, RangeList, UnitEntryId, Writer,
};
use gimli::{Encoding, Format, LineEncoding, RunTimeEndian, X86_64};

pub(crate) use emit::{DebugReloc, DebugRelocName};

fn target_endian(tcx: TyCtxt<'_>) -> RunTimeEndian {
    use rustc_target::abi::Endian;

    match tcx.data_layout.endian {
        Endian::Big => RunTimeEndian::Big,
        Endian::Little => RunTimeEndian::Little,
    }
}

pub(crate) struct DebugContext<'tcx> {
    tcx: TyCtxt<'tcx>,

    endian: RunTimeEndian,
    symbols: indexmap::IndexMap<FuncId, String>,

    dwarf: DwarfUnit,
    unit_range_list: RangeList,

    types: FxHashMap<Ty<'tcx>, UnitEntryId>,
}

impl<'tcx> DebugContext<'tcx> {
    pub(crate) fn new(tcx: TyCtxt<'tcx>, address_size: u8) -> Self {
        let encoding = Encoding {
            format: Format::Dwarf32,
            // TODO: this should be configurable
            // macOS doesn't seem to support DWARF > 3
            version: 3,
            address_size,
        };

        let mut dwarf = DwarfUnit::new(encoding);

        // FIXME: how to get version when building out of tree?
        // Normally this would use option_env!("CFG_VERSION").
        let producer = format!("cg_clif (rustc {})", "unknown version");
        let comp_dir = tcx.sess.working_dir.0.to_string_lossy().into_owned();
        let name = match tcx.sess.local_crate_source_file {
            Some(ref path) => path.to_string_lossy().into_owned(),
            None => tcx.crate_name(LOCAL_CRATE).to_string(),
        };

        let line_program = LineProgram::new(
            encoding,
            LineEncoding::default(),
            LineString::new(comp_dir.as_bytes(), encoding, &mut dwarf.line_strings),
            LineString::new(name.as_bytes(), encoding, &mut dwarf.line_strings),
            None,
        );
        dwarf.unit.line_program = line_program;

        {
            let name = dwarf.strings.add(name);
            let comp_dir = dwarf.strings.add(comp_dir);

            let root = dwarf.unit.root();
            let root = dwarf.unit.get_mut(root);
            root.set(
                gimli::DW_AT_producer,
                AttributeValue::StringRef(dwarf.strings.add(producer)),
            );
            root.set(
                gimli::DW_AT_language,
                AttributeValue::Language(gimli::DW_LANG_Rust),
            );
            root.set(gimli::DW_AT_name, AttributeValue::StringRef(name));
            root.set(gimli::DW_AT_comp_dir, AttributeValue::StringRef(comp_dir));
            root.set(
                gimli::DW_AT_low_pc,
                AttributeValue::Address(Address::Constant(0)),
            );
        }

        DebugContext {
            tcx,

            endian: target_endian(tcx),
            symbols: indexmap::IndexMap::new(),

            dwarf,
            unit_range_list: RangeList(Vec::new()),

            types: FxHashMap::default(),
        }
    }

    fn dwarf_ty(&mut self, ty: Ty<'tcx>) -> UnitEntryId {
        if let Some(type_id) = self.types.get(ty) {
            return *type_id;
        }

        let new_entry = |dwarf: &mut DwarfUnit, tag| dwarf.unit.add(dwarf.unit.root(), tag);

        let primitive = |dwarf: &mut DwarfUnit, ate| {
            let type_id = new_entry(dwarf, gimli::DW_TAG_base_type);
            let type_entry = dwarf.unit.get_mut(type_id);
            type_entry.set(gimli::DW_AT_encoding, AttributeValue::Encoding(ate));
            type_id
        };

        let name = format!("{}", ty);
        let layout = self.tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap();

        let type_id = match ty.kind {
            ty::Bool => primitive(&mut self.dwarf, gimli::DW_ATE_boolean),
            ty::Char => primitive(&mut self.dwarf, gimli::DW_ATE_UTF),
            ty::Uint(_) => primitive(&mut self.dwarf, gimli::DW_ATE_unsigned),
            ty::Int(_) => primitive(&mut self.dwarf, gimli::DW_ATE_signed),
            ty::Float(_) => primitive(&mut self.dwarf, gimli::DW_ATE_float),
            ty::Ref(_, pointee_ty, _mutbl)
            | ty::RawPtr(ty::TypeAndMut {
                ty: pointee_ty,
                mutbl: _mutbl,
            }) => {
                let type_id = new_entry(&mut self.dwarf, gimli::DW_TAG_pointer_type);

                // Ensure that type is inserted before recursing to avoid duplicates
                self.types.insert(ty, type_id);

                let pointee = self.dwarf_ty(pointee_ty);

                let type_entry = self.dwarf.unit.get_mut(type_id);

                //type_entry.set(gimli::DW_AT_mutable, AttributeValue::Flag(mutbl == rustc_hir::Mutability::Mut));
                type_entry.set(gimli::DW_AT_type, AttributeValue::ThisUnitEntryRef(pointee));

                type_id
            }
            ty::Adt(adt_def, _substs) if adt_def.is_struct() && !layout.is_unsized() => {
                let type_id = new_entry(&mut self.dwarf, gimli::DW_TAG_structure_type);

                // Ensure that type is inserted before recursing to avoid duplicates
                self.types.insert(ty, type_id);

                let variant = adt_def.non_enum_variant();

                for (field_idx, field_def) in variant.fields.iter().enumerate() {
                    let field_offset = layout.fields.offset(field_idx);
                    let field_layout = layout.field(&layout::LayoutCx {
                        tcx: self.tcx,
                        param_env: ParamEnv::reveal_all(),
                    }, field_idx).unwrap();

                    let field_type = self.dwarf_ty(field_layout.ty);

                    let field_id = self.dwarf.unit.add(type_id, gimli::DW_TAG_member);
                    let field_entry = self.dwarf.unit.get_mut(field_id);

                    field_entry.set(gimli::DW_AT_name, AttributeValue::String(field_def.ident.as_str().to_string().into_bytes()));
                    field_entry.set(gimli::DW_AT_data_member_location, AttributeValue::Udata(field_offset.bytes()));
                    field_entry.set(gimli::DW_AT_type, AttributeValue::ThisUnitEntryRef(field_type));
                }

                type_id
            }
            _ => new_entry(&mut self.dwarf, gimli::DW_TAG_structure_type),
        };

        let type_entry = self.dwarf.unit.get_mut(type_id);

        type_entry.set(gimli::DW_AT_name, AttributeValue::String(name.into_bytes()));
        type_entry.set(
            gimli::DW_AT_byte_size,
            AttributeValue::Udata(layout.size.bytes()),
        );

        self.types.insert(ty, type_id);

        type_id
    }
}

pub(crate) struct FunctionDebugContext<'a, 'tcx> {
    debug_context: &'a mut DebugContext<'tcx>,
    entry_id: UnitEntryId,
    symbol: usize,
    instance: Instance<'tcx>,
    mir: &'tcx mir::Body<'tcx>,
}

impl<'a, 'tcx> FunctionDebugContext<'a, 'tcx> {
    pub(crate) fn new(
        debug_context: &'a mut DebugContext<'tcx>,
        instance: Instance<'tcx>,
        func_id: FuncId,
        name: &str,
    ) -> Self {
        let mir = *debug_context.tcx.instance_mir(instance.def);

        let (symbol, _) = debug_context.symbols.insert_full(func_id, name.to_string());

        // FIXME: add to appropriate scope intead of root
        let scope = debug_context.dwarf.unit.root();

        let entry_id = debug_context
            .dwarf
            .unit
            .add(scope, gimli::DW_TAG_subprogram);
        let entry = debug_context.dwarf.unit.get_mut(entry_id);
        let name_id = debug_context.dwarf.strings.add(name);
        entry.set(
            gimli::DW_AT_linkage_name,
            AttributeValue::StringRef(name_id),
        );

        FunctionDebugContext {
            debug_context,
            entry_id,
            symbol,
            instance,
            mir,
        }
    }

    fn define_local(&mut self, name: String, ty: Ty<'tcx>) -> UnitEntryId {
        let ty = self.debug_context.tcx.subst_and_normalize_erasing_regions(
            self.instance.substs,
            ty::ParamEnv::reveal_all(),
            &ty,
        );
        let dw_ty = self.debug_context.dwarf_ty(ty);

        let var_id = self
            .debug_context
            .dwarf
            .unit
            .add(self.entry_id, gimli::DW_TAG_variable);
        let var_entry = self.debug_context.dwarf.unit.get_mut(var_id);

        var_entry.set(gimli::DW_AT_name, AttributeValue::String(name.into_bytes()));
        var_entry.set(gimli::DW_AT_type, AttributeValue::ThisUnitEntryRef(dw_ty));

        var_id
    }

    pub(crate) fn define(
        &mut self,
        context: &Context,
        isa: &dyn TargetIsa,
        source_info_set: &indexmap::IndexSet<SourceInfo>,
        local_map: FxHashMap<mir::Local, CPlace<'tcx>>,
    ) {
        if isa.get_mach_backend().is_some() {
            return; // The AArch64 backend doesn't support line debuginfo yet.
        }

        let end = self.create_debug_lines(context, isa, source_info_set);

        self.debug_context
            .unit_range_list
            .0
            .push(Range::StartLength {
                begin: Address::Symbol {
                    symbol: self.symbol,
                    addend: 0,
                },
                length: end as u64,
            });

        // FIXME make it more reliable and implement scopes before re-enabling this.
        if false {
            let value_labels_ranges = context.build_value_labels_ranges(isa).unwrap();

            for (local, _local_decl) in self.mir.local_decls.iter_enumerated() {
                let var_id = self.define_local(format!("{:?}", local), &self.mir.local_decls[local].ty);

                let location = place_location(
                    self,
                    isa,
                    context,
                    &local_map,
                    &value_labels_ranges,
                    Place {
                        local,
                        projection: ty::List::empty(),
                    },
                );

                let var_entry = self.debug_context.dwarf.unit.get_mut(var_id);
                var_entry.set(gimli::DW_AT_location, location);
            }
        }

        // FIXME create locals for all entries in mir.var_debug_info
    }
}

fn place_location<'a, 'tcx>(
    func_debug_ctx: &mut FunctionDebugContext<'a, 'tcx>,
    isa: &dyn TargetIsa,
    context: &Context,
    local_map: &FxHashMap<mir::Local, CPlace<'tcx>>,
    #[allow(rustc::default_hash_types)]
    value_labels_ranges: &std::collections::HashMap<ValueLabel, Vec<ValueLocRange>>,
    place: Place<'tcx>,
) -> AttributeValue {
    assert!(place.projection.is_empty()); // FIXME implement them

    match local_map[&place.local].inner() {
        CPlaceInner::Var(local) => {
            let value_label = cranelift_codegen::ir::ValueLabel::from_u32(local.as_u32());
            if let Some(value_loc_ranges) = value_labels_ranges.get(&value_label) {
                let loc_list = LocationList(
                    value_loc_ranges
                        .iter()
                        .map(|value_loc_range| Location::StartEnd {
                            begin: Address::Symbol {
                                symbol: func_debug_ctx.symbol,
                                addend: i64::from(value_loc_range.start),
                            },
                            end: Address::Symbol {
                                symbol: func_debug_ctx.symbol,
                                addend: i64::from(value_loc_range.end),
                            },
                            data: Expression(
                                translate_loc(isa, value_loc_range.loc, &context.func.stack_slots).unwrap(),
                            ),
                        })
                        .collect(),
                );
                let loc_list_id = func_debug_ctx.debug_context.dwarf.unit.locations.add(loc_list);

                AttributeValue::LocationListRef(loc_list_id)
            } else {
                // FIXME set value labels for unused locals

                AttributeValue::Exprloc(Expression(vec![]))
            }
        }
        CPlaceInner::Addr(_, _) => {
            // FIXME implement this (used by arguments and returns)

            AttributeValue::Exprloc(Expression(vec![]))

            // For PointerBase::Stack:
            //AttributeValue::Exprloc(Expression(translate_loc(ValueLoc::Stack(*stack_slot), &context.func.stack_slots).unwrap()))
        }
    }
}

// Adapted from https://github.com/CraneStation/wasmtime/blob/5a1845b4caf7a5dba8eda1fef05213a532ed4259/crates/debug/src/transform/expression.rs#L59-L137
fn translate_loc(isa: &dyn TargetIsa, loc: ValueLoc, stack_slots: &StackSlots) -> Option<Vec<u8>> {
    match loc {
        ValueLoc::Reg(reg) => {
            let machine_reg = isa.map_dwarf_register(reg).unwrap();
            assert!(machine_reg <= 32); // FIXME
            Some(vec![gimli::constants::DW_OP_reg0.0 + machine_reg as u8])
        }
        ValueLoc::Stack(ss) => {
            if let Some(ss_offset) = stack_slots[ss].offset {
                let endian = gimli::RunTimeEndian::Little;
                let mut writer = write::EndianVec::new(endian);
                writer
                    .write_u8(gimli::constants::DW_OP_breg0.0 + X86_64::RBP.0 as u8)
                    .expect("bp wr");
                writer.write_sleb128(ss_offset as i64 + 16).expect("ss wr");
                let buf = writer.into_vec();
                return Some(buf);
            }
            None
        }
        _ => None,
    }
}
<|endoftext|>


<commit_before>extern crate walkdir;
extern crate chrono;

use std::path;
use self::walkdir::{WalkDir, DirEntry, Error as WalkDirError};
use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;
use self::chrono::{DateTime, UTC};
use std::error::Error;
use std::fmt::{Display, Formatter, Result as fmtResult};
use std::str::FromStr;

pub struct ELBLogEntry {
    timestamp: DateTime<UTC>,
    elb_name: String,
    client_address: String,
    backend_address: String,
    request_processing_time: f32,
    backend_processing_time: String,
    response_processing_time: String,
    elb_status_code: String,
    backend_status_code: String,
    received_bytes: String,
    sent_bytes: String,
    request_method: String,
    request_url: String,
    request_http_version: String
}

pub fn file_list(dir: &path::Path, filenames: &mut Vec<DirEntry>) -> Result<usize, WalkDirError> {
    for entry in WalkDir::new(dir).min_depth(1) {
        match entry {
            Err(err) => return Err(err),
            Ok(entry) => filenames.push(entry),
        }
    }
    Ok(filenames.len())
}

pub fn process_files(runtime_context: &::RuntimeContext, filenames: Vec<walkdir::DirEntry>) -> usize {
    let debug = runtime_context.debug;
    let mut record_count = 0;
    for filename in filenames {
        debug!(debug, "Processing file {}.", filename.path().display());
        match File::open(filename.path()) {
            Ok(file) => {
                let buffered_file = BufReader::new(&file);
                let recs: Vec<_> = buffered_file.lines()
                    .map(|x| {
                        parse_line(&(x.unwrap()))
                    })
                    .collect();
                record_count += recs.len();
                debug!(debug, "Found {} records in file {}.", recs.len(), filename.path().display());
            },
            Err(e) => {
                println!("ERROR: {}", e);
            }
        }
    }

    record_count
}

#[derive(Debug)]
pub struct ParsingError{
    property: &'static str,
    inner_description: String,
}

impl Display for ParsingError {
    fn fmt(&self, f: &mut Formatter) -> fmtResult {
        write!(
            f,
            "Failed to parse {}. The failure messae is {}",
            self.property,
            self.inner_description
        )
    }
}

impl Error for ParsingError {
    fn description(&self) -> &str {
        &self.inner_description
    }

    fn cause(&self) -> Option<&Error> {
        None
    }
}

#[derive(Debug)]
pub struct ParsingErrors {
    record: String,
    errors: Vec<ParsingError>,
}

const TIMESTAMP: &'static str = "timestamp";
const REQUEST_PROCESSING_TIME: &'static str = "request processing time";

pub fn parse_line(line: &String) -> Result<Box<ELBLogEntry>, Box<ParsingErrors>> {
    let split_line: Vec<_> = line.split(" ").collect();
    let mut errors: Vec<ParsingError> = Vec::new();

    let ts = parse_property::<DateTime<UTC>>(split_line[0], TIMESTAMP, &mut errors);
    let req_proc_time = parse_property::<f32>(split_line[4], REQUEST_PROCESSING_TIME, &mut errors);

    if errors.is_empty() {
        Ok(Box::new(
            ELBLogEntry {
                timestamp: ts.unwrap(),
                elb_name: split_line[1].to_string(),
                client_address: split_line[2].to_string(),
                backend_address: split_line[3].to_string(),
                request_processing_time: req_proc_time.unwrap(),
                backend_processing_time: split_line[5].to_string(),
                response_processing_time: split_line[6].to_string(),
                elb_status_code: split_line[7].to_string(),
                backend_status_code: split_line[8].to_string(),
                received_bytes: split_line[9].to_string(),
                sent_bytes: split_line[10].to_string(),
                request_method: split_line[11].trim_matches('"').to_string(),
                request_url: split_line[12].to_string(),
                request_http_version: split_line[13].trim_matches('"').to_string()
            }
        ))
    } else {
        Err(Box::new(
            ParsingErrors {
                record: line.clone(),
                errors: errors
            }
        ))
    }
}

fn parse_property<T: FromStr>(raw_prop: &str, prop_name: &'static str, errors: &mut Vec<ParsingError>) -> Option<T> {
    match raw_prop.parse::<T>() {
        Ok(parsed) => Some(parsed),

        Err(e) => {
            errors.push(
                ParsingError {
                    property: prop_name,
                    //TODO Figure out a way to pass ownership of the original error to the ParsingError to make it available to callers.
                    inner_description: "(e as Error).to_string()".to_string(),
                }
            );
            None
        }
    }
}

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

    const TEST_LINE: &'static str = "2015-08-15T23:43:05.302180Z elb-name 172.16.1.6:54814 \
    172.16.1.5:9000 0.000039 0.145507 0.00003 200 200 0 7582 \
    \"GET http://some.domain.com:80/path0/path1?param0=p0&param1=p1 HTTP/1.1\" \
    ";

    #[test]
	fn parse_line_returns_a_log_entry_with_the_request_http_version() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.request_http_version, "HTTP/1.1")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_request_url() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.request_url, "http://some.domain.com:80/path0/path1?param0=p0&param1=p1")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_request_method() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.request_method, "GET")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_sent_bytes() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.sent_bytes, "7582")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_received_bytes() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.received_bytes, "0")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_backend_status_code() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.backend_status_code, "200")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_elb_status_code() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.elb_status_code, "200")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_response_processing_time() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.response_processing_time, "0.00003")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_backend_processing_time() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.backend_processing_time, "0.145507")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_request_processing_time() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.request_processing_time, 0.000039)
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_backend_address() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.backend_address, "172.16.1.5:9000")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_client_address() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.client_address, "172.16.1.6:54814")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_timestamp() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(format!("{:?}", elb_log_entry.timestamp), "2015-08-15T23:43:05.302180Z")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_elb_name() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.elb_name, "elb-name")
	}
}
<commit_msg>Figured out how to transfer ownership of the errors that occur during parsing to the ParsingError.<commit_after>extern crate walkdir;
extern crate chrono;

use std::path;
use self::walkdir::{WalkDir, DirEntry, Error as WalkDirError};
use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;
use self::chrono::{DateTime, UTC};
use std::error::Error;
use std::str::FromStr;

pub struct ELBLogEntry {
    timestamp: DateTime<UTC>,
    elb_name: String,
    client_address: String,
    backend_address: String,
    request_processing_time: f32,
    backend_processing_time: String,
    response_processing_time: String,
    elb_status_code: String,
    backend_status_code: String,
    received_bytes: String,
    sent_bytes: String,
    request_method: String,
    request_url: String,
    request_http_version: String
}

pub fn file_list(dir: &path::Path, filenames: &mut Vec<DirEntry>) -> Result<usize, WalkDirError> {
    for entry in WalkDir::new(dir).min_depth(1) {
        match entry {
            Err(err) => return Err(err),
            Ok(entry) => filenames.push(entry),
        }
    }
    Ok(filenames.len())
}

pub fn process_files(runtime_context: &::RuntimeContext, filenames: Vec<walkdir::DirEntry>) -> usize {
    let debug = runtime_context.debug;
    let mut record_count = 0;
    for filename in filenames {
        debug!(debug, "Processing file {}.", filename.path().display());
        match File::open(filename.path()) {
            Ok(file) => {
                let buffered_file = BufReader::new(&file);
                let recs: Vec<_> = buffered_file.lines()
                    .map(|x| {
                        parse_line(&(x.unwrap()))
                    })
                    .collect();
                record_count += recs.len();
                debug!(debug, "Found {} records in file {}.", recs.len(), filename.path().display());
            },
            Err(e) => {
                println!("ERROR: {}", e);
            }
        }
    }

    record_count
}

#[derive(Debug)]
pub struct ParsingError{
    property: &'static str,
    inner_description: Box<Error>,
}

#[derive(Debug)]
pub struct ParsingErrors {
    record: String,
    errors: Vec<ParsingError>,
}

const TIMESTAMP: &'static str = "timestamp";
const REQUEST_PROCESSING_TIME: &'static str = "request processing time";

pub fn parse_line(line: &String) -> Result<Box<ELBLogEntry>, Box<ParsingErrors>> {
    let split_line: Vec<_> = line.split(" ").collect();
    let mut errors: Vec<ParsingError> = Vec::new();

    let ts = parse_property::<DateTime<UTC>>(split_line[0], TIMESTAMP, &mut errors);
    let req_proc_time = parse_property::<f32>(split_line[4], REQUEST_PROCESSING_TIME, &mut errors);

    if errors.is_empty() {
        Ok(Box::new(
            ELBLogEntry {
                timestamp: ts.unwrap(),
                elb_name: split_line[1].to_string(),
                client_address: split_line[2].to_string(),
                backend_address: split_line[3].to_string(),
                request_processing_time: req_proc_time.unwrap(),
                backend_processing_time: split_line[5].to_string(),
                response_processing_time: split_line[6].to_string(),
                elb_status_code: split_line[7].to_string(),
                backend_status_code: split_line[8].to_string(),
                received_bytes: split_line[9].to_string(),
                sent_bytes: split_line[10].to_string(),
                request_method: split_line[11].trim_matches('"').to_string(),
                request_url: split_line[12].to_string(),
                request_http_version: split_line[13].trim_matches('"').to_string()
            }
        ))
    } else {
        Err(Box::new(
            ParsingErrors {
                record: line.clone(),
                errors: errors
            }
        ))
    }
}

fn parse_property<T>(raw_prop: &str, prop_name: &'static str, errors: &mut Vec<ParsingError>) -> Option<T>
    where T: FromStr,
    T::Err: 'static + Error,
{
    match raw_prop.parse::<T>() {
        Ok(parsed) => Some(parsed),

        Err(e) => {
            errors.push(
                ParsingError {
                    property: prop_name,
                    inner_description: Box::new(e),
                }
            );
            None
        }
    }
}

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

    const TEST_LINE: &'static str = "2015-08-15T23:43:05.302180Z elb-name 172.16.1.6:54814 \
    172.16.1.5:9000 0.000039 0.145507 0.00003 200 200 0 7582 \
    \"GET http://some.domain.com:80/path0/path1?param0=p0&param1=p1 HTTP/1.1\" \
    ";

    #[test]
	fn parse_line_returns_a_log_entry_with_the_request_http_version() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.request_http_version, "HTTP/1.1")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_request_url() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.request_url, "http://some.domain.com:80/path0/path1?param0=p0&param1=p1")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_request_method() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.request_method, "GET")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_sent_bytes() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.sent_bytes, "7582")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_received_bytes() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.received_bytes, "0")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_backend_status_code() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.backend_status_code, "200")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_elb_status_code() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.elb_status_code, "200")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_response_processing_time() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.response_processing_time, "0.00003")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_backend_processing_time() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.backend_processing_time, "0.145507")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_request_processing_time() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.request_processing_time, 0.000039)
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_backend_address() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.backend_address, "172.16.1.5:9000")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_client_address() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.client_address, "172.16.1.6:54814")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_timestamp() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(format!("{:?}", elb_log_entry.timestamp), "2015-08-15T23:43:05.302180Z")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_elb_name() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.elb_name, "elb-name")
	}
}
<|endoftext|>


<commit_before>use cocoa::base::id;
use std::error::Error;
use std::fmt;
use std::ops::Deref;
use std::ptr;
use winit;
use Device;

pub use winit::{
    CursorState,
    Event,
    MonitorId,
    MouseCursor,
    PollEventsIterator,
    WaitEventsIterator,
    ElementState,
    MouseButton,
    MouseScrollDelta,
    Touch,
    TouchPhase,
    ScanCode,
    VirtualKeyCode
};

pub struct WindowBuilder {
    window: winit::WindowBuilder
}

#[derive(Debug)]
pub enum CreationError {
    NoDevice,
    Winit(winit::CreationError)
}

impl fmt::Display for CreationError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.description())
    }
}

impl Error for CreationError {
    fn description(&self) -> &str {
        match *self {
            CreationError::NoDevice => "A device was not set for the windowbuilder",
            CreationError::Winit(ref e) => e.description()
        }
    }

    fn cause(&self) -> Option<&Error> {
        if let CreationError::Winit(ref e) = *self {
            Some(e)
        } else {
            None
        }
    }
}

impl From<winit::CreationError> for CreationError {
    fn from(error: winit::CreationError) -> Self {
        CreationError::Winit(error)
    }
}

impl WindowBuilder {
    /// Initializes a new `WindowBuilder` with default values.
    #[inline]
    pub fn new() -> Self {
        WindowBuilder {
            window: winit::WindowBuilder::new()
        }
    }

    /// Requests the window to be of specific dimensions.
    ///
    /// Width and height are in pixels.
    #[inline]
    pub fn with_dimensions(self, width: u32, height: u32) -> WindowBuilder {
        WindowBuilder {window: self.window.with_dimensions(width, height), ..self}
    }

    /// Sets a minimum dimension size for the window
    ///
    /// Width and height are in pixels.
    #[inline]
    pub fn with_min_dimensions(self, width: u32, height: u32) -> WindowBuilder {
        WindowBuilder {window: self.window.with_min_dimensions(width, height), ..self}
    }

    /// Sets a maximum dimension size for the window
    ///
    /// Width and height are in pixels.
    #[inline]
    pub fn with_max_dimensions(self, width: u32, height: u32) -> WindowBuilder {
        WindowBuilder {window: self.window.with_max_dimensions(width, height), ..self}
    }

    /// Requests a specific title for the window.
    #[inline]
    pub fn with_title(self, title: String) -> WindowBuilder {
        WindowBuilder {window: self.window.with_title(title), ..self}
    }

    /// Requests fullscreen mode.
    ///
    /// If you don't specify dimensions for the window, it will match the monitor's.
    #[inline]
    pub fn with_fullscreen(self, monitor: MonitorId) -> WindowBuilder {
        WindowBuilder {window: self.window.with_fullscreen(monitor), ..self}
    }

    /// Sets whether the window will be initially hidden or visible.
    #[inline]
    pub fn with_visibility(self, visible: bool) -> WindowBuilder {
        WindowBuilder {window: self.window.with_visibility(visible), ..self}
    }

    /// Sets whether the background of the window should be transparent.
    #[inline]
    pub fn with_transparency(self, transparent: bool) -> WindowBuilder {
        WindowBuilder {window: self.window.with_transparency(transparent), ..self}
    }

    /// Sets whether the window should have a border, a title bar, etc.
    #[inline]
    pub fn with_decorations(self, decorations: bool) -> WindowBuilder {
        WindowBuilder {window: self.window.with_decorations(decorations), ..self}
    }

    /// Enables multitouch
    #[inline]
    pub fn with_multitouch(self) -> WindowBuilder {
        WindowBuilder {window: self.window.with_multitouch(), ..self}
    }

    /// Builds the window.
    ///
    /// Error should be very rare and only occur in case of permission denied, incompatible system,
    /// out of memory, etc.
    pub fn build(self) -> Result<Window, CreationError> {
        let window = try!(self.window.build());
        let native_window: id = unsafe { window.platform_window() as id };
        Ok(Window {
            window: window,
            view: ptr::null_mut()
        })
    }

    /// Builds the window.
    ///
    /// The context is build in a *strict* way. That means that if the backend couldn't give
    /// you what you requested, an `Err` will be returned.
    #[inline]
    pub fn build_strict(self) -> Result<Window, CreationError> {
        self.build()
    }
}

pub struct Window {
    window: winit::Window,
    view: id
}

pub struct WinRef<'a>(&'a winit::Window);

impl<'a> Deref for WinRef<'a> {
    type Target = winit::Window;
    fn deref(&self) -> &Self::Target {
        self.0
    }
}

impl Window {
    pub fn poll_events(&self) -> PollEventsIterator {
        self.window.poll_events()
    }

    pub fn wait_events(&self) -> WaitEventsIterator {
        self.window.wait_events()
    }

    pub fn window(&self) -> WinRef {
        WinRef(&self.window)
    }
}

pub trait WindowBuilderExt {
    fn build_metal(self, device: Device) -> Result<MetalFacade, CreationError>;
}

impl WindowBuilderExt for WindowBuilder {
    fn build_metal(self, device: Device) -> Result<MetalFacade, CreationError> {
        let window = try!(self.build());
        Ok(MetalFacade {
            window: window,
            device: device
        })
    }
}

pub struct MetalFacade {
    pub window: Window,
    pub device: Device
}

impl MetalFacade {
    #[inline]
    pub fn poll_events(&self) -> PollEventsIterator {
        self.window.poll_events()
    }

    #[inline]
    pub fn wait_events(&self) -> WaitEventsIterator {
        self.window.wait_events()
    }
}
<commit_msg>Don't make MetalFacade members public ; use accessors instead<commit_after>use cocoa::base::id;
use std::error::Error;
use std::fmt;
use std::ops::Deref;
use std::ptr;
use winit;
use Device;

pub use winit::{
    CursorState,
    Event,
    MonitorId,
    MouseCursor,
    PollEventsIterator,
    WaitEventsIterator,
    ElementState,
    MouseButton,
    MouseScrollDelta,
    Touch,
    TouchPhase,
    ScanCode,
    VirtualKeyCode
};

pub struct WindowBuilder {
    window: winit::WindowBuilder
}

#[derive(Debug)]
pub enum CreationError {
    NoDevice,
    Winit(winit::CreationError)
}

impl fmt::Display for CreationError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.description())
    }
}

impl Error for CreationError {
    fn description(&self) -> &str {
        match *self {
            CreationError::NoDevice => "A device was not set for the windowbuilder",
            CreationError::Winit(ref e) => e.description()
        }
    }

    fn cause(&self) -> Option<&Error> {
        if let CreationError::Winit(ref e) = *self {
            Some(e)
        } else {
            None
        }
    }
}

impl From<winit::CreationError> for CreationError {
    fn from(error: winit::CreationError) -> Self {
        CreationError::Winit(error)
    }
}

impl WindowBuilder {
    /// Initializes a new `WindowBuilder` with default values.
    #[inline]
    pub fn new() -> Self {
        WindowBuilder {
            window: winit::WindowBuilder::new()
        }
    }

    /// Requests the window to be of specific dimensions.
    ///
    /// Width and height are in pixels.
    #[inline]
    pub fn with_dimensions(self, width: u32, height: u32) -> WindowBuilder {
        WindowBuilder {window: self.window.with_dimensions(width, height), ..self}
    }

    /// Sets a minimum dimension size for the window
    ///
    /// Width and height are in pixels.
    #[inline]
    pub fn with_min_dimensions(self, width: u32, height: u32) -> WindowBuilder {
        WindowBuilder {window: self.window.with_min_dimensions(width, height), ..self}
    }

    /// Sets a maximum dimension size for the window
    ///
    /// Width and height are in pixels.
    #[inline]
    pub fn with_max_dimensions(self, width: u32, height: u32) -> WindowBuilder {
        WindowBuilder {window: self.window.with_max_dimensions(width, height), ..self}
    }

    /// Requests a specific title for the window.
    #[inline]
    pub fn with_title(self, title: String) -> WindowBuilder {
        WindowBuilder {window: self.window.with_title(title), ..self}
    }

    /// Requests fullscreen mode.
    ///
    /// If you don't specify dimensions for the window, it will match the monitor's.
    #[inline]
    pub fn with_fullscreen(self, monitor: MonitorId) -> WindowBuilder {
        WindowBuilder {window: self.window.with_fullscreen(monitor), ..self}
    }

    /// Sets whether the window will be initially hidden or visible.
    #[inline]
    pub fn with_visibility(self, visible: bool) -> WindowBuilder {
        WindowBuilder {window: self.window.with_visibility(visible), ..self}
    }

    /// Sets whether the background of the window should be transparent.
    #[inline]
    pub fn with_transparency(self, transparent: bool) -> WindowBuilder {
        WindowBuilder {window: self.window.with_transparency(transparent), ..self}
    }

    /// Sets whether the window should have a border, a title bar, etc.
    #[inline]
    pub fn with_decorations(self, decorations: bool) -> WindowBuilder {
        WindowBuilder {window: self.window.with_decorations(decorations), ..self}
    }

    /// Enables multitouch
    #[inline]
    pub fn with_multitouch(self) -> WindowBuilder {
        WindowBuilder {window: self.window.with_multitouch(), ..self}
    }

    /// Builds the window.
    ///
    /// Error should be very rare and only occur in case of permission denied, incompatible system,
    /// out of memory, etc.
    pub fn build(self) -> Result<Window, CreationError> {
        let window = try!(self.window.build());
        let native_window: id = unsafe { window.platform_window() as id };
        Ok(Window {
            window: window,
            view: ptr::null_mut()
        })
    }

    /// Builds the window.
    ///
    /// The context is build in a *strict* way. That means that if the backend couldn't give
    /// you what you requested, an `Err` will be returned.
    #[inline]
    pub fn build_strict(self) -> Result<Window, CreationError> {
        self.build()
    }
}

pub struct Window {
    window: winit::Window,
    view: id
}

pub struct WinRef<'a>(&'a winit::Window);

impl<'a> Deref for WinRef<'a> {
    type Target = winit::Window;
    fn deref(&self) -> &Self::Target {
        self.0
    }
}

impl Window {
    pub fn poll_events(&self) -> PollEventsIterator {
        self.window.poll_events()
    }

    pub fn wait_events(&self) -> WaitEventsIterator {
        self.window.wait_events()
    }

    pub fn window(&self) -> WinRef {
        WinRef(&self.window)
    }
}

pub trait WindowBuilderExt {
    fn build_metal(self, device: Device) -> Result<MetalFacade, CreationError>;
}

impl WindowBuilderExt for WindowBuilder {
    fn build_metal(self, device: Device) -> Result<MetalFacade, CreationError> {
        let window = try!(self.build());
        Ok(MetalFacade {
            window: window,
            device: device
        })
    }
}

pub struct MetalFacade {
    window: Window,
    device: Device
}

impl MetalFacade {
    #[inline]
    pub fn window(&self) -> &Window {
        &self.window
    }

    #[inline]
    pub fn window_mut(&mut self) -> &mut Window {
        &mut self.window
    }

    #[inline]
    pub fn device(&self) -> &Device {
        &self.device
    }

    #[inline]
    pub fn device_mut(&mut self) -> &mut Device {
        &mut self.device
    }

    #[inline]
    pub fn poll_events(&self) -> PollEventsIterator {
        self.window.poll_events()
    }

    #[inline]
    pub fn wait_events(&self) -> WaitEventsIterator {
        self.window.wait_events()
    }
}
<|endoftext|>


<commit_before>struct Gradient {
    start: [i32; 3],
    steps: [i32; 3],
    n: i32,
    total: i32,
}

impl Gradient {
    fn new(start: String, stop: String, steps: i32) -> Gradient {
        Gradient{
            start: [0,0,0],
            steps: [17,17,17],
            n: 0,
            total: steps
        }
    }
}

impl Iterator for Gradient {
    type Item = String;

    fn next(&mut self) -> Option<String> {
        match self.n {
            n if n == self.total => None,
            n => {
                let r = self.start[0] as i32 + (self.steps[0] as i32 * n);
                let g = self.start[1] as i32 + (self.steps[1] as i32 * n);
                let b = self.start[2] as i32 + (self.steps[2] as i32 * n);

                self.n += 1;

                Some(format!("{:02x}{:02x}{:02x}", r, g, b))
            }
        }
    }
}

#[test]
fn it_works() {
    let g = Gradient::new("000000".to_string(), "ffffff".to_string(), 16);

    assert_eq!(g.take(2).collect::<Vec<String>>(), vec!["000000".to_string(), "111111".to_string()]);
}

fn main() {
    let g = Gradient::new("000000".to_string(), "ffffff".to_string(), 10000);

    g.collect::<Vec<String>>();
}
<commit_msg>Rewrote next() in declarative style<commit_after>struct Gradient {
    start: Vec<i32>,
    steps: Vec<i32>,
    n: i32,
    total: i32,
}

impl Gradient {
    fn new(start: String, stop: String, steps: i32) -> Gradient {
        Gradient{
            start: vec![0, 0, 0],
            steps: vec![17,17,17],
            n: 0,
            total: steps
        }
    }
}

impl Iterator for Gradient {
    type Item = String;

    fn next(&mut self) -> Option<String> {
        match self.n {
            n if n == self.total => None,
            n => {
                let rgb: String = self.start
                    .iter()
                    .zip(self.steps.iter())
                    .map(|(&a, &b)| a + (b * n))
                    .map(|i| format!("{:02x}", i))
                    .collect();

                self.n += 1;

                Some(rgb)
            }
        }
    }
}

fn main() {
    let g = Gradient::new("000000".to_string(), "ffffff".to_string(), 10000);

    g.collect::<Vec<String>>();
}

#[test]
fn it_works() {
    let g = Gradient::new("000000".to_string(), "ffffff".to_string(), 16);

    assert_eq!(g.take(2).collect::<Vec<String>>(), vec!["000000".to_string(), "111111".to_string()]);
}
<|endoftext|>


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

#![allow(dead_code)]

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>Export stuff out of mod game.<commit_after>//! This module is for everything about the rules of chess.

#![allow(dead_code)]

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, Plies};
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, make_move_mut};
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;
<|endoftext|>


<commit_before>use structs::{CliError, Config, UserConfig, Member, Team, PublicKey};
use std;
use std::fs::File;
use std::io::prelude::*;
use std::collections::HashMap;

use glob::glob;
use reqwest;
use reqwest::header::Authorization;
use serde_json;

pub struct GithubClient {
    client: reqwest::Client,
    conf: Config,
}

impl GithubClient {
    pub fn new(config: &Config) -> Result<GithubClient, CliError> {
        if std::env::var("SSL_CERT_FILE").is_err() {
            std::env::set_var("SSL_CERT_FILE", &config.cert_path);
        }
        let client = reqwest::Client::new()?;
        Ok(GithubClient { client: client, conf: config.clone() })
    }

    fn get_cache_path(url: &str) -> std::path::PathBuf {
        let mut path = std::env::temp_dir();
        path.push("ghteam-auth-cache");
        path.push(url);
        path
    }

    fn load_content_from_cache(&self, url: &str) -> Result<(std::fs::Metadata, String), CliError> {
        let path = Self::get_cache_path(url);
        let metadata = std::fs::metadata(path.to_str().unwrap())?;
        let mut f = File::open(path.to_str().unwrap())?;
        let mut content = String::new();
        f.read_to_string(&mut content)?;
        Ok((metadata, content))
    }

    fn store_content_to_cache(&self, url: &str, content: &str) -> Result<(), CliError> {
        let path = Self::get_cache_path(url);
        std::fs::create_dir_all(path.parent().unwrap())?;
        let mut f = File::create(path.to_str().unwrap())?;
        f.write(content.as_bytes())?;
        Ok(())
    }

    fn get_content_from_url(&self, url: &str) -> Result<String, CliError> {
        let token = String::from("token ") + &self.conf.token;
        let res = self.client.get(url).header(Authorization(token)).send();
        let mut content = String::new();
        res?.read_to_string(&mut content)?;
        self.store_content_to_cache(url, &content)?;
        Ok(content)
    }

    fn get_content(&self, url: &str) -> Result<String, CliError> {
        match self.load_content_from_cache(url) {
            Ok((metadata, cache_content)) => {
                match std::time::SystemTime::now().duration_since(metadata.modified()?) {
                    Ok(caching_duration) => {
                        if caching_duration.as_secs() > self.conf.cache_duration {
                            match self.get_content_from_url(url) {
                                Ok(content_from_url) => Ok(content_from_url),
                                Err(_) => Ok(cache_content),
                            }
                        } else {
                            Ok(cache_content)
                        }
                    }
                    Err(_) => Ok(cache_content),
                }
            }
            Err(_) => self.get_content_from_url(url),
        }
    }

    #[allow(dead_code)]
    pub fn print_user_public_key(&self, user: &str) -> Result<(), CliError> {
        let keys = self.get_user_public_key(user)?;
        println!("{}", keys);
        Ok(())
    }

    fn get_user_public_key(&self, user: &str) -> Result<String, CliError> {
        let url = format!("{}/users/{}/keys", self.conf.endpoint, user);
        let content = self.get_content(&url)?;
        let keys = serde_json::from_str::<Vec<PublicKey>>(&content)?;
        Ok(keys.iter().map(|k| k.key.clone()).collect::<Vec<String>>().join("\n"))
    }

    #[allow(dead_code)]
    pub fn check_pam(&self, user: &str) -> Result<bool, CliError> {
        let (_, members) = self.get_team_members()?;
        Ok(members.contains_key(user))
    }

    pub fn get_team_members(&self) -> Result<(Team, HashMap<String, Member>), CliError> {
        let teams: HashMap<String, Team> = self.get_teams()?;
        if let Some(team) = teams.get(&self.conf.team.clone()) {
            Ok((team.clone(), self.get_members(team.id)?))
        } else {
            Err(CliError::from(std::io::Error::new(std::io::ErrorKind::NotFound, "Team not found")))
        }
    }

    fn get_teams(&self) -> Result<HashMap<String, Team>, CliError> {
        let url = format!("{}/orgs/{}/teams", self.conf.endpoint, self.conf.org);
        let content = self.get_content(&url)?;
        let teams = serde_json::from_str::<Vec<Team>>(&content)?;
        let mut team_map = HashMap::new();
        for team in teams {
            team_map.insert(team.name.clone(), team);
        }
        Ok(team_map)
    }

    fn get_members(&self, mid: u64) -> Result<HashMap<String, Member>, CliError> {
        let url = format!("{}/teams/{}/members", self.conf.endpoint, mid);
        let content = self.get_content(&url)?;
        let members = serde_json::from_str::<Vec<Member>>(&content)?;
        let mut member_map = HashMap::new();
        for member in members {
            member_map.insert(member.login.clone(), member);
        }
        Ok(member_map)
    }

    fn get_user_conf_path(&self, user: &str) -> UserConfig {
        let home = self.conf.home.replace("{}", user);
        UserConfig::new(&(home + &self.conf.user_conf_path))
    }

    #[allow(dead_code)]
    pub fn clear_all_caches(&self) -> Result<(), CliError> {
        let mut path = std::env::temp_dir();
        path.push("ghteam-auth-cache");
        path.push("**");
        path.push("*");
        for entry in glob(&path.to_str().unwrap()).unwrap() {
            match entry {
                Ok(path) => {
                    if path.is_file() {
                        std::fs::remove_file(path)?
                    }
                }
                Err(e) => println!("{:?}", e),
            }
        }
        Ok(())
    }
}
<commit_msg>Fix build<commit_after>use structs::{CliError, Config, UserConfig, Member, Team, PublicKey};
use std;
use std::fs::File;
use std::io::prelude::*;
use std::collections::HashMap;

use glob::glob;
use reqwest;
use reqwest::header::Authorization;
use serde_json;

pub struct GithubClient {
    client: reqwest::Client,
    conf: Config,
}

impl GithubClient {
    pub fn new(config: &Config) -> Result<GithubClient, CliError> {
        if std::env::var("SSL_CERT_FILE").is_err() {
            std::env::set_var("SSL_CERT_FILE", &config.cert_path);
        }
        let client = reqwest::Client::new()?;
        Ok(GithubClient { client: client, conf: config.clone() })
    }

    fn get_cache_path(url: &str) -> std::path::PathBuf {
        let mut path = std::env::temp_dir();
        path.push("ghteam-auth-cache");
        path.push(url);
        path
    }

    fn load_content_from_cache(&self, url: &str) -> Result<(std::fs::Metadata, String), CliError> {
        let path = Self::get_cache_path(url);
        let metadata = std::fs::metadata(path.to_str().unwrap())?;
        let mut f = File::open(path.to_str().unwrap())?;
        let mut content = String::new();
        f.read_to_string(&mut content)?;
        Ok((metadata, content))
    }

    fn store_content_to_cache(&self, url: &str, content: &str) -> Result<(), CliError> {
        let path = Self::get_cache_path(url);
        std::fs::create_dir_all(path.parent().unwrap())?;
        let mut f = File::create(path.to_str().unwrap())?;
        f.write(content.as_bytes())?;
        Ok(())
    }

    fn get_content_from_url(&self, url: &str) -> Result<String, CliError> {
        let token = String::from("token ") + &self.conf.token;
        let res = self.client.get(url).header(Authorization(token)).send();
        let mut content = String::new();
        res?.read_to_string(&mut content)?;
        self.store_content_to_cache(url, &content)?;
        Ok(content)
    }

    fn get_content(&self, url: &str) -> Result<String, CliError> {
        match self.load_content_from_cache(url) {
            Ok((metadata, cache_content)) => {
                match std::time::SystemTime::now().duration_since(metadata.modified()?) {
                    Ok(caching_duration) => {
                        if caching_duration.as_secs() > self.conf.cache_duration {
                            match self.get_content_from_url(url) {
                                Ok(content_from_url) => Ok(content_from_url),
                                Err(_) => Ok(cache_content),
                            }
                        } else {
                            Ok(cache_content)
                        }
                    }
                    Err(_) => Ok(cache_content),
                }
            }
            Err(_) => self.get_content_from_url(url),
        }
    }

    #[allow(dead_code)]
    pub fn print_user_public_key(&self, user: &str) -> Result<(), CliError> {
        let keys = self.get_user_public_key(user)?;
        println!("{}", keys);
        Ok(())
    }

    fn get_user_public_key(&self, user: &str) -> Result<String, CliError> {
        let url = format!("{}/users/{}/keys", self.conf.endpoint, user);
        let content = self.get_content(&url)?;
        let keys = serde_json::from_str::<Vec<PublicKey>>(&content)?;
        Ok(keys.iter().map(|k| k.key.clone()).collect::<Vec<String>>().join("\n"))
    }

    #[allow(dead_code)]
    pub fn check_pam(&self, user: &str) -> Result<bool, CliError> {
        let (_, members) = self.get_team_members()?;
        Ok(members.contains_key(user))
    }

    pub fn get_team_members(&self) -> Result<(Team, HashMap<String, Member>), CliError> {
        let teams: HashMap<String, Team> = self.get_teams()?;
        if let Some(team) = teams.get(&self.conf.team.clone()) {
            Ok((team.clone(), self.get_members(team.id)?))
        } else {
            Err(CliError::from(std::io::Error::new(std::io::ErrorKind::NotFound, "Team not found")))
        }
    }

    fn get_teams(&self) -> Result<HashMap<String, Team>, CliError> {
        let url = format!("{}/orgs/{}/teams", self.conf.endpoint, self.conf.org);
        let content = self.get_content(&url)?;
        let teams = serde_json::from_str::<Vec<Team>>(&content)?;
        let mut team_map = HashMap::new();
        for team in teams {
            team_map.insert(team.name.clone(), team);
        }
        Ok(team_map)
    }

    fn get_members(&self, mid: u64) -> Result<HashMap<String, Member>, CliError> {
        let url = format!("{}/teams/{}/members", self.conf.endpoint, mid);
        let content = self.get_content(&url)?;
        let members = serde_json::from_str::<Vec<Member>>(&content)?;
        let mut member_map = HashMap::new();
        for member in members {
            member_map.insert(member.login.clone(), member);
        }
        Ok(member_map)
    }

    fn get_user_conf_path(&self, user: &str) -> Result<UserConfig, CliError> {
        let home = self.conf.home.replace("{}", user);
        UserConfig::new(&(home + &self.conf.user_conf_path))
    }

    #[allow(dead_code)]
    pub fn clear_all_caches(&self) -> Result<(), CliError> {
        let mut path = std::env::temp_dir();
        path.push("ghteam-auth-cache");
        path.push("**");
        path.push("*");
        for entry in glob(&path.to_str().unwrap()).unwrap() {
            match entry {
                Ok(path) => {
                    if path.is_file() {
                        std::fs::remove_file(path)?
                    }
                }
                Err(e) => println!("{:?}", e),
            }
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>extern crate rand;

use iron::headers;
use iron::prelude::*;
use iron::method::Method;
use iron::modifiers::{Redirect, Header};
use iron::{Handler, Url, status};

use rand::Rng;

use std::collections::HashMap;
use std::sync::RwLock;

use urlencoded::UrlEncodedBody;

pub struct UrlShortenerHandler {
    shortened_urls: RwLock<HashMap<String, Url>>,
}

impl UrlShortenerHandler {
    pub fn new() -> Self {
        UrlShortenerHandler { shortened_urls: RwLock::new(HashMap::new()) }
    }
}

impl Handler for UrlShortenerHandler {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        match &req.method {
            &Method::Post => {
                let long_url = req.get_ref::<UrlEncodedBody>()
                    .map_err(|_| "URL encoded body missing")
                    .and_then(|data| match data.get("url") {
                        Some(urls) => Ok(urls.first().unwrap()),
                        None => Err("Parameter 'url' missing from the URL encoded body"),
                    })
                    .and_then(|url| Url::parse(url).map_err(|_| "Parameter 'url' is invalid"));

                match long_url {
                    Ok(long_url) => {
                        let random_key: String =
                        rand::thread_rng().gen_ascii_chars().take(5).collect();
                        let short_url = format!("http://localhost:3000/{}", random_key);

                        self.shortened_urls.write().unwrap().insert(random_key, long_url);

                        Ok(Response::with((status::Created, Header(headers::Location(short_url)))))
                    }
                    Err(e) => Ok(Response::with((status::BadRequest, e))),
                }
            }
            &Method::Get | &Method::Head => {
                let request_path = &req.url.path().join("/");
                match self.shortened_urls.read().unwrap().get(request_path) {
                    Some(url) => Ok(Response::with((status::Found, Redirect(url.clone())))),
                    None => Ok(Response::with(status::NotFound)),
                }
            }
            _ => Ok(Response::with(status::NotFound)),
        }
    }
}
<commit_msg>Generate new URL key on key collision<commit_after>extern crate rand;

use iron::headers;
use iron::prelude::*;
use iron::method::Method;
use iron::modifiers::{Redirect, Header};
use iron::{Handler, Url, status};

use rand::Rng;

use std::collections::HashMap;
use std::sync::RwLock;

use urlencoded::UrlEncodedBody;

pub struct UrlShortenerHandler {
    shortened_urls: RwLock<HashMap<String, Url>>,
}

impl UrlShortenerHandler {
    pub fn new() -> Self {
        UrlShortenerHandler { shortened_urls: RwLock::new(HashMap::new()) }
    }
}

impl Handler for UrlShortenerHandler {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        match &req.method {
            &Method::Post => {
                let long_url = req.get_ref::<UrlEncodedBody>()
                    .map_err(|_| "URL encoded body missing")
                    .and_then(|data| match data.get("url") {
                        Some(urls) => Ok(urls.first().unwrap()),
                        None => Err("Parameter 'url' missing from the URL encoded body"),
                    })
                    .and_then(|url| Url::parse(url).map_err(|_| "Parameter 'url' is invalid"));

                match long_url {
                    Ok(long_url) => {
                        match self.shortened_urls.write() {
                            Ok(mut shortened_urls) => {
                                let mut url_key: Option<String> = None;
                                while url_key.is_none() {
                                    let random_key: String =
                                        rand::thread_rng().gen_ascii_chars().take(5).collect();
                                    url_key = match shortened_urls.get(&random_key) {
                                        Some(_) => None,
                                        None => Some(random_key),
                                    }
                                }
                                let url_key = url_key.unwrap();

                                let short_url = format!("http://localhost:3000/{}", url_key);
                                shortened_urls.insert(url_key, long_url);
                                Ok(Response::with((status::Created,
                                                   Header(headers::Location(short_url)))))
                            }
                            Err(_) => {
                                println!("Error acquiring shortened_url lock");
                                Ok(Response::with(status::InternalServerError))
                            }
                        }
                    }
                    Err(e) => Ok(Response::with((status::BadRequest, e))),
                }
            }
            &Method::Get | &Method::Head => {
                let request_path = &req.url.path().join("/");
                match self.shortened_urls.read().unwrap().get(request_path) {
                    Some(url) => Ok(Response::with((status::Found, Redirect(url.clone())))),
                    None => Ok(Response::with(status::NotFound)),
                }
            }
            _ => Ok(Response::with(status::NotFound)),
        }
    }
}
<|endoftext|>