<commit_before>#[macro_use]
mod macros;

use coerce::{AsBool,AsNumber};

use french_press::ScopeManager;
use french_press::js_types::js_type::{JsVar, JsType, Binding};
use french_press::js_types::js_type::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::*;

pub fn eval_string(string: &str, state: &mut ScopeManager) -> JsVar {
    match parse_Stmt(string) {
        Ok(stmt) => eval_stmt(&stmt, state),
        //Err(e) => JsError(format!("{:?}", e))
        Err(_) => unimplemented!()
    }
    //eval_stmt(parse_Stmt(string).unwrap(), state)
}

pub fn eval_stmt(s: &Stmt, mut state: &mut ScopeManager) -> JsVar {
    match *s {
        Assign(ref var_string, ref exp) => {
            // TODO: this is a hack to return the value properly, which should be changed once we
            // stop using HashMap to store state.
            let mut var = eval_exp(exp, state);
            let cloned = var.clone();
            var.binding = Binding::new(var_string);
            match state.alloc(var, None) {
                Ok(_) => (),
                e @ Err(_) => println!("{:?}", e),
            }
            cloned
        },
        BareExp(ref exp) => eval_exp(exp, &mut state),
        Decl(ref var_string, ref exp) => {
            let mut var = eval_exp(exp, state);
            var.binding = Binding::new(var_string);
            // TODO: use value
            match state.alloc(var, None) {
                Ok(_) => (),
                e @ Err(_) => println!("{:?}", e),
            }
            JsVar::new(JsType::JsUndef)
        },
        If(ref condition, ref if_block, ref else_block) => {
            if eval_exp(&condition, state).as_bool() {
                eval_stmt(&*if_block, state)
            } else {
                if let Some(ref block) = *else_block {
                    eval_stmt(&*block, state)
                } else {
                    JsVar::new(JsType::JsUndef)
                }
            }
        },
        Ret(_) => panic!("unimplemented: ret statement"),
        Seq(ref s1, ref s2) => {
            let _exp = eval_stmt(&*s1, &mut state);
            eval_stmt(&*s2, &mut state)
        },
        While(ref condition, ref block) => {
            let mut ret_val = JsVar::new(JsUndef);
            loop {
                if eval_exp(&condition, state).as_bool() {
                    ret_val = eval_stmt(&*block, state)
                } else {
                    return ret_val
                }
            }
        }
    }
}

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(_, _) => {
            unimplemented!()
            //// TODO: create scope with arguments
            //let fun_name = eval_exp(fun_exp, state);
            //match fun_name {
            //    JsFunction(_, _, stmt) => eval_stmt(&*stmt, state),
            //    _ => panic!("TypeError: {} is not a function.", fun_name)
            //}
        },
        &Defun(_, _, _) => {
            unimplemented!()
            // TODO unimpl
            //if let Some(ref var) = *opt_var {
            //    let f = JsFunction(var.clone(), params.clone(), (*block).clone());
            //    state.insert(var.clone(), f);
            //    JsUndefined
            //} else {
            //    JsFunction(String::from(""), params.clone(), (*block).clone())
            //}
        },
        &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) => {
            match state.load(&Binding::new(var)) {
                Ok((var, _)) => var,
                //_ => JsError(format!("ReferenceError: {} is not defined", var))
                _ => panic!(format!("ReferenceError: {} is not defined", var))
            }
        }
    }
}

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

    fn new_hash_set() -> HashSet<Binding> {
        HashSet::new()
    }

    #[test]
    fn test_eval_literals() {
        let mut state = init_gc(new_hash_set);
        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(new_hash_set);
        //assert_eq!(JsType::JsNum(1.0f64), eval_string("var a = 1;\n", &mut state).t);
        //assert_eq!(&JsType::JsNum(1.0), state.get(&String::from("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(new_hash_set);
        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>Return values from Decl.<commit_after>#[macro_use]
mod macros;

use coerce::{AsBool,AsNumber};

use french_press::ScopeManager;
use french_press::js_types::js_type::{JsVar, JsType, Binding};
use french_press::js_types::js_type::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::*;

pub fn eval_string(string: &str, state: &mut ScopeManager) -> JsVar {
    match parse_Stmt(string) {
        Ok(stmt) => eval_stmt(&stmt, state),
        //Err(e) => JsError(format!("{:?}", e))
        Err(_) => unimplemented!()
    }
    //eval_stmt(parse_Stmt(string).unwrap(), state)
}

pub fn eval_stmt(s: &Stmt, mut state: &mut ScopeManager) -> JsVar {
    match *s {
        Assign(ref var_string, ref exp) => {
            // TODO: this is a hack to return the value properly, which should be changed once we
            // stop using HashMap to store state.
            let mut var = eval_exp(exp, state);
            let cloned = var.clone();
            var.binding = Binding::new(var_string);
            match state.alloc(var, None) {
                Ok(_) => (),
                e @ Err(_) => println!("{:?}", e),
            }
            cloned
        },
        BareExp(ref exp) => eval_exp(exp, &mut state),
        Decl(ref var_string, ref exp) => {
            let mut var = eval_exp(exp, state);
            var.binding = Binding::new(var_string);
            // TODO: use value
            match state.alloc(var.clone(), None) {
                Ok(_) => var,
                e @ Err(_) => panic!("{:?}", e),
            }
        },
        If(ref condition, ref if_block, ref else_block) => {
            if eval_exp(&condition, state).as_bool() {
                eval_stmt(&*if_block, state)
            } else {
                if let Some(ref block) = *else_block {
                    eval_stmt(&*block, state)
                } else {
                    JsVar::new(JsType::JsUndef)
                }
            }
        },
        Ret(_) => panic!("unimplemented: ret statement"),
        Seq(ref s1, ref s2) => {
            let _exp = eval_stmt(&*s1, &mut state);
            eval_stmt(&*s2, &mut state)
        },
        While(ref condition, ref block) => {
            let mut ret_val = JsVar::new(JsUndef);
            loop {
                if eval_exp(&condition, state).as_bool() {
                    ret_val = eval_stmt(&*block, state)
                } else {
                    return ret_val
                }
            }
        }
    }
}

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(_, _) => {
            unimplemented!()
            //// TODO: create scope with arguments
            //let fun_name = eval_exp(fun_exp, state);
            //match fun_name {
            //    JsFunction(_, _, stmt) => eval_stmt(&*stmt, state),
            //    _ => panic!("TypeError: {} is not a function.", fun_name)
            //}
        },
        &Defun(_, _, _) => {
            unimplemented!()
            // TODO unimpl
            //if let Some(ref var) = *opt_var {
            //    let f = JsFunction(var.clone(), params.clone(), (*block).clone());
            //    state.insert(var.clone(), f);
            //    JsUndefined
            //} else {
            //    JsFunction(String::from(""), params.clone(), (*block).clone())
            //}
        },
        &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) => {
            match state.load(&Binding::new(var)) {
                Ok((var, _)) => var,
                //_ => JsError(format!("ReferenceError: {} is not defined", var))
                _ => panic!(format!("ReferenceError: {} is not defined", var))
            }
        }
    }
}

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

    fn new_hash_set() -> HashSet<Binding> {
        HashSet::new()
    }

    #[test]
    fn test_eval_literals() {
        let mut state = init_gc(new_hash_set);
        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(new_hash_set);
        //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(new_hash_set);
        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>
use clap::ArgMatches;

use doapi::{DoManager, DoRequest};

use config::Config;
use message::CliMessage;

pub fn run(m: &ArgMatches, cfg: &mut Config) {
    if m.is_present("verbose") { cfg.verbose = true; }
    if m.is_present("nosend") { cfg.no_send = true; }
    let domgr = DoManager::with_token(&cfg.auth[..]);
    match m.subcommand() {
        ("regions", Some(m))         => {
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::Request(
                    &domgr.regions()
                         .to_string()
                         .replace("\n", "\n\t")[..]).display();
            }
            if cfg.no_send || m.is_present("nosend") { return }
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::JsonResponse.display();
                match domgr.regions().retrieve_json() {
                    Ok(s)  => {
                        CliMessage::Success.display();
                        println!("\n\t{}\n", s);
                    },
                    Err(e) => {
                        CliMessage::Failure.display();
                        println!("\n\t{}\n", e);
                    }
                }
            }
            CliMessage::Regions.display();
            match domgr.regions().retrieve() {
                Ok(v) => {
                    CliMessage::Success.display();
                    for reg in v.iter() {
                        CliMessage::Region.display();
                        println!("\t{}", reg);
                    }
                    if v.is_empty() { println!("\tNo regions to dipslay"); }
                },
                Err(e) => {
                    CliMessage::Failure.display();
                    println!("{}\n", e);
                }
            }
        },
        ("sizes", Some(m))           => {
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::Request(
                    &domgr.sizes()
                         .to_string()
                         .replace("\n", "\n\t")[..]).display();
            }
            if cfg.no_send || m.is_present("nosend") { return }
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::JsonResponse.display();
                match domgr.sizes().retrieve_json() {
                    Ok(s)  => {
                        CliMessage::Success.display();
                        println!("\n\t{}\n", s);
                    },
                    Err(e) => {
                        CliMessage::Failure.display();
                        println!("\n\t{}\n", e);
                    }
                }
            }
            CliMessage::Sizes.display();
            match domgr.sizes().retrieve() {
                Ok(v) => {
                    CliMessage::Success.display();
                    for siz in v.iter() {
                        CliMessage::Size.display();
                        println!("\t{}", siz);
                    }
                    if v.is_empty() { println!("\tNo sizes to dipslay"); }
                },
                Err(e) => {
                    CliMessage::Failure.display();
                    println!("{}\n", e);
                }
            }
        },
        ("images", Some(m))          => {
            let request = if m.is_present("applications") {
                domgr.images().applications()
            } else if m.is_present("distributions") {
                domgr.images().distributions()
            } else if m.is_present("private") {
                domgr.images().private()
            } else if m.is_present("available") {
                domgr.images().available()
            } else {
                domgr.images()
            };
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::Request(
                    &request.to_string()
                        .replace("\n", "\n\t")[..]
                ).display();
            }
            if cfg.no_send || m.is_present("nosend") { return }
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::JsonResponse.display();
                match request.retrieve_json() {
                    Ok(s)  => {
                        CliMessage::Success.display();
                        println!("\n\t{}\n", s);
                    },
                    Err(e) => {
                        CliMessage::Failure.display();
                        println!("\n\t{}\n", e);
                    }
                }
            }
            CliMessage::Images.display();
            match request.retrieve() {
                Ok(v) => {
                    CliMessage::Success.display();
                    for img in v.iter() {
                        CliMessage::ImageList.display();
                        println!("\t{}", &img.to_string()[..].replace("$", ""));
                    }
                    if v.is_empty() { println!("\tNo images to dipslay"); }
                },
                Err(e) => {
                    CliMessage::Failure.display();
                    println!("{}\n", e);
                }
            }
        },
        ("ssh-keys", Some(m))        => {
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::Request(
                    &domgr.ssh_keys()
                         .to_string()
                         .replace("\n", "\n\t")[..]).display();
            }
            if cfg.no_send || m.is_present("nosend") { return }
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::JsonResponse.display();
                match domgr.ssh_keys().retrieve_json() {
                    Ok(s)  => {
                        CliMessage::Success.display();
                        println!("\n\t{}\n", s);
                    },
                    Err(e) => {
                        CliMessage::Failure.display();
                        println!("\n\t{}\n", e);
                    }
                }
            }
            CliMessage::SshKeys.display();
            match domgr.ssh_keys().retrieve() {
                Ok(v) => {
                    CliMessage::Success.display();
                    for k in v.iter() {
                        CliMessage::SshKeys.display();
                        println!("\t{}", k);
                    }
                    if v.is_empty() { println!("\tNo SSH keys to dipslay"); }
                },
                Err(e) => {
                    CliMessage::Failure.display();
                    println!("{}\n", e);
                }
            }
        },
        ("droplets", Some(m))        => {
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::Request(
                    &domgr.droplets()
                         .to_string()
                         .replace("\n", "\n\t")[..]).display();
            }
            if cfg.no_send || m.is_present("nosend") { return }
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::JsonResponse.display();
                match domgr.droplets().retrieve_json() {
                    Ok(s)  => {
                        CliMessage::Success.display();
                        println!("\n\t{}\n", s);
                    },
                    Err(e) => {
                        CliMessage::Failure.display();
                        println!("\n\t{}\n", e);
                    }
                }
            }
            CliMessage::Droplets.display();
            match domgr.droplets().retrieve() {
                Ok(v) => {
                    CliMessage::Success.display();
                    for d in v.iter() {
                        CliMessage::AnonDroplet.display();
                        println!("\t{}", &d.to_string()[..].replace("\n", "\n\t"));
                    }
                    if v.is_empty() { println!("\tNo droplets to dipslay"); }
                },
                Err(e) => {
                    CliMessage::Failure.display();
                    println!("{}\n", e);
                }
            }
        },
        ("domains", Some(m))         => {
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::Request(
                    &domgr.domains()
                         .to_string()
                         .replace("\n", "\n\t")[..]).display();
            }
            if cfg.no_send || m.is_present("nosend") { return }
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::JsonResponse.display();
                match domgr.domains().retrieve_json() {
                    Ok(s)  => {
                        CliMessage::Success.display();
                        println!("\n\t{}\n", s);
                    },
                    Err(e) => {
                        CliMessage::Failure.display();
                        println!("\n\t{}\n", e);
                    }
                }
            }
            CliMessage::Domains.display();
            match domgr.domains().retrieve() {
                Ok(v) => {
                    CliMessage::Success.display();
                    for d in v.iter() {
                        CliMessage::Domains.display();
                        println!("\t{}", d);
                    }
                    if v.is_empty() { println!("\tNo domains to dipslay"); }
                },
                Err(e) => {
                    CliMessage::Failure.display();
                    println!("{}\n", e);
                }
            }
        },
        ("account-actions", Some(m)) => {
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::Request(
                    &domgr.account()
                         .actions()
                         .to_string()
                         .replace("\n", "\n\t")[..]).display();
            }
            if cfg.no_send || m.is_present("nosend") { return }
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::JsonResponse.display();
                match domgr.account().actions().retrieve_json() {
                    Ok(s)  => {
                        CliMessage::Success.display();
                        println!("\n\t{}\n", s);
                    },
                    Err(e) => {
                        CliMessage::Failure.display();
                        println!("\n\t{}\n", e);
                    }
                }
            }
            CliMessage::Actions.display();
            match domgr.account().actions().retrieve() {
                Ok(v) => {
                    CliMessage::Success.display();
                    for act in v.iter() {
                        CliMessage::Action.display();
                        println!("\t{}", act);
                    }
                    if v.is_empty() { println!("\tNo account actions to dipslay"); }
                },
                Err(e) => {
                    CliMessage::Failure.display();
                    println!("{}\n", e);
                }
            }
        },
        _                      => unreachable!()
    }
}
<commit_msg>imp: fixes output of list regions command<commit_after>
use clap::ArgMatches;

use doapi::{DoManager, DoRequest};

use config::Config;
use message::CliMessage;

pub fn run(m: &ArgMatches, cfg: &mut Config) {
    if m.is_present("verbose") { cfg.verbose = true; }
    if m.is_present("nosend") { cfg.no_send = true; }
    let domgr = DoManager::with_token(&cfg.auth[..]);
    match m.subcommand() {
        ("regions", Some(m))         => {
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::Request(
                    &domgr.regions()
                         .to_string()
                         .replace("\n", "\n\t")[..]).display();
            }
            if cfg.no_send || m.is_present("nosend") { return }
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::JsonResponse.display();
                match domgr.regions().retrieve_json() {
                    Ok(s)  => {
                        CliMessage::Success.display();
                        println!("\n\t{}\n", s);
                    },
                    Err(e) => {
                        CliMessage::Failure.display();
                        println!("\n\t{}\n", e);
                    }
                }
            }
            CliMessage::Regions.display();
            match domgr.regions().retrieve() {
                Ok(v) => {
                    CliMessage::Success.display();
                    for reg in v.iter() {
                        CliMessage::Region.display();
                        println!("\t{}\n", &reg.to_string()[..].replace("\n", "\n\t"));
                    }
                    if v.is_empty() { println!("\tNo regions to dipslay"); }
                },
                Err(e) => {
                    CliMessage::Failure.display();
                    println!("{}\n", e);
                }
            }
        },
        ("sizes", Some(m))           => {
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::Request(
                    &domgr.sizes()
                         .to_string()
                         .replace("\n", "\n\t")[..]).display();
            }
            if cfg.no_send || m.is_present("nosend") { return }
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::JsonResponse.display();
                match domgr.sizes().retrieve_json() {
                    Ok(s)  => {
                        CliMessage::Success.display();
                        println!("\n\t{}\n", s);
                    },
                    Err(e) => {
                        CliMessage::Failure.display();
                        println!("\n\t{}\n", e);
                    }
                }
            }
            CliMessage::Sizes.display();
            match domgr.sizes().retrieve() {
                Ok(v) => {
                    CliMessage::Success.display();
                    for siz in v.iter() {
                        CliMessage::Size.display();
                        println!("\t{}", siz);
                    }
                    if v.is_empty() { println!("\tNo sizes to dipslay"); }
                },
                Err(e) => {
                    CliMessage::Failure.display();
                    println!("{}\n", e);
                }
            }
        },
        ("images", Some(m))          => {
            let request = if m.is_present("applications") {
                domgr.images().applications()
            } else if m.is_present("distributions") {
                domgr.images().distributions()
            } else if m.is_present("private") {
                domgr.images().private()
            } else if m.is_present("available") {
                domgr.images().available()
            } else {
                domgr.images()
            };
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::Request(
                    &request.to_string()
                        .replace("\n", "\n\t")[..]
                ).display();
            }
            if cfg.no_send || m.is_present("nosend") { return }
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::JsonResponse.display();
                match request.retrieve_json() {
                    Ok(s)  => {
                        CliMessage::Success.display();
                        println!("\n\t{}\n", s);
                    },
                    Err(e) => {
                        CliMessage::Failure.display();
                        println!("\n\t{}\n", e);
                    }
                }
            }
            CliMessage::Images.display();
            match request.retrieve() {
                Ok(v) => {
                    CliMessage::Success.display();
                    for img in v.iter() {
                        CliMessage::ImageList.display();
                        println!("\t{}", &img.to_string()[..].replace("$", ""));
                    }
                    if v.is_empty() { println!("\tNo images to dipslay"); }
                },
                Err(e) => {
                    CliMessage::Failure.display();
                    println!("{}\n", e);
                }
            }
        },
        ("ssh-keys", Some(m))        => {
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::Request(
                    &domgr.ssh_keys()
                         .to_string()
                         .replace("\n", "\n\t")[..]).display();
            }
            if cfg.no_send || m.is_present("nosend") { return }
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::JsonResponse.display();
                match domgr.ssh_keys().retrieve_json() {
                    Ok(s)  => {
                        CliMessage::Success.display();
                        println!("\n\t{}\n", s);
                    },
                    Err(e) => {
                        CliMessage::Failure.display();
                        println!("\n\t{}\n", e);
                    }
                }
            }
            CliMessage::SshKeys.display();
            match domgr.ssh_keys().retrieve() {
                Ok(v) => {
                    CliMessage::Success.display();
                    for k in v.iter() {
                        CliMessage::SshKeys.display();
                        println!("\t{}", k);
                    }
                    if v.is_empty() { println!("\tNo SSH keys to dipslay"); }
                },
                Err(e) => {
                    CliMessage::Failure.display();
                    println!("{}\n", e);
                }
            }
        },
        ("droplets", Some(m))        => {
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::Request(
                    &domgr.droplets()
                         .to_string()
                         .replace("\n", "\n\t")[..]).display();
            }
            if cfg.no_send || m.is_present("nosend") { return }
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::JsonResponse.display();
                match domgr.droplets().retrieve_json() {
                    Ok(s)  => {
                        CliMessage::Success.display();
                        println!("\n\t{}\n", s);
                    },
                    Err(e) => {
                        CliMessage::Failure.display();
                        println!("\n\t{}\n", e);
                    }
                }
            }
            CliMessage::Droplets.display();
            match domgr.droplets().retrieve() {
                Ok(v) => {
                    CliMessage::Success.display();
                    for d in v.iter() {
                        CliMessage::AnonDroplet.display();
                        println!("\t{}", &d.to_string()[..].replace("\n", "\n\t"));
                    }
                    if v.is_empty() { println!("\tNo droplets to dipslay"); }
                },
                Err(e) => {
                    CliMessage::Failure.display();
                    println!("{}\n", e);
                }
            }
        },
        ("domains", Some(m))         => {
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::Request(
                    &domgr.domains()
                         .to_string()
                         .replace("\n", "\n\t")[..]).display();
            }
            if cfg.no_send || m.is_present("nosend") { return }
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::JsonResponse.display();
                match domgr.domains().retrieve_json() {
                    Ok(s)  => {
                        CliMessage::Success.display();
                        println!("\n\t{}\n", s);
                    },
                    Err(e) => {
                        CliMessage::Failure.display();
                        println!("\n\t{}\n", e);
                    }
                }
            }
            CliMessage::Domains.display();
            match domgr.domains().retrieve() {
                Ok(v) => {
                    CliMessage::Success.display();
                    for d in v.iter() {
                        CliMessage::Domains.display();
                        println!("\t{}", d);
                    }
                    if v.is_empty() { println!("\tNo domains to dipslay"); }
                },
                Err(e) => {
                    CliMessage::Failure.display();
                    println!("{}\n", e);
                }
            }
        },
        ("account-actions", Some(m)) => {
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::Request(
                    &domgr.account()
                         .actions()
                         .to_string()
                         .replace("\n", "\n\t")[..]).display();
            }
            if cfg.no_send || m.is_present("nosend") { return }
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::JsonResponse.display();
                match domgr.account().actions().retrieve_json() {
                    Ok(s)  => {
                        CliMessage::Success.display();
                        println!("\n\t{}\n", s);
                    },
                    Err(e) => {
                        CliMessage::Failure.display();
                        println!("\n\t{}\n", e);
                    }
                }
            }
            CliMessage::Actions.display();
            match domgr.account().actions().retrieve() {
                Ok(v) => {
                    CliMessage::Success.display();
                    for act in v.iter() {
                        CliMessage::Action.display();
                        println!("\t{}", act);
                    }
                    if v.is_empty() { println!("\tNo account actions to dipslay"); }
                },
                Err(e) => {
                    CliMessage::Failure.display();
                    println!("{}\n", e);
                }
            }
        },
        _                      => unreachable!()
    }
}
<|endoftext|>


<commit_before>// run-pass
#![feature(core_intrinsics)]

use std::intrinsics::*;

pub fn main() {
    unsafe {
        let mut x: Box<u8> = Box::new(0);
        let mut y: Box<u8> = Box::new(0);

        // test volatile load
        assert_eq!(volatile_load(&*x), 0);
        *x = 1;
        assert_eq!(volatile_load(&*x), 1);

        // test volatile store
        volatile_store(&mut *x, 2);
        assert_eq!(*x, 2);

        // test volatile copy memory
        volatile_copy_memory(&mut *y, &*x, 1);
        assert_eq!(*y, 2);

        // test volatile copy non-overlapping memory
        *x = 3;
        volatile_copy_nonoverlapping_memory(&mut *y, &*x, 1);
        assert_eq!(*y, 3);

        // test volatile set memory
        volatile_set_memory(&mut *x, 4, 1);
        assert_eq!(*x, 4);

        // test unaligned volatile load
        let arr: [u8; 3] = [1, 2, 3];
        let ptr = arr[1..].as_ptr() as *const u16;
        assert_eq!(unaligned_volatile_load(ptr), u16::from_ne_bytes([arr[1], arr[2]]));

        // test unaligned volatile store
        let ptr = arr[1..].as_ptr() as *mut u16;
        unaligned_volatile_store(ptr, 0);
        assert_eq!(arr, [1, 0, 0]);
    }
}
<commit_msg>Removed trailing whitespace<commit_after>// run-pass
#![feature(core_intrinsics)]

use std::intrinsics::*;

pub fn main() {
    unsafe {
        let mut x: Box<u8> = Box::new(0);
        let mut y: Box<u8> = Box::new(0);

        // test volatile load
        assert_eq!(volatile_load(&*x), 0);
        *x = 1;
        assert_eq!(volatile_load(&*x), 1);

        // test volatile store
        volatile_store(&mut *x, 2);
        assert_eq!(*x, 2);

        // test volatile copy memory
        volatile_copy_memory(&mut *y, &*x, 1);
        assert_eq!(*y, 2);

        // test volatile copy non-overlapping memory
        *x = 3;
        volatile_copy_nonoverlapping_memory(&mut *y, &*x, 1);
        assert_eq!(*y, 3);

        // test volatile set memory
        volatile_set_memory(&mut *x, 4, 1);
        assert_eq!(*x, 4);

        // test unaligned volatile load
        let arr: [u8; 3] = [1, 2, 3];
        let ptr = arr[1..].as_ptr() as *const u16;
        assert_eq!(unaligned_volatile_load(ptr), u16::from_ne_bytes([arr[1], arr[2]]));

        // test unaligned volatile store
        let ptr = arr[1..].as_ptr() as *mut u16;
        unaligned_volatile_store(ptr, 0);
        assert_eq!(arr, [1, 0, 0]);
    }
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! `x86_64` architecture-specific implementation.
// pub mod cpu;
pub mod drivers;
pub mod interrupts;

#[path = "../x86_all/bda.rs"] pub mod bda;
#[path = "../x86_all/multiboot2.rs"] pub mod multiboot2;

use memory::PAddr;
use params::InitParams;
use ::kernel_init;

pub const ARCH_BITS: u8 = 64;

/// Trampoline to ensure we have a correct stack frame for calling [`arch_init`]
///
/// I have no idea why this works, but it does.
///
/// [`arch_init`]: fn.arch_init
#[naked]
#[no_mangle]
pub unsafe extern "C" fn long_mode_init() {
    asm!("movabsq $$(stack_top), %rsp");
    asm!("mov ax, 0
          mov ss, ax
          mov ds, ax
          mov es, ax
          mov fs, ax
          mov gs, ax
          call arch_init"
        :::: "intel");

}

/// Entry point for architecture-specific kernel init
///
/// This expects to be passed the address of a valid
/// Multiboot 2 info struct. It's the bootloader's responsibility to ensure
/// that this is passed in the correct register as expected by the calling
/// convention (`edi` on x86). If this isn't there, you can expect to have a
/// bad problem and not go to space today.
#[no_mangle]
pub extern "C" fn arch_init(multiboot_addr: PAddr) {
    use memory::arch::{HEAP_BASE, HEAP_TOP};

    ::io::term::CONSOLE.lock().clear();
    ::logger::initialize()
        .expect("Could not initialize logger!");

    kinfoln!("in arch_init");

    // -- Unpack multiboot tag ------------------------------------------------
    kinfoln!( dots: " . "
            , "trying to unpack multiboot info at {:?}"
            , multiboot_addr);

    let boot_info
        = unsafe { multiboot2::Info::from(multiboot_addr)
                    .expect("Could not unpack multiboot2 information!") };
    // Extract the memory map tag from the multiboot info
    let mem_map = boot_info.mem_map()
                           .expect("Memory map tag required!");

    kinfoln!(dots: " . ", "Detected memory areas:");
    for area in mem_map {
        kinfoln!( dots: " . . ", "{}", area);
        // TODO: add memory map to init params here
    }

    // Extract ELF sections tag from the multiboot info
    let elf_sections_tag
        = boot_info.elf_sections()
                   .expect("ELF sections tag required!");

    kinfoln!(dots: " . ", "Detecting kernel ELF sections:");

    // Extract kernel ELF sections from  multiboot info
    let kernel_begin
        = elf_sections_tag.sections()
            .map(|s| {
                kinfoln!( dots: " . . "
                     , "address: {:#08x}, size: {:#08x}, flags: {:#08x}"
                        , s.addr()
                        , s.length()
                        , s.flags() );
                s.addr() })
            .min()
            .expect("Could not find kernel start section!\
                    \nSomething is deeply wrong.");

    let mut n_elf_sections = 0;
    let kernel_end
        = elf_sections_tag.sections()
            .map(|s| { n_elf_sections += 1; s.addr() })
            .max()
            .expect("Could not find kernel end section!\
                    \nSomething is deeply wrong.");

    kinfoln!( dots: " . ", "Detected {} kernel ELF sections.", n_elf_sections);
    kinfoln!(dots: " . . ", "Kernel begins at {:#x} and ends at {:#x}."
             , kernel_begin, kernel_end );

    let multiboot_end = multiboot_addr + boot_info.length as u64;

    kinfoln!(dots: " . . ", "Multiboot info begins at {:#x} and ends at {:#x}."
             , multiboot_addr, multiboot_end);

    let params = InitParams { kernel_base: kernel_begin
                            , kernel_top:  kernel_end
                            , heap_base:   unsafe { PAddr::from(HEAP_BASE) }
                            , heap_top:    unsafe { PAddr::from(HEAP_TOP) }
                            };
    kernel_init(params);
}
<commit_msg>refac(x86_64): pretty-print ELF sections in arch_init<commit_after>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! `x86_64` architecture-specific implementation.
// pub mod cpu;
pub mod drivers;
pub mod interrupts;

#[path = "../x86_all/bda.rs"] pub mod bda;
#[path = "../x86_all/multiboot2.rs"] pub mod multiboot2;

use memory::PAddr;
use params::InitParams;
use ::kernel_init;

pub const ARCH_BITS: u8 = 64;

/// Trampoline to ensure we have a correct stack frame for calling [`arch_init`]
///
/// I have no idea why this works, but it does.
///
/// [`arch_init`]: fn.arch_init
#[naked]
#[no_mangle]
pub unsafe extern "C" fn long_mode_init() {
    asm!("movabsq $$(stack_top), %rsp");
    asm!("mov ax, 0
          mov ss, ax
          mov ds, ax
          mov es, ax
          mov fs, ax
          mov gs, ax
          call arch_init"
        :::: "intel");

}

/// Entry point for architecture-specific kernel init
///
/// This expects to be passed the address of a valid
/// Multiboot 2 info struct. It's the bootloader's responsibility to ensure
/// that this is passed in the correct register as expected by the calling
/// convention (`edi` on x86). If this isn't there, you can expect to have a
/// bad problem and not go to space today.
#[no_mangle]
pub extern "C" fn arch_init(multiboot_addr: PAddr) {
    use memory::arch::{HEAP_BASE, HEAP_TOP};

    ::io::term::CONSOLE.lock().clear();
    ::logger::initialize()
        .expect("Could not initialize logger!");

    kinfoln!("in arch_init");

    // -- Unpack multiboot tag ------------------------------------------------
    kinfoln!( dots: " . "
            , "trying to unpack multiboot info at {:?}"
            , multiboot_addr);

    let boot_info
        = unsafe { multiboot2::Info::from(multiboot_addr)
                    .expect("Could not unpack multiboot2 information!") };
    // Extract the memory map tag from the multiboot info
    let mem_map = boot_info.mem_map()
                           .expect("Memory map tag required!");

    kinfoln!(dots: " . ", "Detected memory areas:");
    for area in mem_map {
        kinfoln!( dots: " . . ", "{}", area);
        // TODO: add memory map to init params here
    }

    // Extract ELF sections tag from the multiboot info
    let elf_sections_tag
        = boot_info.elf_sections()
                   .expect("ELF sections tag required!");

    kinfoln!(dots: " . ", "Detecting kernel ELF sections:");

    // Extract kernel ELF sections from  multiboot info
    let kernel_begin
        = elf_sections_tag.sections()
            .map(|s| {
                kinfoln!( dots: " . . ", "{}, flags: {:?}", s, s.flags() );
                s.addr() })
            .min()
            .expect("Could not find kernel start section!\
                    \nSomething is deeply wrong.");

    let mut n_elf_sections = 0;
    let kernel_end
        = elf_sections_tag.sections()
            .map(|s| { n_elf_sections += 1; s.addr() })
            .max()
            .expect("Could not find kernel end section!\
                    \nSomething is deeply wrong.");

    kinfoln!( dots: " . ", "Detected {} kernel ELF sections.", n_elf_sections);
    kinfoln!(dots: " . . ", "Kernel begins at {:#x} and ends at {:#x}."
             , kernel_begin, kernel_end );

    let multiboot_end = multiboot_addr + boot_info.length as u64;

    kinfoln!(dots: " . . ", "Multiboot info begins at {:#x} and ends at {:#x}."
             , multiboot_addr, multiboot_end);

    let params = InitParams { kernel_base: kernel_begin
                            , kernel_top:  kernel_end
                            , heap_base:   unsafe { PAddr::from(HEAP_BASE) }
                            , heap_top:    unsafe { PAddr::from(HEAP_TOP) }
                            };
    kernel_init(params);
}
<|endoftext|>


<commit_before>pub fn verse(n: i32) -> String {
    match n {
        0 => "No more bottles of beer on the wall, no more bottles of beer.\n\
              Go to the store and buy some more, 99 bottles of beer on the wall.\n".to_string(),
        1 => "1 bottle of beer on the wall, 1 bottle of beer.\n\
              Take it down and pass it around, no more bottles of beer on the wall.\n".to_string(),
        2 => "2 bottles of beer on the wall, 2 bottles of beer.\n\
              Take one down and pass it around, 1 bottle of beer on the wall.\n".to_string(),
        n if n > 2 && n <= 99 =>
            format!(
                "{n} bottles of beer on the wall, {n} bottles of beer.\n\
                 Take one down and pass it around, {n_minus_1} bottles of beer on the wall.\n",
                n=n,
                n_minus_1=n - 1),
        _ =>
            panic!(),
    }
}

pub fn sing(start: i32, end: i32) -> String {
    let mut song = Vec::new();
    for n in (end .. start + 1).rev() {
        song.push(verse(n))
    }
    song.join("\n")
}
<commit_msg>beer-song: Use map<commit_after>pub fn verse(n: i32) -> String {
    match n {
        0 => "No more bottles of beer on the wall, no more bottles of beer.\n\
              Go to the store and buy some more, 99 bottles of beer on the wall.\n".to_string(),
        1 => "1 bottle of beer on the wall, 1 bottle of beer.\n\
              Take it down and pass it around, no more bottles of beer on the wall.\n".to_string(),
        2 => "2 bottles of beer on the wall, 2 bottles of beer.\n\
              Take one down and pass it around, 1 bottle of beer on the wall.\n".to_string(),
        n if n > 2 && n <= 99 =>
            format!(
                "{n} bottles of beer on the wall, {n} bottles of beer.\n\
                 Take one down and pass it around, {n_minus_1} bottles of beer on the wall.\n",
                n=n,
                n_minus_1=n - 1),
        _ =>
            panic!(),
    }
}

pub fn sing(start: i32, end: i32) -> String {
    (end .. start + 1).rev().map(|n| verse(n)).collect::<Vec<_>>().join("\n")
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};
use std::fs;
use std::io;
use std::path::{Path, PathBuf};

use core::{Package, SourceId, PackageId, EitherManifest};
use util::{self, paths, CargoResult, human, Config, ChainError};
use util::important_paths::find_project_manifest_exact;
use util::toml::Layout;

pub fn read_manifest(path: &Path, source_id: &SourceId, config: &Config)
                     -> CargoResult<(EitherManifest, Vec<PathBuf>)> {
    trace!("read_package; path={}; source-id={}", path.display(), source_id);
    let contents = paths::read(path)?;

    let layout = Layout::from_project_path(path.parent().unwrap());
    let root = layout.root.clone();
    util::toml::to_manifest(&contents, source_id, layout, config).chain_error(|| {
        human(format!("failed to parse manifest at `{}`",
                      root.join("Cargo.toml").display()))
    })
}

pub fn read_package(path: &Path, source_id: &SourceId, config: &Config)
                    -> CargoResult<(Package, Vec<PathBuf>)> {
    trace!("read_package; path={}; source-id={}", path.display(), source_id);
    let (manifest, nested) = read_manifest(path, source_id, config)?;
    let manifest = match manifest {
        EitherManifest::Real(manifest) => manifest,
        EitherManifest::Virtual(..) => {
            bail!("found a virtual manifest at `{}` instead of a package \
                   manifest", path.display())
        }
    };

    Ok((Package::new(manifest, path), nested))
}

pub fn read_packages(path: &Path, source_id: &SourceId, config: &Config)
                     -> CargoResult<Vec<Package>> {
    let mut all_packages = HashMap::new();
    let mut visited = HashSet::<PathBuf>::new();

    trace!("looking for root package: {}, source_id={}", path.display(), source_id);

    walk(path, &mut |dir| {
        trace!("looking for child package: {}", dir.display());

        // Don't recurse into hidden/dot directories unless we're at the toplevel
        if dir != path {
            let name = dir.file_name().and_then(|s| s.to_str());
            if name.map(|s| s.starts_with(".")) == Some(true) {
                return Ok(false)
            }

            // Don't automatically discover packages across git submodules
            if fs::metadata(&dir.join(".git")).is_ok() {
                return Ok(false)
            }
        }

        // Don't ever look at target directories
        if dir.file_name().and_then(|s| s.to_str()) == Some("target") &&
           has_manifest(dir.parent().unwrap()) {
            return Ok(false)
        }

        if has_manifest(dir) {
            read_nested_packages(dir, &mut all_packages, source_id, config,
                                      &mut visited)?;
        }
        Ok(true)
    })?;

    if all_packages.is_empty() {
        Err(human(format!("Could not find Cargo.toml in `{}`", path.display())))
    } else {
        Ok(all_packages.into_iter().map(|(_, v)| v).collect())
    }
}

fn walk(path: &Path, callback: &mut FnMut(&Path) -> CargoResult<bool>)
        -> CargoResult<()> {
    if !callback(path)? {
        trace!("not processing {}", path.display());
        return Ok(())
    }

    // Ignore any permission denied errors because temporary directories
    // can often have some weird permissions on them.
    let dirs = match fs::read_dir(path) {
        Ok(dirs) => dirs,
        Err(ref e) if e.kind() == io::ErrorKind::PermissionDenied => {
            return Ok(())
        }
        Err(e) => {
            return Err(human(e)).chain_error(|| {
                human(format!("failed to read directory `{}`", path.display()))
            })
        }
    };
    for dir in dirs {
        let dir = dir?;
        if dir.file_type()?.is_dir() {
            walk(&dir.path(), callback)?;
        }
    }
    Ok(())
}

fn has_manifest(path: &Path) -> bool {
    find_project_manifest_exact(path, "Cargo.toml").is_ok()
}

fn read_nested_packages(path: &Path,
                        all_packages: &mut HashMap<PackageId, Package>,
                        source_id: &SourceId,
                        config: &Config,
                        visited: &mut HashSet<PathBuf>) -> CargoResult<()> {
    if !visited.insert(path.to_path_buf()) { return Ok(()) }

    let manifest_path = find_project_manifest_exact(path, "Cargo.toml")?;

    let result = read_manifest(&manifest_path, source_id, config);

    // Ignore malformed manifests
    if result.is_err() {
        info!("skipping malformed package found at `{}`",
              path.to_string_lossy());
        return Ok(());
    }

    let (manifest, nested) = result.unwrap();
    let manifest = match manifest {
        EitherManifest::Real(manifest) => manifest,
        EitherManifest::Virtual(..) => return Ok(()),
    };
    let pkg = Package::new(manifest, &manifest_path);

    let pkg_id = pkg.package_id().clone();
    if !all_packages.contains_key(&pkg_id) {
        all_packages.insert(pkg_id, pkg);
    } else {
        info!("skipping nested package `{}` found at `{}`",
              pkg.name(), path.to_string_lossy());
    }

    // Registry sources are not allowed to have `path=` dependencies because
    // they're all translated to actual registry dependencies.
    //
    // We normalize the path here ensure that we don't infinitely walk around
    // looking for crates. By normalizing we ensure that we visit this crate at
    // most once.
    //
    // TODO: filesystem/symlink implications?
    if !source_id.is_registry() {
        for p in nested.iter() {
            let path = util::normalize_path(&path.join(p));
            read_nested_packages(&path, all_packages, source_id,
                                      config, visited)?;
        }
    }

    Ok(())
}
<commit_msg>Refactorized code<commit_after>use std::collections::{HashMap, HashSet};
use std::fs;
use std::io;
use std::path::{Path, PathBuf};

use core::{Package, SourceId, PackageId, EitherManifest};
use util::{self, paths, CargoResult, human, Config, ChainError};
use util::important_paths::find_project_manifest_exact;
use util::toml::Layout;

pub fn read_manifest(path: &Path, source_id: &SourceId, config: &Config)
                     -> CargoResult<(EitherManifest, Vec<PathBuf>)> {
    trace!("read_package; path={}; source-id={}", path.display(), source_id);
    let contents = paths::read(path)?;

    let layout = Layout::from_project_path(path.parent().unwrap());
    let root = layout.root.clone();
    util::toml::to_manifest(&contents, source_id, layout, config).chain_error(|| {
        human(format!("failed to parse manifest at `{}`",
                      root.join("Cargo.toml").display()))
    })
}

pub fn read_package(path: &Path, source_id: &SourceId, config: &Config)
                    -> CargoResult<(Package, Vec<PathBuf>)> {
    trace!("read_package; path={}; source-id={}", path.display(), source_id);
    let (manifest, nested) = read_manifest(path, source_id, config)?;
    let manifest = match manifest {
        EitherManifest::Real(manifest) => manifest,
        EitherManifest::Virtual(..) => {
            bail!("found a virtual manifest at `{}` instead of a package \
                   manifest", path.display())
        }
    };

    Ok((Package::new(manifest, path), nested))
}

pub fn read_packages(path: &Path, source_id: &SourceId, config: &Config)
                     -> CargoResult<Vec<Package>> {
    let mut all_packages = HashMap::new();
    let mut visited = HashSet::<PathBuf>::new();

    trace!("looking for root package: {}, source_id={}", path.display(), source_id);

    walk(path, &mut |dir| {
        trace!("looking for child package: {}", dir.display());

        // Don't recurse into hidden/dot directories unless we're at the toplevel
        if dir != path {
            let name = dir.file_name().and_then(|s| s.to_str());
            if name.map(|s| s.starts_with(".")) == Some(true) {
                return Ok(false)
            }

            // Don't automatically discover packages across git submodules
            if fs::metadata(&dir.join(".git")).is_ok() {
                return Ok(false)
            }
        }

        // Don't ever look at target directories
        if dir.file_name().and_then(|s| s.to_str()) == Some("target") &&
           has_manifest(dir.parent().unwrap()) {
            return Ok(false)
        }

        if has_manifest(dir) {
            read_nested_packages(dir, &mut all_packages, source_id, config,
                                      &mut visited)?;
        }
        Ok(true)
    })?;

    if all_packages.is_empty() {
        Err(human(format!("Could not find Cargo.toml in `{}`", path.display())))
    } else {
        Ok(all_packages.into_iter().map(|(_, v)| v).collect())
    }
}

fn walk(path: &Path, callback: &mut FnMut(&Path) -> CargoResult<bool>)
        -> CargoResult<()> {
    if !callback(path)? {
        trace!("not processing {}", path.display());
        return Ok(())
    }

    // Ignore any permission denied errors because temporary directories
    // can often have some weird permissions on them.
    let dirs = match fs::read_dir(path) {
        Ok(dirs) => dirs,
        Err(ref e) if e.kind() == io::ErrorKind::PermissionDenied => {
            return Ok(())
        }
        Err(e) => {
            return Err(human(e)).chain_error(|| {
                human(format!("failed to read directory `{}`", path.display()))
            })
        }
    };
    for dir in dirs {
        let dir = dir?;
        if dir.file_type()?.is_dir() {
            walk(&dir.path(), callback)?;
        }
    }
    Ok(())
}

fn has_manifest(path: &Path) -> bool {
    find_project_manifest_exact(path, "Cargo.toml").is_ok()
}

fn read_nested_packages(path: &Path,
                        all_packages: &mut HashMap<PackageId, Package>,
                        source_id: &SourceId,
                        config: &Config,
                        visited: &mut HashSet<PathBuf>) -> CargoResult<()> {
    if !visited.insert(path.to_path_buf()) { return Ok(()) }

    let manifest_path = find_project_manifest_exact(path, "Cargo.toml")?;

    let (manifest, nested) = match read_manifest(&manifest_path, source_id, config) {
        Err(_) => {
            // Ignore malformed manifests found on git repositories
            //
            // git source try to find and read all manifests from the repository
            // but since it's not possible to exclude folders from this search
            // it's safer to ignore malformed manifests to avoid
            //
            // TODO: Add a way to exclude folders?
            info!("skipping malformed package found at `{}`",
                  path.to_string_lossy());
            return Ok(());
        }
        Ok(tuple) => tuple
    };

    let manifest = match manifest {
        EitherManifest::Real(manifest) => manifest,
        EitherManifest::Virtual(..) => return Ok(()),
    };
    let pkg = Package::new(manifest, &manifest_path);

    let pkg_id = pkg.package_id().clone();
    if !all_packages.contains_key(&pkg_id) {
        all_packages.insert(pkg_id, pkg);
    } else {
        info!("skipping nested package `{}` found at `{}`",
              pkg.name(), path.to_string_lossy());
    }

    // Registry sources are not allowed to have `path=` dependencies because
    // they're all translated to actual registry dependencies.
    //
    // We normalize the path here ensure that we don't infinitely walk around
    // looking for crates. By normalizing we ensure that we visit this crate at
    // most once.
    //
    // TODO: filesystem/symlink implications?
    if !source_id.is_registry() {
        for p in nested.iter() {
            let path = util::normalize_path(&path.join(p));
            read_nested_packages(&path, all_packages, source_id,
                                      config, visited)?;
        }
    }

    Ok(())
}
<|endoftext|>


<commit_before>use super::TyCtxt;

use super::super::core::*;
use super::name_generator::*;

/// A context with the needed state to deal with operations that process an inductive definition.
pub struct RecursorCx<'i, 'tcx> {
    ty_cx: &'tcx mut TyCtxt,
    inductive_ty: &'i Data,
    ind_hyp: Name,
}

impl<'i, 'tcx> RecursorCx<'i, 'tcx> {
    fn new(ty_cx: &'tcx mut TyCtxt, inductive_ty: &'i Data) -> RecursorCx<'i, 'tcx> {

        let mut rcx = RecursorCx {
            ty_cx: ty_cx,
            inductive_ty: inductive_ty,
            ind_hyp: inductive_ty.name.clone(),
        };

        let ty = rcx.eta_expand();

        let ty = rcx.with_params(ty);
        let ind_hyp = rcx.ty_cx.local_with_repr("C".to_string(),
            Term::abstract_pi(vec![rcx.ty_cx.local_with_repr("".to_string(), ty)],
                Term::Type));

        rcx.ind_hyp = ind_hyp;

        rcx
    }

    fn eta_expand(&self) -> Term {
        let mut pi = self.inductive_ty.ty.clone();
        let mut result = self.inductive_ty.name.to_term();
        let mut i = 0;
        let mut locals = vec![];
        while let Term::Forall { ty, term, .. } = pi {
            let local = self.ty_cx.local_with_repr(format!("x{}", 0), *ty);
            locals.push(local);
            pi = *term;
        }
        Term::abstract_lambda(
            locals.clone(),
            Term::apply_all(result, locals.into_iter().map(|t| t.to_term()).collect()))
    }

    pub fn with_params(&self, term: Term) -> Term {
        let params = self.inductive_ty
                         .parameters
                         .iter()
                         .map(|x| x.to_term())
                         .collect();

        Term::apply_all(term, params).whnf()
    }

    fn is_recursive_arg(&self, term: &Term) -> bool {
        match term.head() {
            None => false,
            Some(h) => h == self.inductive_ty.name.to_term(),
        }
    }

    pub fn minor_premise_for(&mut self, ind_hyp: &Name, ctor: &(Name, Term)) -> Term {
        // Apply the constructor name to the parameters.
        let ctor_with_params =
            self.with_params(ctor.0.to_term());

        // Apply the constructor type to the parameters.
        let mut ctor_ty_with_params =
            self.with_params(ctor.1.clone());

        let mut i = 0;
        let mut binders = Vec::new();
        let mut arguments = Vec::new();
        let mut pi = &ctor_ty_with_params;

        while let &Term::Forall { ref ty, ref term, .. } = pi {
            // Create a local with a fresh name and type of the binder.
            let arg_local =
                self.ty_cx.local_with_repr(
                    format!("a{}", i),
                    *ty.clone());

            // Add this to the list of binders (a0 : A) (a1 : List A)
            binders.push(arg_local.clone());
            // (a0 : A) (a1 : List A) -> C a1 -> C (Cons a0 a1)

            // If this is a recursive argument we all need to generate a piece of proof
            // for that case for example `C a1`.
            if self.is_recursive_arg(&*ty) {
                let local_x =
                    self.ty_cx.local_with_repr(
                        "".to_string(),
                        Term::apply(ind_hyp.to_term(), arg_local.to_term()));

                 arguments.push(local_x);
            }

            pi = &**term;
            i += 1;
        }

        let c_for_ctor = Term::apply(
            ind_hyp.to_term(),
            Term::apply_all(
                ctor_with_params,
                binders.iter()
                       .map(|x| x.to_term())
                       .collect()));

        Term::abstract_pi(
            binders,
            Term::abstract_pi(
                arguments,
                c_for_ctor))
    }

    pub fn construct_recursor(&self,
                              minor_premises: Vec<Name>,
                              major_premise_args: Vec<Name>,
                              major_premise: Term) -> (Term, Term) {
        let ind_hyp = self.ind_hyp.clone();
        let params =
            self.inductive_ty
                .parameters
                .clone();

        let recursor_ty =
            Term::abstract_pi(
                params.clone(),
                Term::abstract_pi(vec![ind_hyp.clone()],
                    Term::abstract_pi(minor_premises.clone(),
                        Term::abstract_pi(major_premise_args.clone(),
                            major_premise))));

        let mut recursor_terms = vec![ind_hyp.clone().to_term()];
        recursor_terms.extend(minor_premises.iter().map(|x| x.to_term()));
        recursor_terms.extend(major_premise_args.iter().map(|x| x.to_term()));

        let recursor_body =
            Term::abstract_lambda(
                params.clone(),
                Term::abstract_lambda(
                    vec![ind_hyp.clone()],
                    Term::abstract_lambda(
                        minor_premises,
                        Term::abstract_lambda(
                            major_premise_args,
                            Term::Recursor(
                                self.inductive_ty.name.clone(),
                                1, // this needs to be fixed
                                recursor_terms)))));

        (recursor_ty, recursor_body)
    }

    pub fn major_premise(&self) -> (Vec<Name>, Term) {
        let mut data_type_ty = self.with_params(
            self.inductive_ty.ty.clone());

        let mut arguments = Vec::new();
        while let Term::Forall { ty, term, .. } = data_type_ty {
            arguments.push(*ty.clone());
            data_type_ty = *term;
        }

        let mut arguments: Vec<_> = arguments.into_iter()
                                         .enumerate()
                                         .map(|(i, ty)|
                                            self.ty_cx.local_with_repr(format!("a{}", i), ty))
                                         .collect();
        let scrutinee =
            Term::apply_all(
                self.with_params(self.inductive_ty.name.to_term()),
                arguments.iter().map(|x| x.to_term()).collect());

        arguments.push(self.ty_cx.local_with_repr(
            "c".to_string(),
            scrutinee));

        let premise =
            self.ind_hyp.to_term();

        let premise = Term::apply_all(
            premise,
            arguments.
            iter().
            map(|a| a.to_term()).
            collect());

        (arguments, premise)
    }
}

/// Construct a recursor for `data_type`.
pub fn make_recursor(ty_cx: &mut TyCtxt, data_type: &Data) {
    let mut rcx = RecursorCx::new(ty_cx, data_type);

    let ind_hyp = rcx.ind_hyp.clone();

    let params = data_type.parameters.clone();

    let minor_premises =
        data_type.ctors
                 .iter()
                 .map(|ctor| {
                     let p = rcx.minor_premise_for(&ind_hyp, ctor);
                     rcx.ty_cx.local_with_repr("".to_string(), p)
                 })
                 .collect();

    let (tys, major_premise) =
        rcx.major_premise();

    let (recursor_ty, recursor_body) =
        rcx.construct_recursor(
            minor_premises,
            tys,
            major_premise);

    let recursor_name = data_type.name.in_scope("rec".to_string()).unwrap();

    rcx.ty_cx
       .definitions
       .insert(recursor_name, (recursor_ty, recursor_body));
}
<commit_msg>Recursors work for data types with parameters<commit_after>use super::TyCtxt;

use super::super::core::*;
use super::name_generator::*;

/// A context with the needed state to deal with operations that process an inductive definition.
pub struct RecursorCx<'i, 'tcx> {
    ty_cx: &'tcx mut TyCtxt,
    inductive_ty: &'i Data,
    ind_hyp: Name,
}

impl<'i, 'tcx> RecursorCx<'i, 'tcx> {
    fn new(ty_cx: &'tcx mut TyCtxt, inductive_ty: &'i Data) -> RecursorCx<'i, 'tcx> {

        let mut rcx = RecursorCx {
            ty_cx: ty_cx,
            inductive_ty: inductive_ty,
            ind_hyp: inductive_ty.name.clone(),
        };

        let ty = rcx.make_ind_hyp_ty();

        let ty = rcx.with_params(ty);
        let ind_hyp = rcx.ty_cx.local_with_repr("C".to_string(),
            Term::abstract_pi(vec![rcx.ty_cx.local_with_repr("".to_string(), ty)],
                Term::Type));

        rcx.ind_hyp = ind_hyp;

        rcx
    }

    fn  make_ind_hyp_ty(&self) -> Term {
        let mut pi = self.inductive_ty.ty.clone();
        let mut result = self.inductive_ty.name.to_term();
        let mut i = 0;
        let mut locals = vec![];
        while let Term::Forall { ty, term, .. } = pi {
            let local = self.ty_cx.local_with_repr(format!("x{}", 0), *ty);
            locals.push(local);
            pi = *term;
        }

        let applied_ty =
            Term::apply_all(
                result,
                locals.into_iter().map(|t| t.to_term()).collect());

        locals.push(
            self.ty_cx.local_with_repr("".to_string(), applied_ty));

        Term::abstract_pi(
            locals.clone(),
            Term::Type)
    }

    pub fn with_params(&self, term: Term) -> Term {
        let params = self.inductive_ty
                         .parameters
                         .iter()
                         .map(|x| x.to_term())
                         .collect();

        Term::apply_all(term, params).whnf()
    }

    fn is_recursive_arg(&self, term: &Term) -> bool {
        match term.head() {
            None => false,
            Some(h) => h == self.inductive_ty.name.to_term(),
        }
    }

    pub fn minor_premise_for(&mut self, ind_hyp: &Name, ctor: &(Name, Term)) -> Term {
        // Apply the constructor name to the parameters.
        let ctor_with_params =
            self.with_params(ctor.0.to_term());

        // Apply the constructor type to the parameters.
        let mut ctor_ty_with_params =
            self.with_params(ctor.1.clone());

        let mut i = 0;
        let mut binders = Vec::new();
        let mut arguments = Vec::new();
        let mut pi = &ctor_ty_with_params;

        while let &Term::Forall { ref ty, ref term, .. } = pi {
            // Create a local with a fresh name and type of the binder.
            let arg_local =
                self.ty_cx.local_with_repr(
                    format!("a{}", i),
                    *ty.clone());

            // Add this to the list of binders (a0 : A) (a1 : List A)
            binders.push(arg_local.clone());
            // (a0 : A) (a1 : List A) -> C a1 -> C (Cons a0 a1)

            // If this is a recursive argument we all need to generate a piece of proof
            // for that case for example `C a1`.
            if self.is_recursive_arg(&*ty) {
                let local_x =
                    self.ty_cx.local_with_repr(
                        "".to_string(),
                        Term::apply(ind_hyp.to_term(), arg_local.to_term()));

                 arguments.push(local_x);
            }

            pi = &**term;
            i += 1;
        }

        let c_for_ctor = Term::apply(
            ind_hyp.to_term(),
            Term::apply_all(
                ctor_with_params,
                binders.iter()
                       .map(|x| x.to_term())
                       .collect()));

        Term::abstract_pi(
            binders,
            Term::abstract_pi(
                arguments,
                c_for_ctor))
    }

    pub fn construct_recursor(&self,
                              minor_premises: Vec<Name>,
                              major_premise_args: Vec<Name>,
                              major_premise: Term) -> (Term, Term) {
        let ind_hyp = self.ind_hyp.clone();
        let params =
            self.inductive_ty
                .parameters
                .clone();

        let recursor_ty =
            Term::abstract_pi(
                params.clone(),
                Term::abstract_pi(vec![ind_hyp.clone()],
                    Term::abstract_pi(minor_premises.clone(),
                        Term::abstract_pi(major_premise_args.clone(),
                            major_premise))));

        let mut recursor_terms = vec![ind_hyp.clone().to_term()];
        recursor_terms.extend(minor_premises.iter().map(|x| x.to_term()));
        recursor_terms.extend(major_premise_args.iter().map(|x| x.to_term()));

        let recursor_body =
            Term::abstract_lambda(
                params.clone(),
                Term::abstract_lambda(
                    vec![ind_hyp.clone()],
                    Term::abstract_lambda(
                        minor_premises,
                        Term::abstract_lambda(
                            major_premise_args,
                            Term::Recursor(
                                self.inductive_ty.name.clone(),
                                1, // this needs to be fixed
                                recursor_terms)))));

        (recursor_ty, recursor_body)
    }

    pub fn major_premise(&self) -> (Vec<Name>, Term) {
        let mut data_type_ty = self.with_params(
            self.inductive_ty.ty.clone());

        let mut arguments = Vec::new();
        while let Term::Forall { ty, term, .. } = data_type_ty {
            arguments.push(*ty.clone());
            data_type_ty = *term;
        }

        let mut arguments: Vec<_> = arguments.into_iter()
                                         .enumerate()
                                         .map(|(i, ty)|
                                            self.ty_cx.local_with_repr(format!("a{}", i), ty))
                                         .collect();
        let scrutinee =
            Term::apply_all(
                self.with_params(self.inductive_ty.name.to_term()),
                arguments.iter().map(|x| x.to_term()).collect());

        arguments.push(self.ty_cx.local_with_repr(
            "c".to_string(),
            scrutinee));

        let premise =
            self.ind_hyp.to_term();

        let premise = Term::apply_all(
            premise,
            arguments.
            iter().
            map(|a| a.to_term()).
            collect());

        (arguments, premise)
    }
}

/// Construct a recursor for `data_type`.
pub fn make_recursor(ty_cx: &mut TyCtxt, data_type: &Data) {
    let mut rcx = RecursorCx::new(ty_cx, data_type);

    let ind_hyp = rcx.ind_hyp.clone();

    let params = data_type.parameters.clone();

    let minor_premises =
        data_type.ctors
                 .iter()
                 .map(|ctor| {
                     let p = rcx.minor_premise_for(&ind_hyp, ctor);
                     rcx.ty_cx.local_with_repr("".to_string(), p)
                 })
                 .collect();

    let (tys, major_premise) =
        rcx.major_premise();

    let (recursor_ty, recursor_body) =
        rcx.construct_recursor(
            minor_premises,
            tys,
            major_premise);

    let recursor_name = data_type.name.in_scope("rec".to_string()).unwrap();

    rcx.ty_cx
       .definitions
       .insert(recursor_name, (recursor_ty, recursor_body));
}
<|endoftext|>


<commit_before>// (C)opyleft 2013-2017 Frank Denis

//! Bloom filter for Rust
//!
//! This is a simple but fast Bloom filter implementation, that requires only
//! 2 hash functions, generated with SipHash-1-3 using randomized keys.
//!

#![crate_name="bloomfilter"]
#![crate_type = "rlib"]
#![warn(non_camel_case_types, non_upper_case_globals, unused_qualifications)]

extern crate bit_vec;
extern crate rand;
extern crate siphasher;

use bit_vec::BitVec;
use siphasher::sip::SipHasher13;
use std::cmp;
use std::f64;
use std::hash::{Hash, Hasher};

#[cfg(test)]
use rand::Rng;

/// Bloom filter structure
pub struct Bloom {
    bitmap: BitVec,
    bitmap_bits: u64,
    k_num: u32,
    sips: [SipHasher13; 2],
}

impl Bloom {
    /// Create a new bloom filter structure.
    /// bitmap_size is the size in bytes (not bits) that will be allocated in memory
    /// items_count is an estimation of the maximum number of items to store.
    pub fn new(bitmap_size: usize, items_count: usize) -> Bloom {
        assert!(bitmap_size > 0 && items_count > 0);
        let bitmap_bits = (bitmap_size as u64) * 8u64;
        let k_num = Bloom::optimal_k_num(bitmap_bits, items_count);
        let bitmap = BitVec::from_elem(bitmap_bits as usize, false);
        let sips = [Bloom::sip_new(), Bloom::sip_new()];
        Bloom {
            bitmap: bitmap,
            bitmap_bits: bitmap_bits,
            k_num: k_num,
            sips: sips,
        }
    }

    /// Create a new bloom filter structure.
    /// items_count is an estimation of the maximum number of items to store.
    /// fp_p is the wanted rate of false positives, in ]0.0, 1.0[
    pub fn new_for_fp_rate(items_count: usize, fp_p: f64) -> Bloom {
        let bitmap_size = Bloom::compute_bitmap_size(items_count, fp_p);
        Bloom::new(bitmap_size, items_count)
    }

    /// Compute a recommended bitmap size for items_count items
    /// and a fp_p rate of false positives.
    /// fp_p obviously has to be within the ]0.0, 1.0[ range.
    pub fn compute_bitmap_size(items_count: usize, fp_p: f64) -> usize {
        assert!(items_count > 0);
        assert!(fp_p > 0.0 && fp_p < 1.0);
        let log2 = f64::consts::LN_2;
        let log2_2 = log2 * log2;
        ((items_count as f64) * f64::ln(fp_p) / (-8.0 * log2_2)).ceil() as usize
    }

    /// Record the presence of an item.
    pub fn set<T>(&mut self, item: T)
        where T: Hash
    {
        let mut hashes = [0u64, 0u64];
        for k_i in 0..self.k_num {
            let bit_offset = (self.bloom_hash(&mut hashes, &item, k_i) % self.bitmap_bits) as usize;
            self.bitmap.set(bit_offset, true);
        }
    }

    /// Check if an item is present in the set.
    /// There can be false positives, but no false negatives.
    pub fn check<T>(&self, item: T) -> bool
        where T: Hash
    {
        let mut hashes = [0u64, 0u64];
        for k_i in 0..self.k_num {
            let bit_offset = (self.bloom_hash(&mut hashes, &item, k_i) % self.bitmap_bits) as usize;
            if self.bitmap.get(bit_offset).unwrap() == false {
                return false;
            }
        }
        true
    }

    /// Record the presence of an item in the set,
    /// and return the previous state of this item.
    pub fn check_and_set<T>(&mut self, item: T) -> bool
        where T: Hash
    {
        let mut hashes = [0u64, 0u64];
        let mut found = true;
        for k_i in 0..self.k_num {
            let bit_offset = (self.bloom_hash(&mut hashes, &item, k_i) % self.bitmap_bits) as usize;
            if self.bitmap.get(bit_offset).unwrap() == false {
                found = false;
                self.bitmap.set(bit_offset, true);
            }
        }
        found
    }

    /// Return the number of bits in the filter
    pub fn number_of_bits(&self) -> u64 {
        self.bitmap_bits
    }

    /// Return the number of hash functions used for `check` and `set`
    pub fn number_of_hash_functions(&self) -> u32 {
        self.k_num
    }

    fn optimal_k_num(bitmap_bits: u64, items_count: usize) -> u32 {
        let m = bitmap_bits as f64;
        let n = items_count as f64;
        let k_num = (m / n * f64::ln(2.0f64)).ceil() as u32;
        cmp::max(k_num, 1)
    }

    fn bloom_hash<T>(&self, hashes: &mut [u64; 2], item: &T, k_i: u32) -> u64
        where T: Hash
    {
        if k_i < 2 {
            let sip = &mut self.sips[k_i as usize].clone();
            item.hash(sip);
            let hash = sip.finish();
            hashes[k_i as usize] = hash;
            hash
        } else {
            hashes[0].wrapping_add((k_i as u64).wrapping_mul(hashes[1]) % 0xffffffffffffffc5)
        }
    }

    /// Clear all of the bits in the filter, removing all keys from the set
    pub fn clear(&mut self) {
        self.bitmap.clear()
    }

    fn sip_new() -> SipHasher13 {
        let mut rng = rand::thread_rng();
        SipHasher13::new_with_keys(rand::Rand::rand(&mut rng), rand::Rand::rand(&mut rng))
    }
}

#[test]
fn bloom_test_set() {
    let mut bloom = Bloom::new(10, 80);
    let key: &Vec<u8> = &rand::thread_rng().gen_iter::<u8>().take(16).collect();
    assert!(bloom.check(key) == false);
    bloom.set(&key);
    assert!(bloom.check(key.clone()) == true);
}

#[test]
fn bloom_test_check_and_set() {
    let mut bloom = Bloom::new(10, 80);
    let key: &Vec<u8> = &rand::thread_rng().gen_iter::<u8>().take(16).collect();
    assert!(bloom.check_and_set(key) == false);
    assert!(bloom.check_and_set(key.clone()) == true);
}

#[test]
fn bloom_test_clear() {
    let mut bloom = Bloom::new(10, 80);
    let key: &Vec<u8> = &rand::thread_rng().gen_iter::<u8>().take(16).collect();
    bloom.set(&key);
    assert!(bloom.check(&key) == true);
    bloom.clear();
    assert!(bloom.check(&key) == false);
}
<commit_msg>Follow the new style guidelines<commit_after>// (C)opyleft 2013-2017 Frank Denis

//! Bloom filter for Rust
//!
//! This is a simple but fast Bloom filter implementation, that requires only
//! 2 hash functions, generated with SipHash-1-3 using randomized keys.
//!

#![crate_name="bloomfilter"]
#![crate_type = "rlib"]
#![warn(non_camel_case_types, non_upper_case_globals, unused_qualifications)]

extern crate bit_vec;
extern crate rand;
extern crate siphasher;

use bit_vec::BitVec;
use siphasher::sip::SipHasher13;
use std::cmp;
use std::f64;
use std::hash::{Hash, Hasher};

#[cfg(test)]
use rand::Rng;

/// Bloom filter structure
pub struct Bloom {
    bitmap: BitVec,
    bitmap_bits: u64,
    k_num: u32,
    sips: [SipHasher13; 2],
}

impl Bloom {
    /// Create a new bloom filter structure.
    /// bitmap_size is the size in bytes (not bits) that will be allocated in memory
    /// items_count is an estimation of the maximum number of items to store.
    pub fn new(bitmap_size: usize, items_count: usize) -> Bloom {
        assert!(bitmap_size > 0 && items_count > 0);
        let bitmap_bits = (bitmap_size as u64) * 8u64;
        let k_num = Bloom::optimal_k_num(bitmap_bits, items_count);
        let bitmap = BitVec::from_elem(bitmap_bits as usize, false);
        let sips = [Bloom::sip_new(), Bloom::sip_new()];
        Bloom {
            bitmap: bitmap,
            bitmap_bits: bitmap_bits,
            k_num: k_num,
            sips: sips,
        }
    }

    /// Create a new bloom filter structure.
    /// items_count is an estimation of the maximum number of items to store.
    /// fp_p is the wanted rate of false positives, in ]0.0, 1.0[
    pub fn new_for_fp_rate(items_count: usize, fp_p: f64) -> Bloom {
        let bitmap_size = Bloom::compute_bitmap_size(items_count, fp_p);
        Bloom::new(bitmap_size, items_count)
    }

    /// Compute a recommended bitmap size for items_count items
    /// and a fp_p rate of false positives.
    /// fp_p obviously has to be within the ]0.0, 1.0[ range.
    pub fn compute_bitmap_size(items_count: usize, fp_p: f64) -> usize {
        assert!(items_count > 0);
        assert!(fp_p > 0.0 && fp_p < 1.0);
        let log2 = f64::consts::LN_2;
        let log2_2 = log2 * log2;
        ((items_count as f64) * f64::ln(fp_p) / (-8.0 * log2_2)).ceil() as usize
    }

    /// Record the presence of an item.
    pub fn set<T>(&mut self, item: T)
    where
        T: Hash,
    {
        let mut hashes = [0u64, 0u64];
        for k_i in 0..self.k_num {
            let bit_offset = (self.bloom_hash(&mut hashes, &item, k_i) % self.bitmap_bits) as usize;
            self.bitmap.set(bit_offset, true);
        }
    }

    /// Check if an item is present in the set.
    /// There can be false positives, but no false negatives.
    pub fn check<T>(&self, item: T) -> bool
    where
        T: Hash,
    {
        let mut hashes = [0u64, 0u64];
        for k_i in 0..self.k_num {
            let bit_offset = (self.bloom_hash(&mut hashes, &item, k_i) % self.bitmap_bits) as usize;
            if self.bitmap.get(bit_offset).unwrap() == false {
                return false;
            }
        }
        true
    }

    /// Record the presence of an item in the set,
    /// and return the previous state of this item.
    pub fn check_and_set<T>(&mut self, item: T) -> bool
    where
        T: Hash,
    {
        let mut hashes = [0u64, 0u64];
        let mut found = true;
        for k_i in 0..self.k_num {
            let bit_offset = (self.bloom_hash(&mut hashes, &item, k_i) % self.bitmap_bits) as usize;
            if self.bitmap.get(bit_offset).unwrap() == false {
                found = false;
                self.bitmap.set(bit_offset, true);
            }
        }
        found
    }

    /// Return the number of bits in the filter
    pub fn number_of_bits(&self) -> u64 {
        self.bitmap_bits
    }

    /// Return the number of hash functions used for `check` and `set`
    pub fn number_of_hash_functions(&self) -> u32 {
        self.k_num
    }

    fn optimal_k_num(bitmap_bits: u64, items_count: usize) -> u32 {
        let m = bitmap_bits as f64;
        let n = items_count as f64;
        let k_num = (m / n * f64::ln(2.0f64)).ceil() as u32;
        cmp::max(k_num, 1)
    }

    fn bloom_hash<T>(&self, hashes: &mut [u64; 2], item: &T, k_i: u32) -> u64
    where
        T: Hash,
    {
        if k_i < 2 {
            let sip = &mut self.sips[k_i as usize].clone();
            item.hash(sip);
            let hash = sip.finish();
            hashes[k_i as usize] = hash;
            hash
        } else {
            hashes[0].wrapping_add((k_i as u64).wrapping_mul(hashes[1]) % 0xffffffffffffffc5)
        }
    }

    /// Clear all of the bits in the filter, removing all keys from the set
    pub fn clear(&mut self) {
        self.bitmap.clear()
    }

    fn sip_new() -> SipHasher13 {
        let mut rng = rand::thread_rng();
        SipHasher13::new_with_keys(rand::Rand::rand(&mut rng), rand::Rand::rand(&mut rng))
    }
}

#[test]
fn bloom_test_set() {
    let mut bloom = Bloom::new(10, 80);
    let key: &Vec<u8> = &rand::thread_rng().gen_iter::<u8>().take(16).collect();
    assert!(bloom.check(key) == false);
    bloom.set(&key);
    assert!(bloom.check(key.clone()) == true);
}

#[test]
fn bloom_test_check_and_set() {
    let mut bloom = Bloom::new(10, 80);
    let key: &Vec<u8> = &rand::thread_rng().gen_iter::<u8>().take(16).collect();
    assert!(bloom.check_and_set(key) == false);
    assert!(bloom.check_and_set(key.clone()) == true);
}

#[test]
fn bloom_test_clear() {
    let mut bloom = Bloom::new(10, 80);
    let key: &Vec<u8> = &rand::thread_rng().gen_iter::<u8>().take(16).collect();
    bloom.set(&key);
    assert!(bloom.check(&key) == true);
    bloom.clear();
    assert!(bloom.check(&key) == false);
}
<|endoftext|>