<commit_before>#![allow(unused)]

use interpreter::ast::*;
use interpreter::tokenizer::*;

use std::collections::HashMap;

pub type Memory = HashMap<Ident, Expr>;

impl Expr {
    fn run(&self, memory: &mut Memory) -> Result<Expr, String> {
        match self.node {
            Node::Ident(ref id) => {
                memory
                    .get(id)
                    .ok_or_else(|| {
                        self.debug.to_string() + ", but " + &id.0 + " has not been defined yet."
                    })
                    .map(|val| val.clone())
            }
            Node::Op(ref operator) => operator.run(memory),
            Node::Function(ref function) => function.run(memory, Vec::new()),
            _ => Ok(self.clone()),
        }
    }
}

/// avoids needlessly cloning an Expr if it is already resolved to
/// a primitive value. unfortunately, this requires passing in an
/// external storage variable for this case where the value has not
/// yet been resolved to a primitive, for lifetime reasons.
macro_rules! resolve {
    ($exp:ident, $memory:ident, $store:ident) => (
        match $exp.node {
            Node::Int(_) => $exp,
            Node::Float(_) => $exp,
            Node::Str(_) => $exp,
            Node::Bool(_) => $exp,
            _ => {$store = $exp.run($memory)?; &$store}
        }
    )
}

macro_rules! do_binary_op {
    ($op:tt, $memory:ident, $left:ident, $right:ident, $(($typeA:tt, $typeB:tt -> ($asType:tt:$asTypePrim:tt))),*; $(($typeA2:tt, $typeB2:tt -> ($asType2:tt))),*; _ => $defaultCase:expr) => ({
        let store1;
        let store2;
        let left_res = resolve!($left, $memory, store1);
        let right_res = resolve!($right, $memory, store2);
        match (&left_res.node, &right_res.node) {
            $(
                (&Node::$typeA(val1), &Node::$typeB(val2)) => {
                    Ok(Expr::new(Node::$asType((val1 as $asTypePrim) $op (val2 as $asTypePrim)), DebugInfo::none()))
                },
            )*
            $(
                (&Node::$typeA2(ref val1), &Node::$typeB2(ref val2)) => {
                    Ok(Expr::new(Node::$asType2(val1 $op val2), DebugInfo::none()))
                },
            )*
            _ => $defaultCase,
        }
    })
}

impl Operator {
    fn run(&self, memory: &mut Memory) -> Result<Expr, String> {
        match *self {
            Operator::Assign(ref id, ref expr) => {
                let val = expr.run(memory)?;
                memory.insert(id.clone(), val);
                Ok(Expr::new(Node::Noop, expr.debug.clone()))
            }

            Operator::Call(ref id, ref args) => unimplemented!(),

            Operator::Add(ref left, ref right) => {
                do_binary_op!(+, memory, left, right, (Int, Int -> (Int:i64)), (Float, Float -> (Float:f64)), (Float, Int -> (Float:f64)), (Int, Float -> (Float:f64));; _ => unimplemented!())
            }
            Operator::Sub(ref left, ref right) => {
                do_binary_op!(-, memory, left, right, (Int, Int -> (Int:i64)), (Float, Float -> (Float:f64)), (Float, Int -> (Float:f64)), (Int, Float -> (Float:f64));; _ => unimplemented!())
            }
            Operator::Mul(ref left, ref right) => {
                do_binary_op!(*, memory, left, right, (Int, Int -> (Int:i64)), (Float, Float -> (Float:f64)), (Float, Int -> (Float:f64)), (Int, Float -> (Float:f64));; _ => unimplemented!())
            }
            Operator::Div(ref left, ref right) => {
                do_binary_op!(/, memory, left, right, (Int, Int -> (Int:i64)), (Float, Float -> (Float:f64)), (Float, Int -> (Float:f64)), (Int, Float -> (Float:f64));; _ => unimplemented!())
            }
            Operator::Mod(ref left, ref right) => {
                do_binary_op!(%, memory, left, right, (Int, Int -> (Int:i64));; _ => unimplemented!())
            }
            Operator::And(ref left, ref right) => {
                do_binary_op!(&&, memory, left, right, (Bool, Bool -> (Bool:bool));; _ => Err(
                            left.debug.to_string() + &right.debug.to_string() +
                            ", attempt to use logical AND on something which is not a boolean")?)
            }
            Operator::Or(ref left, ref right) => {
                do_binary_op!(||, memory, left, right, (Bool, Bool -> (Bool:bool));; _ => Err(
                            left.debug.to_string() + &right.debug.to_string() +
                            ", attempt to use logical OR on something which is not a boolean")?)
            }
            Operator::Less(ref left, ref right) => {
                do_binary_op!(<, memory, left, right, (Int, Int -> (Bool:i64)), (Float, Float -> (Bool:f64)), (Float, Int -> (Bool:f64)), (Int, Float -> (Bool:f64)); (Str, Str -> (Bool)); _ => Err(
                            left.debug.to_string() + &right.debug.to_string() +
                            ", attempt to compare two values for equality which cannot be compared")?)
            }
            Operator::LessOrEquals(ref left, ref right) => {
                do_binary_op!(<=, memory, left, right, (Int, Int -> (Bool:i64)), (Float, Float -> (Bool:f64)), (Float, Int -> (Bool:f64)), (Int, Float -> (Bool:f64)); (Str, Str -> (Bool)); _ => Err(
                            left.debug.to_string() + &right.debug.to_string() +
                            ", attempt to compare two values for equality which cannot be compared")?)
            }
            Operator::Greater(ref left, ref right) => {
                do_binary_op!(>, memory, left, right, (Int, Int -> (Bool:i64)), (Float, Float -> (Bool:f64)), (Float, Int -> (Bool:f64)), (Int, Float -> (Bool:f64)); (Str, Str -> (Bool)); _ => Err(
                            left.debug.to_string() + &right.debug.to_string() +
                            ", attempt to compare two values for equality which cannot be compared")?)
            }
            Operator::GreaterOrEquals(ref left, ref right) => {
                do_binary_op!(>=, memory, left, right, (Int, Int -> (Bool:i64)), (Float, Float -> (Bool:f64)), (Float, Int -> (Bool:f64)), (Int, Float -> (Bool:f64)); (Str, Str -> (Bool)); _ => Err(
                            left.debug.to_string() + &right.debug.to_string() +
                            ", attempt to compare two values for equality which cannot be compared")?)
            }
            Operator::Equals(ref left, ref right) => {
                do_binary_op!(==, memory, left, right,; (Int, Int -> (Bool)), (Float, Float -> (Bool)), (Str, Str -> (Bool)), (Bool, Bool -> (Bool)); _ => Err(
                            left.debug.to_string() + &right.debug.to_string() +
                            ", attempt to compare two values for equality which cannot be compared")?)
            }
            Operator::NotEquals(ref left, ref right) => {
                do_binary_op!(!=, memory, left, right,; (Int, Int -> (Bool)), (Float, Float -> (Bool)), (Str, Str -> (Bool)), (Bool, Bool -> (Bool)); _ => Err(
                            left.debug.to_string() + &right.debug.to_string() +
                            ", attempt to compare two values for equality which cannot be compared")?)
            }

            Operator::Negate(ref expr) => {
                let store;
                let expr_res = resolve!(expr, memory, store);
                match &expr_res.node {
                    &Node::Int(val) => Ok(Expr::new(Node::Int(-val), DebugInfo::none())),
                    &Node::Float(val) => Ok(Expr::new(Node::Float(-val), DebugInfo::none())),
                    _ => {
                        Err(
                            expr.debug.to_string() +
                                ", attempt to negate something which is not a number",
                        )?
                    }
                }
            }

            Operator::Not(ref expr) => {
                let store;
                let expr_res = resolve!(expr, memory, store);
                match &expr_res.node {
                    &Node::Bool(val) => Ok(Expr::new(Node::Bool(!val), DebugInfo::none())),
                    _ => {
                        Err(
                            expr.debug.to_string() +
                                ", attempt to use logical NOT on something which is not a boolean",
                        )?
                    }
                }
            }
        }
    }
}

/// get the list of visible identifiers at this scope level
fn get_scope(memory: &mut Memory) -> Vec<Ident> {
    memory.keys().cloned().collect()
}

/// remove any identifiers that were created during the scoped region
fn revert_scope(scope: Vec<Ident>, memory: &mut Memory) {
    memory.retain(|ident, _| scope.contains(ident));
}

fn revert_scope_after<T>(val: T, scope: Vec<Ident>, memory: &mut Memory) -> T {
    revert_scope(scope, memory);
    val
}

impl Function {
    fn run(&self, memory: &mut Memory, args: Vec<Expr>) -> Result<Expr, String> {
        if self.args.len() != args.len() {
            return Err(format!(
                "Function {} called with incorrect number of arguments. Expected {} but found {}.",
                self.name,
                self.args.len(),
                args.len()
            ))?;
        }
        let scope = get_scope(memory);
        for (id, val) in self.args.iter().zip(args) {
            memory.insert(id.clone(), val);
        }
        for mut expr in &self.body {
            match expr.node {
                Node::Return(_) => return revert_scope_after(expr.run(memory), scope, memory),
                _ => expr.run(memory)?,
            };
        }

        revert_scope(scope, memory);

        Ok(Expr::new(Node::Noop, DebugInfo::none()))
    }
}

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

    fn create_global(name: &str, memory: &mut Memory) {
        memory.insert(
            Ident(name.to_string()),
            Expr::new(Node::Noop, DebugInfo::none()),
        );
    }

    #[test]
    fn walk_assign() {
        let expr = Expr::parse("$someInt = 35").unwrap();
        let mut memory = &mut HashMap::new();

        // create $someInt outside the scope of the anonymous outer function that
        // Expr::parse returns, that way the effect of the assignment can be seen here.
        create_global("$someInt", memory);

        let result = expr.run(memory).unwrap();
        println!("{:#?}\n memory: {:#?}", result, memory);
    }

    #[test]
    fn walk_assign2() {
        let expr = Expr::parse("$otherInt = 35; $someInt = $otherInt + 2;").unwrap();
        let mut memory = &mut HashMap::new();

        // create $someInt outside the scope of the anonymous outer function that
        // Expr::parse returns, that way the effect of the assignment can be seen here.
        create_global("$someInt", memory);

        let result = expr.run(memory).unwrap();
        println!("{:#?}\n memory: {:#?}", result, memory);
    }

    #[test]
    #[should_panic]
    fn walk_assign_undefined() {
        let expr = Expr::parse("$someInt = 35; $otherInt = $someInt + $whatIsThis;").unwrap();
        let mut memory = &mut HashMap::new();
        let result = expr.run(memory).unwrap();
    }
}
<commit_msg>Make progress on the AST walker<commit_after>#![allow(unused)]

use interpreter::ast::*;
use interpreter::tokenizer::*;

use std::collections::HashMap;

pub type Memory = HashMap<Ident, Expr>;

impl Expr {
    fn run(&self, memory: &mut Memory) -> Result<Expr, String> {
        match self.node {
            Node::Ident(ref id) => {
                memory
                    .get(id)
                    .ok_or_else(|| {
                        self.debug.to_string() + ", but " + &id.0 + " has not been defined yet."
                    })
                    .map(|val| val.clone())
            }
            Node::Return(ref expr) => {
                let mut res = self.clone();
                res.node = Node::Return(Box::new(expr.run(memory)?));
                Ok(res)
            }
            Node::Op(ref operator) => operator.run(memory),
            Node::Function(ref function) => function.run(memory, Vec::new()),
            Node::If(ref if_stmt) => if_stmt.run(memory),
            Node::For(ref for_stmt) => for_stmt.run(memory),
            Node::While(ref while_stmt) => while_stmt.run(memory),
            _ => Ok(self.clone()),
        }
    }
}

/// avoids needlessly cloning an Expr if it is already resolved to
/// a primitive value. unfortunately, this requires passing in an
/// external storage variable for this case where the value has not
/// yet been resolved to a primitive, for lifetime reasons.
macro_rules! resolve {
    ($exp:ident, $memory:ident, $store:ident) => (
        match $exp.node {
            Node::Int(_) => $exp,
            Node::Float(_) => $exp,
            Node::Str(_) => $exp,
            Node::Bool(_) => $exp,
            _ => {$store = $exp.run($memory)?; &$store}
        }
    )
}

macro_rules! do_binary_op {
    ($op:tt, $memory:ident, $left:ident, $right:ident, $(($typeA:tt, $typeB:tt -> ($asType:tt:$asTypePrim:tt))),*; $(($typeA2:tt, $typeB2:tt -> ($asType2:tt))),*; _ => $defaultCase:expr) => ({
        let store1;
        let store2;
        let left_res = resolve!($left, $memory, store1);
        let right_res = resolve!($right, $memory, store2);
        match (&left_res.node, &right_res.node) {
            $(
                (&Node::$typeA(val1), &Node::$typeB(val2)) => {
                    Ok(Expr::new(Node::$asType((val1 as $asTypePrim) $op (val2 as $asTypePrim)), DebugInfo::none()))
                },
            )*
            $(
                (&Node::$typeA2(ref val1), &Node::$typeB2(ref val2)) => {
                    Ok(Expr::new(Node::$asType2(val1 $op val2), DebugInfo::none()))
                },
            )*
            _ => $defaultCase,
        }
    })
}

impl Operator {
    fn run(&self, memory: &mut Memory) -> Result<Expr, String> {
        match *self {
            Operator::Assign(ref id, ref expr) => {
                let val = expr.run(memory)?;
                memory.insert(id.clone(), val);
                Ok(Expr::new(Node::Noop, expr.debug.clone()))
            }

            Operator::Call(ref id, ref args) => unimplemented!(),

            Operator::Add(ref left, ref right) => {
                do_binary_op!(+, memory, left, right, (Int, Int -> (Int:i64)), (Float, Float -> (Float:f64)), (Float, Int -> (Float:f64)), (Int, Float -> (Float:f64));; _ => unimplemented!())
            }
            Operator::Sub(ref left, ref right) => {
                do_binary_op!(-, memory, left, right, (Int, Int -> (Int:i64)), (Float, Float -> (Float:f64)), (Float, Int -> (Float:f64)), (Int, Float -> (Float:f64));; _ => unimplemented!())
            }
            Operator::Mul(ref left, ref right) => {
                do_binary_op!(*, memory, left, right, (Int, Int -> (Int:i64)), (Float, Float -> (Float:f64)), (Float, Int -> (Float:f64)), (Int, Float -> (Float:f64));; _ => unimplemented!())
            }
            Operator::Div(ref left, ref right) => {
                do_binary_op!(/, memory, left, right, (Int, Int -> (Int:i64)), (Float, Float -> (Float:f64)), (Float, Int -> (Float:f64)), (Int, Float -> (Float:f64));; _ => unimplemented!())
            }
            Operator::Mod(ref left, ref right) => {
                do_binary_op!(%, memory, left, right, (Int, Int -> (Int:i64));; _ => unimplemented!())
            }
            Operator::And(ref left, ref right) => {
                do_binary_op!(&&, memory, left, right, (Bool, Bool -> (Bool:bool));; _ => Err(
                            left.debug.to_string() + &right.debug.to_string() +
                            ", attempt to use logical AND on something which is not a boolean")?)
            }
            Operator::Or(ref left, ref right) => {
                do_binary_op!(||, memory, left, right, (Bool, Bool -> (Bool:bool));; _ => Err(
                            left.debug.to_string() + &right.debug.to_string() +
                            ", attempt to use logical OR on something which is not a boolean")?)
            }
            Operator::Less(ref left, ref right) => {
                do_binary_op!(<, memory, left, right, (Int, Int -> (Bool:i64)), (Float, Float -> (Bool:f64)), (Float, Int -> (Bool:f64)), (Int, Float -> (Bool:f64)); (Str, Str -> (Bool)); _ => Err(
                            left.debug.to_string() + &right.debug.to_string() +
                            ", attempt to compare two values for equality which cannot be compared")?)
            }
            Operator::LessOrEquals(ref left, ref right) => {
                do_binary_op!(<=, memory, left, right, (Int, Int -> (Bool:i64)), (Float, Float -> (Bool:f64)), (Float, Int -> (Bool:f64)), (Int, Float -> (Bool:f64)); (Str, Str -> (Bool)); _ => Err(
                            left.debug.to_string() + &right.debug.to_string() +
                            ", attempt to compare two values for equality which cannot be compared")?)
            }
            Operator::Greater(ref left, ref right) => {
                do_binary_op!(>, memory, left, right, (Int, Int -> (Bool:i64)), (Float, Float -> (Bool:f64)), (Float, Int -> (Bool:f64)), (Int, Float -> (Bool:f64)); (Str, Str -> (Bool)); _ => Err(
                            left.debug.to_string() + &right.debug.to_string() +
                            ", attempt to compare two values for equality which cannot be compared")?)
            }
            Operator::GreaterOrEquals(ref left, ref right) => {
                do_binary_op!(>=, memory, left, right, (Int, Int -> (Bool:i64)), (Float, Float -> (Bool:f64)), (Float, Int -> (Bool:f64)), (Int, Float -> (Bool:f64)); (Str, Str -> (Bool)); _ => Err(
                            left.debug.to_string() + &right.debug.to_string() +
                            ", attempt to compare two values for equality which cannot be compared")?)
            }
            Operator::Equals(ref left, ref right) => {
                do_binary_op!(==, memory, left, right,; (Int, Int -> (Bool)), (Float, Float -> (Bool)), (Str, Str -> (Bool)), (Bool, Bool -> (Bool)); _ => Err(
                            left.debug.to_string() + &right.debug.to_string() +
                            ", attempt to compare two values for equality which cannot be compared")?)
            }
            Operator::NotEquals(ref left, ref right) => {
                do_binary_op!(!=, memory, left, right,; (Int, Int -> (Bool)), (Float, Float -> (Bool)), (Str, Str -> (Bool)), (Bool, Bool -> (Bool)); _ => Err(
                            left.debug.to_string() + &right.debug.to_string() +
                            ", attempt to compare two values for equality which cannot be compared")?)
            }

            Operator::Negate(ref expr) => {
                let store;
                let expr_res = resolve!(expr, memory, store);
                match &expr_res.node {
                    &Node::Int(val) => Ok(Expr::new(Node::Int(-val), DebugInfo::none())),
                    &Node::Float(val) => Ok(Expr::new(Node::Float(-val), DebugInfo::none())),
                    _ => {
                        Err(
                            expr.debug.to_string() +
                                ", attempt to negate something which is not a number",
                        )?
                    }
                }
            }

            Operator::Not(ref expr) => {
                let store;
                let expr_res = resolve!(expr, memory, store);
                match &expr_res.node {
                    &Node::Bool(val) => Ok(Expr::new(Node::Bool(!val), DebugInfo::none())),
                    _ => {
                        Err(
                            expr.debug.to_string() +
                                ", attempt to use logical NOT on something which is not a boolean",
                        )?
                    }
                }
            }
        }
    }
}

/// get the list of visible identifiers at this scope level
fn get_scope(memory: &mut Memory) -> Vec<Ident> {
    memory.keys().cloned().collect()
}

/// remove any identifiers that were created during the scoped region
fn revert_scope(scope: Vec<Ident>, memory: &mut Memory) {
    memory.retain(|ident, _| scope.contains(ident));
}

fn revert_scope_after<T>(val: T, scope: Vec<Ident>, memory: &mut Memory) -> T {
    revert_scope(scope, memory);
    val
}

fn run_exprs(exprs: &Vec<Expr>, memory: &mut Memory) -> Result<Expr, String> {
    for mut expr in exprs {
        match expr.node {
            Node::Return(_) => expr.run(memory)?,
            _ => expr.run(memory)?,
        };
    }
    Ok(Expr::new(Node::Noop, DebugInfo::none()))
}

impl Function {
    fn run(&self, memory: &mut Memory, args: Vec<Expr>) -> Result<Expr, String> {
        if self.args.len() != args.len() {
            return Err(format!(
                "Function {} called with incorrect number of arguments. Expected {} but found {}.",
                self.name,
                self.args.len(),
                args.len()
            ))?;
        }
        let scope = get_scope(memory);
        for (id, val) in self.args.iter().zip(args) {
            memory.insert(id.clone(), val);
        }
        for mut expr in &self.body {
            let expr = expr.run(memory)?;
            match expr.node {
                Node::Return(_) => return revert_scope_after(Ok(expr), scope, memory),
                _ => {}
            };
        }

        revert_scope(scope, memory);

        Ok(Expr::new(Node::Noop, DebugInfo::none()))
    }
}

impl If {
    fn run(&self, memory: &mut Memory) -> Result<Expr, String> {
        let conditional = self.condition.run(memory)?;
        let conditional = match conditional.node {
            Node::Bool(bool_val) => bool_val,
            _ => Err("")?,
        };

        if conditional {
            run_exprs(&self.true_body, memory)
        } else {
            run_exprs(&self.else_body, memory)
        }
    }
}

impl For {
    fn run(&self, memory: &mut Memory) -> Result<Expr, String> {
        unimplemented!();
    }
}

impl While {
    fn run(&self, memory: &mut Memory) -> Result<Expr, String> {
        unimplemented!();
    }
}

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

    fn create_global(name: &str, memory: &mut Memory) {
        memory.insert(
            Ident(name.to_string()),
            Expr::new(Node::Noop, DebugInfo::none()),
        );
    }

    #[test]
    fn walk_assign() {
        let expr = Expr::parse("$someInt = 35").unwrap();
        let mut memory = &mut HashMap::new();

        // create $someInt outside the scope of the anonymous outer function that
        // Expr::parse returns, that way the effect of the assignment can be seen here.
        create_global("$someInt", memory);

        let result = expr.run(memory).unwrap();
        println!("{:#?}\n memory: {:#?}", result, memory);
    }

    #[test]
    fn walk_assign2() {
        let expr = Expr::parse("$otherInt = 35; $someInt = $otherInt + 2;").unwrap();
        let mut memory = &mut HashMap::new();

        // create $someInt outside the scope of the anonymous outer function that
        // Expr::parse returns, that way the effect of the assignment can be seen here.
        create_global("$someInt", memory);

        let result = expr.run(memory).unwrap();
        println!("{:#?}\n memory: {:#?}", result, memory);
    }

    #[test]
    #[should_panic]
    fn walk_assign_undefined() {
        let expr = Expr::parse("$someInt = 35; $otherInt = $someInt + $whatIsThis;").unwrap();
        let mut memory = &mut HashMap::new();
        let result = expr.run(memory).unwrap();
    }
}
<|endoftext|>


<commit_before>extern crate regex;
#[macro_use]
extern crate lazy_static;

use regex::Regex;
use std::ffi::OsStr;
use std::fs;
use std::io::prelude::*;

lazy_static! {
    static ref DEC_CLIPPY_LINT_RE: Regex = Regex::new(r#"(?x)
        declare_clippy_lint!\s*[\{(]\s*
        pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
        (?P<cat>[a-z_]+)\s*,\s*
        "(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]
    "#).unwrap();
    static ref DEC_DEPRECATED_LINT_RE: Regex = Regex::new(r#"(?x)
        declare_deprecated_lint!\s*[{(]\s*
        pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
        "(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]
    "#).unwrap();
    static ref NL_ESCAPE_RE: Regex = Regex::new(r#"\\\n\s*"#).unwrap();
    pub static ref DOCS_LINK: String = "https://rust-lang-nursery.github.io/rust-clippy/master/index.html".to_string();
}

#[derive(Clone, PartialEq, Debug)]
pub struct Lint {
    pub name: String,
    pub group: String,
    pub desc: String,
    pub deprecation: Option<String>,
    pub module: String,
}

impl Lint {
    pub fn new(name: &str, group: &str, desc: &str, deprecation: Option<&str>, module: &str) -> Lint {
        Lint {
            name: name.to_lowercase(),
            group: group.to_string(),
            desc: NL_ESCAPE_RE.replace(&desc.replace("\\\"", "\""), "").to_string(),
            deprecation: deprecation.map(|d| d.to_string()),
            module: module.to_string(),
        }
    }

    pub fn active_lints(lints: &[Lint]) -> Vec<Lint> {
        lints.iter().filter(|l| l.deprecation.is_none()).cloned().collect::<Vec<Lint>>()
    }

    pub fn in_lint_group(group: &str, lints: &[Lint]) -> Vec<Lint> {
        lints.iter().filter(|l| l.group == group).cloned().collect::<Vec<Lint>>()
    }
}

pub fn collect_all() -> Vec<Lint> {
    let mut lints = vec![];
    for direntry in lint_files() {
        lints.append(&mut collect_from_file(&direntry));
    }
    lints
}

fn collect_from_file(direntry: &fs::DirEntry) -> Vec<Lint> {
    let mut file = fs::File::open(direntry.path()).unwrap();
    let mut content = String::new();
    file.read_to_string(&mut content).unwrap();
    parse_contents(&content, direntry.path().file_stem().unwrap().to_str().unwrap())
}

fn parse_contents(content: &str, filename: &str) -> Vec<Lint> {
    let mut lints: Vec<Lint> = DEC_CLIPPY_LINT_RE
        .captures_iter(&content)
        .map(|m| Lint::new(&m["name"], &m["cat"], &m["desc"], None, filename))
        .collect();
    let mut deprecated = DEC_DEPRECATED_LINT_RE
        .captures_iter(&content)
        .map(|m| Lint::new( &m["name"], "Deprecated", &m["desc"], Some(&m["desc"]), filename))
        .collect();
    lints.append(&mut deprecated);
    lints
}

/// Collects all .rs files in the `clippy_lints/src` directory
fn lint_files() -> Vec<fs::DirEntry> {
    let paths = fs::read_dir("../clippy_lints/src").unwrap();
    paths
        .filter_map(|f| f.ok())
        .filter(|f| f.path().extension() == Some(OsStr::new("rs")))
        .collect::<Vec<fs::DirEntry>>()
}

#[test]
fn test_parse_contents() {
    let result = parse_contents(
        r#"
declare_clippy_lint! {
    pub PTR_ARG,
    style,
    "really long \
     text"
}

declare_clippy_lint!{
    pub DOC_MARKDOWN,
    pedantic,
    "single line"
}

/// some doc comment
declare_deprecated_lint! {
    pub SHOULD_ASSERT_EQ,
    "`assert!()` will be more flexible with RFC 2011"
}
    "#,
    "module_name");

    let expected = vec![
        Lint::new("ptr_arg", "style", "really long text", None, "module_name"),
        Lint::new("doc_markdown", "pedantic", "single line", None, "module_name"),
        Lint::new(
            "should_assert_eq",
            "Deprecated",
            "`assert!()` will be more flexible with RFC 2011",
            Some("`assert!()` will be more flexible with RFC 2011"),
            "module_name"
        ),
    ];
    assert_eq!(expected, result);
}

#[test]
fn test_active_lints() {
    let lints = vec![
        Lint::new("should_assert_eq", "Deprecated", "abc", Some("Reason"), "module_name"),
        Lint::new("should_assert_eq2", "Not Deprecated", "abc", None, "module_name")
    ];
    let expected = vec![
        Lint::new("should_assert_eq2", "Not Deprecated", "abc", None, "module_name")
    ];
    assert_eq!(expected, Lint::active_lints(&lints));
}

#[test]
fn test_in_lint_group() {
    let lints = vec![
        Lint::new("ptr_arg", "style", "really long text", None, "module_name"),
        Lint::new("doc_markdown", "pedantic", "single line", None, "module_name"),
    ];
    let expected = vec![
        Lint::new("ptr_arg", "style", "really long text", None, "module_name")
    ];
    assert_eq!(expected, Lint::in_lint_group("style", &lints));
}
<commit_msg>s/direntry/dir_entry<commit_after>extern crate regex;
#[macro_use]
extern crate lazy_static;

use regex::Regex;
use std::ffi::OsStr;
use std::fs;
use std::io::prelude::*;

lazy_static! {
    static ref DEC_CLIPPY_LINT_RE: Regex = Regex::new(r#"(?x)
        declare_clippy_lint!\s*[\{(]\s*
        pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
        (?P<cat>[a-z_]+)\s*,\s*
        "(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]
    "#).unwrap();
    static ref DEC_DEPRECATED_LINT_RE: Regex = Regex::new(r#"(?x)
        declare_deprecated_lint!\s*[{(]\s*
        pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
        "(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]
    "#).unwrap();
    static ref NL_ESCAPE_RE: Regex = Regex::new(r#"\\\n\s*"#).unwrap();
    pub static ref DOCS_LINK: String = "https://rust-lang-nursery.github.io/rust-clippy/master/index.html".to_string();
}

#[derive(Clone, PartialEq, Debug)]
pub struct Lint {
    pub name: String,
    pub group: String,
    pub desc: String,
    pub deprecation: Option<String>,
    pub module: String,
}

impl Lint {
    pub fn new(name: &str, group: &str, desc: &str, deprecation: Option<&str>, module: &str) -> Lint {
        Lint {
            name: name.to_lowercase(),
            group: group.to_string(),
            desc: NL_ESCAPE_RE.replace(&desc.replace("\\\"", "\""), "").to_string(),
            deprecation: deprecation.map(|d| d.to_string()),
            module: module.to_string(),
        }
    }

    pub fn active_lints(lints: &[Lint]) -> Vec<Lint> {
        lints.iter().filter(|l| l.deprecation.is_none()).cloned().collect::<Vec<Lint>>()
    }

    pub fn in_lint_group(group: &str, lints: &[Lint]) -> Vec<Lint> {
        lints.iter().filter(|l| l.group == group).cloned().collect::<Vec<Lint>>()
    }
}

pub fn collect_all() -> Vec<Lint> {
    let mut lints = vec![];
    for dir_entry in lint_files() {
        lints.append(&mut collect_from_file(&dir_entry));
    }
    lints
}

fn collect_from_file(dir_entry: &fs::DirEntry) -> Vec<Lint> {
    let mut file = fs::File::open(dir_entry.path()).unwrap();
    let mut content = String::new();
    file.read_to_string(&mut content).unwrap();
    parse_contents(&content, dir_entry.path().file_stem().unwrap().to_str().unwrap())
}

fn parse_contents(content: &str, filename: &str) -> Vec<Lint> {
    let mut lints: Vec<Lint> = DEC_CLIPPY_LINT_RE
        .captures_iter(&content)
        .map(|m| Lint::new(&m["name"], &m["cat"], &m["desc"], None, filename))
        .collect();
    let mut deprecated = DEC_DEPRECATED_LINT_RE
        .captures_iter(&content)
        .map(|m| Lint::new( &m["name"], "Deprecated", &m["desc"], Some(&m["desc"]), filename))
        .collect();
    lints.append(&mut deprecated);
    lints
}

/// Collects all .rs files in the `clippy_lints/src` directory
fn lint_files() -> Vec<fs::DirEntry> {
    let paths = fs::read_dir("../clippy_lints/src").unwrap();
    paths
        .filter_map(|f| f.ok())
        .filter(|f| f.path().extension() == Some(OsStr::new("rs")))
        .collect::<Vec<fs::DirEntry>>()
}

#[test]
fn test_parse_contents() {
    let result = parse_contents(
        r#"
declare_clippy_lint! {
    pub PTR_ARG,
    style,
    "really long \
     text"
}

declare_clippy_lint!{
    pub DOC_MARKDOWN,
    pedantic,
    "single line"
}

/// some doc comment
declare_deprecated_lint! {
    pub SHOULD_ASSERT_EQ,
    "`assert!()` will be more flexible with RFC 2011"
}
    "#,
    "module_name");

    let expected = vec![
        Lint::new("ptr_arg", "style", "really long text", None, "module_name"),
        Lint::new("doc_markdown", "pedantic", "single line", None, "module_name"),
        Lint::new(
            "should_assert_eq",
            "Deprecated",
            "`assert!()` will be more flexible with RFC 2011",
            Some("`assert!()` will be more flexible with RFC 2011"),
            "module_name"
        ),
    ];
    assert_eq!(expected, result);
}

#[test]
fn test_active_lints() {
    let lints = vec![
        Lint::new("should_assert_eq", "Deprecated", "abc", Some("Reason"), "module_name"),
        Lint::new("should_assert_eq2", "Not Deprecated", "abc", None, "module_name")
    ];
    let expected = vec![
        Lint::new("should_assert_eq2", "Not Deprecated", "abc", None, "module_name")
    ];
    assert_eq!(expected, Lint::active_lints(&lints));
}

#[test]
fn test_in_lint_group() {
    let lints = vec![
        Lint::new("ptr_arg", "style", "really long text", None, "module_name"),
        Lint::new("doc_markdown", "pedantic", "single line", None, "module_name"),
    ];
    let expected = vec![
        Lint::new("ptr_arg", "style", "really long text", None, "module_name")
    ];
    assert_eq!(expected, Lint::in_lint_group("style", &lints));
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

pub struct Translator
{
	rules: HashMap<(char, char), char>,
}

impl Translator
{
	pub fn new() -> Translator
	{
		Translator
		{
			rules: get_default_rules(),
		}
	}

	// Returns translated characted and boolean value indicating that previous character should be erased.
	fn translate_char(&self, current : char, previous : char) -> (char, bool)
	{
		match self.rules.get(&(current, previous))
		{
			Some(result) => (*result, previous != ' '),
			None => match self.rules.get(&(current, ' '))
			{
				Some(result) => (*result, false),
				None => (current, false),
			}
		}
	}

	pub fn translate(&self, text : &str) -> String
	{
		let mut result = String::with_capacity(text.len());

		let mut previous = ' ';
		for c in text.chars()
		{
			let (translated, erase_previous) = self.translate_char(c, previous);
			if erase_previous
			{
				result.pop();
			}

			result.push(translated);
			previous = translated;
		}

		result
	}
}

fn get_default_rules() -> HashMap<(char, char), char>
{
	let mut result = HashMap::with_capacity(50);

	result.insert(('a', ' '), 'а');
	result.insert(('b', ' '), 'б');
	result.insert(('v', ' '), 'в');
	result.insert(('g', ' '), 'г');
	result.insert(('d', ' '), 'д');
	result.insert(('e', ' '), 'е');
	result.insert(('o', 'j'), 'ё');
	result.insert(('o', 'й'), 'ё');
	result.insert(('h', 'z'), 'ж');
	result.insert(('h', 'з'), 'ж');
	result.insert(('z', ' '), 'з');
	result.insert(('i', ' '), 'и');
	result.insert(('j', ' '), 'й');
	result.insert(('k', ' '), 'к');
	result.insert(('l', ' '), 'л');
	result.insert(('m', ' '), 'м');
	result.insert(('n', ' '), 'н');
	result.insert(('o', ' '), 'о');
	result.insert(('p', ' '), 'п');
	result.insert(('r', ' '), 'р');
	result.insert(('s', ' '), 'с');
	result.insert(('t', ' '), 'т');
	result.insert(('u', ' '), 'у');
	result.insert(('f', ' '), 'ф');
	result.insert(('h', ' '), 'х');
	result.insert(('x', ' '), 'х');
	result.insert(('c', ' '), 'ц');
	result.insert(('h', 'c'), 'ч');
	result.insert(('h', 'ц'), 'ч');
	result.insert(('h', 'h'), 'ш');
	result.insert(('h', 'с'), 'ш');
	result.insert(('h', 'ш'), 'щ');
	result.insert(('w', ' '), 'щ');
	result.insert(('#', ' '), 'ъ');
	result.insert(('y', ' '), 'ы');
	result.insert(('\'', ' '), 'ь');
	result.insert(('e', 'j'), 'э');
	result.insert(('e', 'й'), 'э');
	result.insert(('u', 'j'), 'ю');
	result.insert(('u', 'й'), 'ю');
	result.insert(('a', 'j'), 'я');
	result.insert(('a', 'й'), 'я');

	result.insert(('A', ' '), 'А');
	result.insert(('B', ' '), 'Б');
	result.insert(('V', ' '), 'В');
	result.insert(('G', ' '), 'Г');
	result.insert(('D', ' '), 'Д');
	result.insert(('E', ' '), 'Е');
	result.insert(('O', 'J'), 'Ё');
	result.insert(('O', 'Й'), 'Ё');
	result.insert(('H', 'Z'), 'Ж');
	result.insert(('H', 'З'), 'Ж');
	result.insert(('Z', ' '), 'З');
	result.insert(('I', ' '), 'И');
	result.insert(('J', ' '), 'Й');
	result.insert(('K', ' '), 'К');
	result.insert(('L', ' '), 'Л');
	result.insert(('M', ' '), 'М');
	result.insert(('N', ' '), 'Н');
	result.insert(('O', ' '), 'О');
	result.insert(('P', ' '), 'П');
	result.insert(('R', ' '), 'Р');
	result.insert(('S', ' '), 'С');
	result.insert(('T', ' '), 'Т');
	result.insert(('U', ' '), 'У');
	result.insert(('F', ' '), 'Ф');
	result.insert(('H', ' '), 'Х');
	result.insert(('X', ' '), 'Х');
	result.insert(('C', ' '), 'Ц');
	result.insert(('H', 'C'), 'Ч');
	result.insert(('H', 'Ц'), 'Ч');
	result.insert(('H', 'H'), 'Ш');
	result.insert(('H', 'С'), 'Ш');
	result.insert(('H', 'Ш'), 'Щ');
	result.insert(('W', ' '), 'Щ');
	result.insert(('#', 'ъ'), 'Ъ');
	result.insert(('Y', ' '), 'Ы');
	result.insert(('\'', 'ь'), 'Ь');
	result.insert(('E', 'J'), 'Э');
	result.insert(('E', 'Й'), 'Э');
	result.insert(('U', 'J'), 'Ю');
	result.insert(('U', 'Й'), 'Ю');
	result.insert(('A', 'J'), 'Я');
	result.insert(('A', 'Й'), 'Я');

	result
}
<commit_msg>Test has been added<commit_after>use std::collections::HashMap;

pub struct Translator
{
	rules: HashMap<(char, char), char>,
}

impl Translator
{
	pub fn new() -> Translator
	{
		Translator
		{
			rules: get_default_rules(),
		}
	}

	// Returns translated characted and boolean value indicating that previous character should be erased.
	fn translate_char(&self, current : char, previous : char) -> (char, bool)
	{
		match self.rules.get(&(current, previous))
		{
			Some(result) => (*result, previous != ' '),
			None => match self.rules.get(&(current, ' '))
			{
				Some(result) => (*result, false),
				None => (current, false),
			}
		}
	}

	pub fn translate(&self, text : &str) -> String
	{
		let mut result = String::with_capacity(text.len());

		let mut previous = ' ';
		for c in text.chars()
		{
			let (translated, erase_previous) = self.translate_char(c, previous);
			if erase_previous
			{
				result.pop();
			}

			result.push(translated);
			previous = translated;
		}

		result
	}
}

fn get_default_rules() -> HashMap<(char, char), char>
{
	let mut result = HashMap::with_capacity(50);

	result.insert(('a', ' '), 'а');
	result.insert(('b', ' '), 'б');
	result.insert(('v', ' '), 'в');
	result.insert(('g', ' '), 'г');
	result.insert(('d', ' '), 'д');
	result.insert(('e', ' '), 'е');
	result.insert(('o', 'j'), 'ё');
	result.insert(('o', 'й'), 'ё');
	result.insert(('h', 'z'), 'ж');
	result.insert(('h', 'з'), 'ж');
	result.insert(('z', ' '), 'з');
	result.insert(('i', ' '), 'и');
	result.insert(('j', ' '), 'й');
	result.insert(('k', ' '), 'к');
	result.insert(('l', ' '), 'л');
	result.insert(('m', ' '), 'м');
	result.insert(('n', ' '), 'н');
	result.insert(('o', ' '), 'о');
	result.insert(('p', ' '), 'п');
	result.insert(('r', ' '), 'р');
	result.insert(('s', ' '), 'с');
	result.insert(('t', ' '), 'т');
	result.insert(('u', ' '), 'у');
	result.insert(('f', ' '), 'ф');
	result.insert(('h', ' '), 'х');
	result.insert(('x', ' '), 'х');
	result.insert(('c', ' '), 'ц');
	result.insert(('h', 'c'), 'ч');
	result.insert(('h', 'ц'), 'ч');
	result.insert(('h', 'h'), 'ш');
	result.insert(('h', 'с'), 'ш');
	result.insert(('h', 'ш'), 'щ');
	result.insert(('w', ' '), 'щ');
	result.insert(('#', ' '), 'ъ');
	result.insert(('y', ' '), 'ы');
	result.insert(('\'', ' '), 'ь');
	result.insert(('e', 'j'), 'э');
	result.insert(('e', 'й'), 'э');
	result.insert(('u', 'j'), 'ю');
	result.insert(('u', 'й'), 'ю');
	result.insert(('a', 'j'), 'я');
	result.insert(('a', 'й'), 'я');

	result.insert(('A', ' '), 'А');
	result.insert(('B', ' '), 'Б');
	result.insert(('V', ' '), 'В');
	result.insert(('G', ' '), 'Г');
	result.insert(('D', ' '), 'Д');
	result.insert(('E', ' '), 'Е');
	result.insert(('O', 'J'), 'Ё');
	result.insert(('O', 'Й'), 'Ё');
	result.insert(('H', 'Z'), 'Ж');
	result.insert(('H', 'З'), 'Ж');
	result.insert(('Z', ' '), 'З');
	result.insert(('I', ' '), 'И');
	result.insert(('J', ' '), 'Й');
	result.insert(('K', ' '), 'К');
	result.insert(('L', ' '), 'Л');
	result.insert(('M', ' '), 'М');
	result.insert(('N', ' '), 'Н');
	result.insert(('O', ' '), 'О');
	result.insert(('P', ' '), 'П');
	result.insert(('R', ' '), 'Р');
	result.insert(('S', ' '), 'С');
	result.insert(('T', ' '), 'Т');
	result.insert(('U', ' '), 'У');
	result.insert(('F', ' '), 'Ф');
	result.insert(('H', ' '), 'Х');
	result.insert(('X', ' '), 'Х');
	result.insert(('C', ' '), 'Ц');
	result.insert(('H', 'C'), 'Ч');
	result.insert(('H', 'Ц'), 'Ч');
	result.insert(('H', 'H'), 'Ш');
	result.insert(('H', 'С'), 'Ш');
	result.insert(('H', 'Ш'), 'Щ');
	result.insert(('W', ' '), 'Щ');
	result.insert(('#', 'ъ'), 'Ъ');
	result.insert(('Y', ' '), 'Ы');
	result.insert(('\'', 'ь'), 'Ь');
	result.insert(('E', 'J'), 'Э');
	result.insert(('E', 'Й'), 'Э');
	result.insert(('U', 'J'), 'Ю');
	result.insert(('U', 'Й'), 'Ю');
	result.insert(('A', 'J'), 'Я');
	result.insert(('A', 'Й'), 'Я');

	result
}

#[test]
fn translator_new() {
    let translator = Translator::new();
    assert_eq(Translator.rules, get_default_rules());
}
<|endoftext|>


<commit_before><commit_msg>Proper use definition<commit_after><|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*! Non-blocking access to stdin, stdout, and stderr.

This module provides bindings to the local event loop's TTY interface, using it
to offer synchronous but non-blocking versions of stdio. These handles can be
inspected for information about terminal dimensions or for related information
about the stream or terminal to which it is attached.

# Example

```rust
# #![allow(unused_must_use)]
use std::io;

let mut out = io::stdout();
out.write(b"Hello, world!");
```

*/

use failure::local_stderr;
use fmt;
use io::{Reader, Writer, IoResult, IoError, OtherIoError,
         standard_error, EndOfFile, LineBufferedWriter, BufferedReader};
use iter::Iterator;
use kinds::Send;
use libc;
use option::{Option, Some, None};
use boxed::Box;
use result::{Ok, Err};
use rt;
use rt::local::Local;
use rt::task::Task;
use rt::rtio::{DontClose, IoFactory, LocalIo, RtioFileStream, RtioTTY};
use slice::ImmutableVector;
use str::StrSlice;
use uint;

// And so begins the tale of acquiring a uv handle to a stdio stream on all
// platforms in all situations. Our story begins by splitting the world into two
// categories, windows and unix. Then one day the creators of unix said let
// there be redirection! And henceforth there was redirection away from the
// console for standard I/O streams.
//
// After this day, the world split into four factions:
//
// 1. Unix with stdout on a terminal.
// 2. Unix with stdout redirected.
// 3. Windows with stdout on a terminal.
// 4. Windows with stdout redirected.
//
// Many years passed, and then one day the nation of libuv decided to unify this
// world. After months of toiling, uv created three ideas: TTY, Pipe, File.
// These three ideas propagated throughout the lands and the four great factions
// decided to settle among them.
//
// The groups of 1, 2, and 3 all worked very hard towards the idea of TTY. Upon
// doing so, they even enhanced themselves further then their Pipe/File
// brethren, becoming the dominant powers.
//
// The group of 4, however, decided to work independently. They abandoned the
// common TTY belief throughout, and even abandoned the fledgling Pipe belief.
// The members of the 4th faction decided to only align themselves with File.
//
// tl;dr; TTY works on everything but when windows stdout is redirected, in that
//        case pipe also doesn't work, but magically file does!
enum StdSource {
    TTY(Box<RtioTTY + Send>),
    File(Box<RtioFileStream + Send>),
}

fn src<T>(fd: libc::c_int, readable: bool, f: |StdSource| -> T) -> T {
    LocalIo::maybe_raise(|io| {
        Ok(match io.tty_open(fd, readable) {
            Ok(tty) => f(TTY(tty)),
            Err(_) => f(File(io.fs_from_raw_fd(fd, DontClose))),
        })
    }).map_err(IoError::from_rtio_error).unwrap()
}

local_data_key!(local_stdout: Box<Writer + Send>)

/// Creates a new non-blocking handle to the stdin of the current process.
///
/// The returned handled is buffered by default with a `BufferedReader`. If
/// buffered access is not desired, the `stdin_raw` function is provided to
/// provided unbuffered access to stdin.
///
/// Care should be taken when creating multiple handles to the stdin of a
/// process. Because this is a buffered reader by default, it's possible for
/// pending input to be unconsumed in one reader and unavailable to other
/// readers. It is recommended that only one handle at a time is created for the
/// stdin of a process.
///
/// See `stdout()` for more notes about this function.
pub fn stdin() -> BufferedReader<StdReader> {
    // The default buffer capacity is 64k, but apparently windows doesn't like
    // 64k reads on stdin. See #13304 for details, but the idea is that on
    // windows we use a slightly smaller buffer that's been seen to be
    // acceptable.
    if cfg!(windows) {
        BufferedReader::with_capacity(8 * 1024, stdin_raw())
    } else {
        BufferedReader::new(stdin_raw())
    }
}

/// Creates a new non-blocking handle to the stdin of the current process.
///
/// Unlike `stdin()`, the returned reader is *not* a buffered reader.
///
/// See `stdout()` for more notes about this function.
pub fn stdin_raw() -> StdReader {
    src(libc::STDIN_FILENO, true, |src| StdReader { inner: src })
}

/// Creates a line-buffered handle to the stdout of the current process.
///
/// Note that this is a fairly expensive operation in that at least one memory
/// allocation is performed. Additionally, this must be called from a runtime
/// task context because the stream returned will be a non-blocking object using
/// the local scheduler to perform the I/O.
///
/// Care should be taken when creating multiple handles to an output stream for
/// a single process. While usage is still safe, the output may be surprising if
/// no synchronization is performed to ensure a sane output.
pub fn stdout() -> LineBufferedWriter<StdWriter> {
    LineBufferedWriter::new(stdout_raw())
}

/// Creates an unbuffered handle to the stdout of the current process
///
/// See notes in `stdout()` for more information.
pub fn stdout_raw() -> StdWriter {
    src(libc::STDOUT_FILENO, false, |src| StdWriter { inner: src })
}

/// Creates a line-buffered handle to the stderr of the current process.
///
/// See `stdout()` for notes about this function.
pub fn stderr() -> LineBufferedWriter<StdWriter> {
    LineBufferedWriter::new(stderr_raw())
}

/// Creates an unbuffered handle to the stderr of the current process
///
/// See notes in `stdout()` for more information.
pub fn stderr_raw() -> StdWriter {
    src(libc::STDERR_FILENO, false, |src| StdWriter { inner: src })
}

/// Resets the task-local stdout handle to the specified writer
///
/// This will replace the current task's stdout handle, returning the old
/// handle. All future calls to `print` and friends will emit their output to
/// this specified handle.
///
/// Note that this does not need to be called for all new tasks; the default
/// output handle is to the process's stdout stream.
pub fn set_stdout(stdout: Box<Writer + Send>) -> Option<Box<Writer + Send>> {
    local_stdout.replace(Some(stdout)).and_then(|mut s| {
        let _ = s.flush();
        Some(s)
    })
}

/// Resets the task-local stderr handle to the specified writer
///
/// This will replace the current task's stderr handle, returning the old
/// handle. Currently, the stderr handle is used for printing failure messages
/// during task failure.
///
/// Note that this does not need to be called for all new tasks; the default
/// output handle is to the process's stderr stream.
pub fn set_stderr(stderr: Box<Writer + Send>) -> Option<Box<Writer + Send>> {
    local_stderr.replace(Some(stderr)).and_then(|mut s| {
        let _ = s.flush();
        Some(s)
    })
}

// Helper to access the local task's stdout handle
//
// Note that this is not a safe function to expose because you can create an
// aliased pointer very easily:
//
//  with_task_stdout(|io1| {
//      with_task_stdout(|io2| {
//          // io1 aliases io2
//      })
//  })
fn with_task_stdout(f: |&mut Writer| -> IoResult<()>) {
    let result = if Local::exists(None::<Task>) {
        let mut my_stdout = local_stdout.replace(None).unwrap_or_else(|| {
            box stdout() as Box<Writer + Send>
        });
        let result = f(my_stdout);
        local_stdout.replace(Some(my_stdout));
        result
    } else {
        let mut io = rt::Stdout;
        f(&mut io as &mut Writer)
    };
    match result {
        Ok(()) => {}
        Err(e) => fail!("failed printing to stdout: {}", e),
    }
}

/// Flushes the local task's stdout handle.
///
/// By default, this stream is a line-buffering stream, so flushing may be
/// necessary to ensure that all output is printed to the screen (if there are
/// no newlines printed).
///
/// Note that logging macros do not use this stream. Using the logging macros
/// will emit output to stderr, and while they are line buffered the log
/// messages are always terminated in a newline (no need to flush).
pub fn flush() {
    with_task_stdout(|io| io.flush())
}

/// Prints a string to the stdout of the current process. No newline is emitted
/// after the string is printed.
pub fn print(s: &str) {
    with_task_stdout(|io| io.write(s.as_bytes()))
}

/// Prints a string as a line. to the stdout of the current process. A literal
/// `\n` character is printed to the console after the string.
pub fn println(s: &str) {
    with_task_stdout(|io| {
        io.write(s.as_bytes()).and_then(|()| io.write(['\n' as u8]))
    })
}

/// Similar to `print`, but takes a `fmt::Arguments` structure to be compatible
/// with the `format_args!` macro.
pub fn print_args(fmt: &fmt::Arguments) {
    with_task_stdout(|io| write!(io, "{}", fmt))
}

/// Similar to `println`, but takes a `fmt::Arguments` structure to be
/// compatible with the `format_args!` macro.
pub fn println_args(fmt: &fmt::Arguments) {
    with_task_stdout(|io| writeln!(io, "{}", fmt))
}

/// Representation of a reader of a standard input stream
pub struct StdReader {
    inner: StdSource
}

impl StdReader {
    /// Returns whether this stream is attached to a TTY instance or not.
    pub fn isatty(&self) -> bool {
        match self.inner {
            TTY(..) => true,
            File(..) => false,
        }
    }
}

impl Reader for StdReader {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        let ret = match self.inner {
            TTY(ref mut tty) => {
                // Flush the task-local stdout so that weird issues like a
                // print!'d prompt not being shown until after the user hits
                // enter.
                flush();
                tty.read(buf)
            },
            File(ref mut file) => file.read(buf).map(|i| i as uint),
        }.map_err(IoError::from_rtio_error);
        match ret {
            // When reading a piped stdin, libuv will return 0-length reads when
            // stdin reaches EOF. For pretty much all other streams it will
            // return an actual EOF error, but apparently for stdin it's a
            // little different. Hence, here we convert a 0 length read to an
            // end-of-file indicator so the caller knows to stop reading.
            Ok(0) => { Err(standard_error(EndOfFile)) }
            ret @ Ok(..) | ret @ Err(..) => ret,
        }
    }
}

/// Representation of a writer to a standard output stream
pub struct StdWriter {
    inner: StdSource
}

impl StdWriter {
    /// Gets the size of this output window, if possible. This is typically used
    /// when the writer is attached to something like a terminal, this is used
    /// to fetch the dimensions of the terminal.
    ///
    /// If successful, returns `Ok((width, height))`.
    ///
    /// # Error
    ///
    /// This function will return an error if the output stream is not actually
    /// connected to a TTY instance, or if querying the TTY instance fails.
    pub fn winsize(&mut self) -> IoResult<(int, int)> {
        match self.inner {
            TTY(ref mut tty) => {
                tty.get_winsize().map_err(IoError::from_rtio_error)
            }
            File(..) => {
                Err(IoError {
                    kind: OtherIoError,
                    desc: "stream is not a tty",
                    detail: None,
                })
            }
        }
    }

    /// Controls whether this output stream is a "raw stream" or simply a normal
    /// stream.
    ///
    /// # Error
    ///
    /// This function will return an error if the output stream is not actually
    /// connected to a TTY instance, or if querying the TTY instance fails.
    pub fn set_raw(&mut self, raw: bool) -> IoResult<()> {
        match self.inner {
            TTY(ref mut tty) => {
                tty.set_raw(raw).map_err(IoError::from_rtio_error)
            }
            File(..) => {
                Err(IoError {
                    kind: OtherIoError,
                    desc: "stream is not a tty",
                    detail: None,
                })
            }
        }
    }

    /// Returns whether this stream is attached to a TTY instance or not.
    pub fn isatty(&self) -> bool {
        match self.inner {
            TTY(..) => true,
            File(..) => false,
        }
    }
}

impl Writer for StdWriter {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        // As with stdin on windows, stdout often can't handle writes of large
        // sizes. For an example, see #14940. For this reason, chunk the output
        // buffer on windows, but on unix we can just write the whole buffer all
        // at once.
        let max_size = if cfg!(windows) {64 * 1024} else {uint::MAX};
        for chunk in buf.chunks(max_size) {
            try!(match self.inner {
                TTY(ref mut tty) => tty.write(chunk),
                File(ref mut file) => file.write(chunk),
            }.map_err(IoError::from_rtio_error))
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    iotest!(fn smoke() {
        // Just make sure we can acquire handles
        stdin();
        stdout();
        stderr();
    })

    iotest!(fn capture_stdout() {
        use io::{ChanReader, ChanWriter};

        let (tx, rx) = channel();
        let (mut r, w) = (ChanReader::new(rx), ChanWriter::new(tx));
        spawn(proc() {
            set_stdout(box w);
            println!("hello!");
        });
        assert_eq!(r.read_to_string().unwrap(), "hello!\n".to_string());
    })

    iotest!(fn capture_stderr() {
        use realstd::comm::channel;
        use realstd::io::{Writer, ChanReader, ChanWriter, Reader};

        let (tx, rx) = channel();
        let (mut r, w) = (ChanReader::new(rx), ChanWriter::new(tx));
        spawn(proc() {
            ::realstd::io::stdio::set_stderr(box w);
            fail!("my special message");
        });
        let s = r.read_to_string().unwrap();
        assert!(s.as_slice().contains("my special message"));
    })
}
<commit_msg>doc: make the sentence make more sense<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*! Non-blocking access to stdin, stdout, and stderr.

This module provides bindings to the local event loop's TTY interface, using it
to offer synchronous but non-blocking versions of stdio. These handles can be
inspected for information about terminal dimensions or for related information
about the stream or terminal to which it is attached.

# Example

```rust
# #![allow(unused_must_use)]
use std::io;

let mut out = io::stdout();
out.write(b"Hello, world!");
```

*/

use failure::local_stderr;
use fmt;
use io::{Reader, Writer, IoResult, IoError, OtherIoError,
         standard_error, EndOfFile, LineBufferedWriter, BufferedReader};
use iter::Iterator;
use kinds::Send;
use libc;
use option::{Option, Some, None};
use boxed::Box;
use result::{Ok, Err};
use rt;
use rt::local::Local;
use rt::task::Task;
use rt::rtio::{DontClose, IoFactory, LocalIo, RtioFileStream, RtioTTY};
use slice::ImmutableVector;
use str::StrSlice;
use uint;

// And so begins the tale of acquiring a uv handle to a stdio stream on all
// platforms in all situations. Our story begins by splitting the world into two
// categories, windows and unix. Then one day the creators of unix said let
// there be redirection! And henceforth there was redirection away from the
// console for standard I/O streams.
//
// After this day, the world split into four factions:
//
// 1. Unix with stdout on a terminal.
// 2. Unix with stdout redirected.
// 3. Windows with stdout on a terminal.
// 4. Windows with stdout redirected.
//
// Many years passed, and then one day the nation of libuv decided to unify this
// world. After months of toiling, uv created three ideas: TTY, Pipe, File.
// These three ideas propagated throughout the lands and the four great factions
// decided to settle among them.
//
// The groups of 1, 2, and 3 all worked very hard towards the idea of TTY. Upon
// doing so, they even enhanced themselves further then their Pipe/File
// brethren, becoming the dominant powers.
//
// The group of 4, however, decided to work independently. They abandoned the
// common TTY belief throughout, and even abandoned the fledgling Pipe belief.
// The members of the 4th faction decided to only align themselves with File.
//
// tl;dr; TTY works on everything but when windows stdout is redirected, in that
//        case pipe also doesn't work, but magically file does!
enum StdSource {
    TTY(Box<RtioTTY + Send>),
    File(Box<RtioFileStream + Send>),
}

fn src<T>(fd: libc::c_int, readable: bool, f: |StdSource| -> T) -> T {
    LocalIo::maybe_raise(|io| {
        Ok(match io.tty_open(fd, readable) {
            Ok(tty) => f(TTY(tty)),
            Err(_) => f(File(io.fs_from_raw_fd(fd, DontClose))),
        })
    }).map_err(IoError::from_rtio_error).unwrap()
}

local_data_key!(local_stdout: Box<Writer + Send>)

/// Creates a new non-blocking handle to the stdin of the current process.
///
/// The returned handled is buffered by default with a `BufferedReader`. If
/// buffered access is not desired, the `stdin_raw` function is provided to
/// provided unbuffered access to stdin.
///
/// Care should be taken when creating multiple handles to the stdin of a
/// process. Because this is a buffered reader by default, it's possible for
/// pending input to be unconsumed in one reader and unavailable to other
/// readers. It is recommended that only one handle at a time is created for the
/// stdin of a process.
///
/// See `stdout()` for more notes about this function.
pub fn stdin() -> BufferedReader<StdReader> {
    // The default buffer capacity is 64k, but apparently windows doesn't like
    // 64k reads on stdin. See #13304 for details, but the idea is that on
    // windows we use a slightly smaller buffer that's been seen to be
    // acceptable.
    if cfg!(windows) {
        BufferedReader::with_capacity(8 * 1024, stdin_raw())
    } else {
        BufferedReader::new(stdin_raw())
    }
}

/// Creates a new non-blocking handle to the stdin of the current process.
///
/// Unlike `stdin()`, the returned reader is *not* a buffered reader.
///
/// See `stdout()` for more notes about this function.
pub fn stdin_raw() -> StdReader {
    src(libc::STDIN_FILENO, true, |src| StdReader { inner: src })
}

/// Creates a line-buffered handle to the stdout of the current process.
///
/// Note that this is a fairly expensive operation in that at least one memory
/// allocation is performed. Additionally, this must be called from a runtime
/// task context because the stream returned will be a non-blocking object using
/// the local scheduler to perform the I/O.
///
/// Care should be taken when creating multiple handles to an output stream for
/// a single process. While usage is still safe, the output may be surprising if
/// no synchronization is performed to ensure a sane output.
pub fn stdout() -> LineBufferedWriter<StdWriter> {
    LineBufferedWriter::new(stdout_raw())
}

/// Creates an unbuffered handle to the stdout of the current process
///
/// See notes in `stdout()` for more information.
pub fn stdout_raw() -> StdWriter {
    src(libc::STDOUT_FILENO, false, |src| StdWriter { inner: src })
}

/// Creates a line-buffered handle to the stderr of the current process.
///
/// See `stdout()` for notes about this function.
pub fn stderr() -> LineBufferedWriter<StdWriter> {
    LineBufferedWriter::new(stderr_raw())
}

/// Creates an unbuffered handle to the stderr of the current process
///
/// See notes in `stdout()` for more information.
pub fn stderr_raw() -> StdWriter {
    src(libc::STDERR_FILENO, false, |src| StdWriter { inner: src })
}

/// Resets the task-local stdout handle to the specified writer
///
/// This will replace the current task's stdout handle, returning the old
/// handle. All future calls to `print` and friends will emit their output to
/// this specified handle.
///
/// Note that this does not need to be called for all new tasks; the default
/// output handle is to the process's stdout stream.
pub fn set_stdout(stdout: Box<Writer + Send>) -> Option<Box<Writer + Send>> {
    local_stdout.replace(Some(stdout)).and_then(|mut s| {
        let _ = s.flush();
        Some(s)
    })
}

/// Resets the task-local stderr handle to the specified writer
///
/// This will replace the current task's stderr handle, returning the old
/// handle. Currently, the stderr handle is used for printing failure messages
/// during task failure.
///
/// Note that this does not need to be called for all new tasks; the default
/// output handle is to the process's stderr stream.
pub fn set_stderr(stderr: Box<Writer + Send>) -> Option<Box<Writer + Send>> {
    local_stderr.replace(Some(stderr)).and_then(|mut s| {
        let _ = s.flush();
        Some(s)
    })
}

// Helper to access the local task's stdout handle
//
// Note that this is not a safe function to expose because you can create an
// aliased pointer very easily:
//
//  with_task_stdout(|io1| {
//      with_task_stdout(|io2| {
//          // io1 aliases io2
//      })
//  })
fn with_task_stdout(f: |&mut Writer| -> IoResult<()>) {
    let result = if Local::exists(None::<Task>) {
        let mut my_stdout = local_stdout.replace(None).unwrap_or_else(|| {
            box stdout() as Box<Writer + Send>
        });
        let result = f(my_stdout);
        local_stdout.replace(Some(my_stdout));
        result
    } else {
        let mut io = rt::Stdout;
        f(&mut io as &mut Writer)
    };
    match result {
        Ok(()) => {}
        Err(e) => fail!("failed printing to stdout: {}", e),
    }
}

/// Flushes the local task's stdout handle.
///
/// By default, this stream is a line-buffering stream, so flushing may be
/// necessary to ensure that all output is printed to the screen (if there are
/// no newlines printed).
///
/// Note that logging macros do not use this stream. Using the logging macros
/// will emit output to stderr, and while they are line buffered the log
/// messages are always terminated in a newline (no need to flush).
pub fn flush() {
    with_task_stdout(|io| io.flush())
}

/// Prints a string to the stdout of the current process. No newline is emitted
/// after the string is printed.
pub fn print(s: &str) {
    with_task_stdout(|io| io.write(s.as_bytes()))
}

/// Prints a string to the stdout of the current process. A literal
/// `\n` character is printed to the console after the string.
pub fn println(s: &str) {
    with_task_stdout(|io| {
        io.write(s.as_bytes()).and_then(|()| io.write(['\n' as u8]))
    })
}

/// Similar to `print`, but takes a `fmt::Arguments` structure to be compatible
/// with the `format_args!` macro.
pub fn print_args(fmt: &fmt::Arguments) {
    with_task_stdout(|io| write!(io, "{}", fmt))
}

/// Similar to `println`, but takes a `fmt::Arguments` structure to be
/// compatible with the `format_args!` macro.
pub fn println_args(fmt: &fmt::Arguments) {
    with_task_stdout(|io| writeln!(io, "{}", fmt))
}

/// Representation of a reader of a standard input stream
pub struct StdReader {
    inner: StdSource
}

impl StdReader {
    /// Returns whether this stream is attached to a TTY instance or not.
    pub fn isatty(&self) -> bool {
        match self.inner {
            TTY(..) => true,
            File(..) => false,
        }
    }
}

impl Reader for StdReader {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        let ret = match self.inner {
            TTY(ref mut tty) => {
                // Flush the task-local stdout so that weird issues like a
                // print!'d prompt not being shown until after the user hits
                // enter.
                flush();
                tty.read(buf)
            },
            File(ref mut file) => file.read(buf).map(|i| i as uint),
        }.map_err(IoError::from_rtio_error);
        match ret {
            // When reading a piped stdin, libuv will return 0-length reads when
            // stdin reaches EOF. For pretty much all other streams it will
            // return an actual EOF error, but apparently for stdin it's a
            // little different. Hence, here we convert a 0 length read to an
            // end-of-file indicator so the caller knows to stop reading.
            Ok(0) => { Err(standard_error(EndOfFile)) }
            ret @ Ok(..) | ret @ Err(..) => ret,
        }
    }
}

/// Representation of a writer to a standard output stream
pub struct StdWriter {
    inner: StdSource
}

impl StdWriter {
    /// Gets the size of this output window, if possible. This is typically used
    /// when the writer is attached to something like a terminal, this is used
    /// to fetch the dimensions of the terminal.
    ///
    /// If successful, returns `Ok((width, height))`.
    ///
    /// # Error
    ///
    /// This function will return an error if the output stream is not actually
    /// connected to a TTY instance, or if querying the TTY instance fails.
    pub fn winsize(&mut self) -> IoResult<(int, int)> {
        match self.inner {
            TTY(ref mut tty) => {
                tty.get_winsize().map_err(IoError::from_rtio_error)
            }
            File(..) => {
                Err(IoError {
                    kind: OtherIoError,
                    desc: "stream is not a tty",
                    detail: None,
                })
            }
        }
    }

    /// Controls whether this output stream is a "raw stream" or simply a normal
    /// stream.
    ///
    /// # Error
    ///
    /// This function will return an error if the output stream is not actually
    /// connected to a TTY instance, or if querying the TTY instance fails.
    pub fn set_raw(&mut self, raw: bool) -> IoResult<()> {
        match self.inner {
            TTY(ref mut tty) => {
                tty.set_raw(raw).map_err(IoError::from_rtio_error)
            }
            File(..) => {
                Err(IoError {
                    kind: OtherIoError,
                    desc: "stream is not a tty",
                    detail: None,
                })
            }
        }
    }

    /// Returns whether this stream is attached to a TTY instance or not.
    pub fn isatty(&self) -> bool {
        match self.inner {
            TTY(..) => true,
            File(..) => false,
        }
    }
}

impl Writer for StdWriter {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        // As with stdin on windows, stdout often can't handle writes of large
        // sizes. For an example, see #14940. For this reason, chunk the output
        // buffer on windows, but on unix we can just write the whole buffer all
        // at once.
        let max_size = if cfg!(windows) {64 * 1024} else {uint::MAX};
        for chunk in buf.chunks(max_size) {
            try!(match self.inner {
                TTY(ref mut tty) => tty.write(chunk),
                File(ref mut file) => file.write(chunk),
            }.map_err(IoError::from_rtio_error))
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    iotest!(fn smoke() {
        // Just make sure we can acquire handles
        stdin();
        stdout();
        stderr();
    })

    iotest!(fn capture_stdout() {
        use io::{ChanReader, ChanWriter};

        let (tx, rx) = channel();
        let (mut r, w) = (ChanReader::new(rx), ChanWriter::new(tx));
        spawn(proc() {
            set_stdout(box w);
            println!("hello!");
        });
        assert_eq!(r.read_to_string().unwrap(), "hello!\n".to_string());
    })

    iotest!(fn capture_stderr() {
        use realstd::comm::channel;
        use realstd::io::{Writer, ChanReader, ChanWriter, Reader};

        let (tx, rx) = channel();
        let (mut r, w) = (ChanReader::new(rx), ChanWriter::new(tx));
        spawn(proc() {
            ::realstd::io::stdio::set_stderr(box w);
            fail!("my special message");
        });
        let s = r.read_to_string().unwrap();
        assert!(s.as_slice().contains("my special message"));
    })
}
<|endoftext|>


<commit_before><commit_msg>Properly remove peer from cio on proto error<commit_after><|endoftext|>


<commit_before><commit_msg>Better contextual information<commit_after><|endoftext|>


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

//! Tests for async mode.. should be run with RUST_TEST_THREADS=1

pub mod common;

//mines for a bit on each available plugin, one after the other
#[test]
fn on_commit_mine_single_plugin_async() {
	let caps = common::get_plugin_vec("");
	for c in &caps {
		let mut plugin_path_vec:Vec<&str> = Vec::new();
		plugin_path_vec.push(&c.full_path);
		common::mine_async_for_duration(plugin_path_vec, 30, None);
	}
}

//Same as above, but only for cuda
#[test]
fn on_cuda_commit_mine_single_plugin_async() {
	let caps = common::get_plugin_vec("cuda");
	for c in &caps {
	 let mut plugin_path_vec:Vec<&str> = Vec::new();
		plugin_path_vec.push(&c.full_path);
		common::mine_async_for_duration(plugin_path_vec, 60, None);
	}
}

//mine cuda and matrix (mean) miner for a bit
#[test]
fn on_cuda_commit_mine_mean_cpu_and_lean_cuda_async() {
	let caps = common::get_plugin_vec("");
	let mut plugin_path_vec:Vec<&str> = Vec::new();
	for c in &caps {
		if c.full_path.contains("lean_cuda_30") || c.full_path.contains("mean_cpu_30"){
			plugin_path_vec.push(&c.full_path);
		}
	}
	common::mine_async_for_duration(plugin_path_vec, 180, None);
}

//Mines for a bit on all available plugins at once
//(won't be efficient, but should stress-tes plugins nicely)
#[test]
fn on_commit_mine_all_plugins_async() {
	// Get a list of installed plugins and capabilities
	// only do cuckoo 30s
	let caps = common::get_plugin_vec("30");
	let mut plugin_path_vec:Vec<&str> = Vec::new();
	for c in &caps {
		plugin_path_vec.push(&c.full_path);
	}
	common::mine_async_for_duration(plugin_path_vec, 120, None);
}
<commit_msg>more scaling back tests due to memory limits<commit_after>// Copyright 2017 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

//! Tests for async mode.. should be run with RUST_TEST_THREADS=1

pub mod common;

//mines for a bit on each available plugin, one after the other
#[test]
fn on_commit_mine_single_plugin_async() {
	let caps = common::get_plugin_vec("");
	for c in &caps {
		let mut plugin_path_vec:Vec<&str> = Vec::new();
		plugin_path_vec.push(&c.full_path);
		common::mine_async_for_duration(plugin_path_vec, 30, None);
	}
}

//Same as above, but only for cuda
#[test]
fn on_cuda_commit_mine_single_plugin_async() {
	let caps = common::get_plugin_vec("cuda");
	for c in &caps {
	 let mut plugin_path_vec:Vec<&str> = Vec::new();
		plugin_path_vec.push(&c.full_path);
		common::mine_async_for_duration(plugin_path_vec, 60, None);
	}
}

//mine cuda and matrix (mean) miner for a bit
#[test]
fn on_cuda_commit_mine_mean_cpu_and_lean_cuda_async() {
	let caps = common::get_plugin_vec("");
	let mut plugin_path_vec:Vec<&str> = Vec::new();
	for c in &caps {
		if c.full_path.contains("lean_cuda_30") || c.full_path.contains("mean_cpu_30"){
			plugin_path_vec.push(&c.full_path);
		}
	}
	common::mine_async_for_duration(plugin_path_vec, 180, None);
}

//Mines for a bit on all available plugins at once
//(won't be efficient, but should stress-tes plugins nicely)
#[test]
fn on_commit_mine_plugins_async() {
	// Get a list of installed plugins and capabilities
	// only do cuckoo 30s
	let caps = common::get_plugin_vec("30");
	let mut plugin_path_vec:Vec<&str> = Vec::new();
	for c in &caps {
		//Have to confine this for the time being to 2, due to travis CI memory constraints
		if c.full_path.contains("lean_cuda_30") || c.full_path.contains("mean_cpu_30"){
			plugin_path_vec.push(&c.full_path);
		}
	}
	common::mine_async_for_duration(plugin_path_vec, 120, None);
}
<|endoftext|>


<commit_before>use types::{BeaconStateError as Error, *};

/// Process slashings.
///
/// Spec v0.5.1
pub fn process_slashings<T: EthSpec>(
    state: &mut BeaconState<T>,
    current_total_balance: u64,
    spec: &ChainSpec,
) -> Result<(), Error> {
    let current_epoch = state.current_epoch(spec);

    let total_at_start = state.get_slashed_balance(current_epoch + 1)?;
    let total_at_end = state.get_slashed_balance(current_epoch)?;
    let total_penalities = total_at_end - total_at_start;

    for (index, validator) in state.validator_registry.iter().enumerate() {
        let should_penalize = current_epoch.as_usize()
            == validator.withdrawable_epoch.as_usize() - T::LatestSlashedExitLength::to_usize() / 2;

        if validator.slashed && should_penalize {
            let effective_balance = state.get_effective_balance(index, spec)?;

            let penalty = std::cmp::max(
                effective_balance * std::cmp::min(total_penalities * 3, current_total_balance)
                    / current_total_balance,
                effective_balance / 1, /* FIXME(sproul): spec.min_penalty_quotient, */
            );

            state.balances[index] -= penalty;
        }
    }

    Ok(())
}
<commit_msg>state_processing: process_slashings v0.6.1<commit_after>use types::{BeaconStateError as Error, *};

/// Process slashings.
///
/// Spec v0.6.1
pub fn process_slashings<T: EthSpec>(
    state: &mut BeaconState<T>,
    current_total_balance: u64,
    spec: &ChainSpec,
) -> Result<(), Error> {
    let current_epoch = state.current_epoch(spec);

    let total_at_start = state.get_slashed_balance(current_epoch + 1)?;
    let total_at_end = state.get_slashed_balance(current_epoch)?;
    let total_penalities = total_at_end - total_at_start;

    for (index, validator) in state.validator_registry.iter().enumerate() {
        let should_penalize = current_epoch.as_usize()
            == validator.withdrawable_epoch.as_usize() - T::LatestSlashedExitLength::to_usize() / 2;

        if validator.slashed && should_penalize {
            let effective_balance = state.get_effective_balance(index, spec)?;

            let penalty = std::cmp::max(
                effective_balance * std::cmp::min(total_penalities * 3, current_total_balance)
                    / current_total_balance,
                effective_balance / spec.min_slashing_penalty_quotient,
            );

            safe_sub_assign!(state.balances[index], penalty);
        }
    }

    Ok(())
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::path;
use toml;
use game::*;
use direction::*;

type StringControlSpec = HashMap<String, String>;

impl<'a> From<&'a ControlMap> for StringControlSpec {
    fn from(map: &'a ControlMap) -> Self {
        let mut spec = StringControlSpec::new();

        for (input_event, control) in map.iter() {
            spec.insert(String::from(*control), String::from(*input_event));
        }

        spec
    }
}

impl<'a> From<&'a StringControlSpec> for ControlMap {
    fn from(spec: &'a StringControlSpec) -> Self {
        let mut map = ControlMap::new();

        for (control, input) in spec.iter() {
            map.insert(InputEvent::from(input), Control::from(control));
        }

        map
    }
}

impl<'a> From<&'a String> for Control {
    fn from(s: &'a String) -> Self {
        match s.as_ref() {
            "North" => Control::Direction(Direction::North),
            "South" => Control::Direction(Direction::South),
            "East" => Control::Direction(Direction::East),
            "West" => Control::Direction(Direction::West),
            "Use" => Control::Use,
            "Close" => Control::Close,
            "Examine" => Control::Examine,
            "Wait" => Control::Wait,
            "Fire" => Control::Fire,
            "NextTarget" => Control::NextTarget,
            "PrevTarget" => Control::PrevTarget,
            "DisplayMessageLog" => Control::DisplayMessageLog,
            "Pause" => Control::Pause,
            _ => panic!("No such control: {}", s),
        }
    }
}

impl From<Control> for String {
    fn from(control: Control) -> Self {
        match control {
            Control::Direction(Direction::North) => "North",
            Control::Direction(Direction::South) => "South",
            Control::Direction(Direction::East) => "East",
            Control::Direction(Direction::West) => "West",
            Control::Use => "Use",
            Control::Close => "Close",
            Control::Examine => "Examine",
            Control::Wait => "Wait",
            Control::Fire => "Fire",
            Control::NextTarget => "NextTarget",
            Control::PrevTarget => "PrevTarget",
            Control::DisplayMessageLog => "DisplayMessageLog",
            Control::Pause => "Pause",
            _ => panic!("Unencodable control: {:?}", control),
        }.to_string()
    }
}

impl From<InputEvent> for String {
    fn from(input: InputEvent) -> Self {
        match input {
            InputEvent::Char(c) => return format!("{}", c),
            InputEvent::Up => "Up",
            InputEvent::Down => "Down",
            InputEvent::Left => "Left",
            InputEvent::Right => "Right",
            InputEvent::Escape => "Escape",
            InputEvent::Return => "Return",
            InputEvent::Space => "Space",
            InputEvent::Quit => panic!("Quit is not a key"),
        }.to_string()
    }
}

impl<'a> From<&'a String> for InputEvent {
    fn from(s: &'a String) -> Self {
        match s.as_ref() {
            "Up" => return InputEvent::Up,
            "Down" => return InputEvent::Down,
            "Left" => return InputEvent::Left,
            "Right" => return InputEvent::Right,
            "Escape" => return InputEvent::Escape,
            "Return" => return InputEvent::Return,
            "Space" => return InputEvent::Space,
            _ => (),
        }

        if s.len() == 1 {
            if let Some(c) = s.chars().next() {
                return InputEvent::Char(c);
            }
        }

        panic!("No such input: {}", s);
    }
}

fn parse_control(name: &str) -> Option<Control> {

    let control = match name {
        "North" => Control::Direction(Direction::North),
        "South" => Control::Direction(Direction::South),
        "East" => Control::Direction(Direction::East),
        "West" => Control::Direction(Direction::West),
        "Use" => Control::Use,
        "Close" => Control::Close,
        "Examine" => Control::Examine,
        "Wait" => Control::Wait,
        "Fire" => Control::Fire,
        "NextTarget" => Control::NextTarget,
        "PrevTarget" => Control::PrevTarget,
        "DisplayMessageLog" => Control::DisplayMessageLog,
        "Pause" => Control::Pause,
        _ => return None,
    };

    Some(control)
}

fn parse_input_event(string: &str) -> Option<InputEvent> {
    match string {
        "Up" => return Some(InputEvent::Up),
        "Down" => return Some(InputEvent::Down),
        "Left" => return Some(InputEvent::Left),
        "Right" => return Some(InputEvent::Right),
        "Escape" => return Some(InputEvent::Escape),
        "Return" => return Some(InputEvent::Return),
        _ => {},
    }

    if string.len() == 1 {
        if let Some(c) = string.chars().next() {
            return Some(InputEvent::Char(c));
        }
    }

    None
}

fn from_toml(table: toml::value::Table) -> Option<ControlMap> {
    table.get("controls")
        .and_then(|t| t.as_table())
        .map(|controls| {
            let mut control_map = ControlMap::new();

            for (control_str, input_event_str) in controls.iter() {
                if let Some(control) = parse_control(control_str.as_str()) {
                    if let Some(input_event) = input_event_str.as_str().and_then(parse_input_event) {
                        control_map.insert(input_event, control);
                    }
                }
            }

            control_map
        })
}

pub fn from_file<P: AsRef<path::Path>>(path: P) -> Option<ControlMap> {
    let spec: Option<StringControlSpec> = game_file::read_toml(path).ok();
    spec.as_ref().map(ControlMap::from)
}

pub fn to_file<P: AsRef<path::Path>>(path: P, map: &ControlMap) {
    game_file::write_toml(path, &StringControlSpec::from(map))
        .expect("Failed to write controls file");
}
<commit_msg>Removed dead code<commit_after>use std::collections::HashMap;
use std::path;
use toml;
use game::*;
use direction::*;

type StringControlSpec = HashMap<String, String>;

impl<'a> From<&'a ControlMap> for StringControlSpec {
    fn from(map: &'a ControlMap) -> Self {
        let mut spec = StringControlSpec::new();

        for (input_event, control) in map.iter() {
            spec.insert(String::from(*control), String::from(*input_event));
        }

        spec
    }
}

impl<'a> From<&'a StringControlSpec> for ControlMap {
    fn from(spec: &'a StringControlSpec) -> Self {
        let mut map = ControlMap::new();

        for (control, input) in spec.iter() {
            map.insert(InputEvent::from(input), Control::from(control));
        }

        map
    }
}

impl<'a> From<&'a String> for Control {
    fn from(s: &'a String) -> Self {
        match s.as_ref() {
            "North" => Control::Direction(Direction::North),
            "South" => Control::Direction(Direction::South),
            "East" => Control::Direction(Direction::East),
            "West" => Control::Direction(Direction::West),
            "Use" => Control::Use,
            "Close" => Control::Close,
            "Examine" => Control::Examine,
            "Wait" => Control::Wait,
            "Fire" => Control::Fire,
            "NextTarget" => Control::NextTarget,
            "PrevTarget" => Control::PrevTarget,
            "DisplayMessageLog" => Control::DisplayMessageLog,
            "Pause" => Control::Pause,
            _ => panic!("No such control: {}", s),
        }
    }
}

impl From<Control> for String {
    fn from(control: Control) -> Self {
        match control {
            Control::Direction(Direction::North) => "North",
            Control::Direction(Direction::South) => "South",
            Control::Direction(Direction::East) => "East",
            Control::Direction(Direction::West) => "West",
            Control::Use => "Use",
            Control::Close => "Close",
            Control::Examine => "Examine",
            Control::Wait => "Wait",
            Control::Fire => "Fire",
            Control::NextTarget => "NextTarget",
            Control::PrevTarget => "PrevTarget",
            Control::DisplayMessageLog => "DisplayMessageLog",
            Control::Pause => "Pause",
            _ => panic!("Unencodable control: {:?}", control),
        }.to_string()
    }
}

impl From<InputEvent> for String {
    fn from(input: InputEvent) -> Self {
        match input {
            InputEvent::Char(c) => return format!("{}", c),
            InputEvent::Up => "Up",
            InputEvent::Down => "Down",
            InputEvent::Left => "Left",
            InputEvent::Right => "Right",
            InputEvent::Escape => "Escape",
            InputEvent::Return => "Return",
            InputEvent::Space => "Space",
            InputEvent::Quit => panic!("Quit is not a key"),
        }.to_string()
    }
}

impl<'a> From<&'a String> for InputEvent {
    fn from(s: &'a String) -> Self {
        match s.as_ref() {
            "Up" => return InputEvent::Up,
            "Down" => return InputEvent::Down,
            "Left" => return InputEvent::Left,
            "Right" => return InputEvent::Right,
            "Escape" => return InputEvent::Escape,
            "Return" => return InputEvent::Return,
            "Space" => return InputEvent::Space,
            _ => (),
        }

        if s.len() == 1 {
            if let Some(c) = s.chars().next() {
                return InputEvent::Char(c);
            }
        }

        panic!("No such input: {}", s);
    }
}

pub fn from_file<P: AsRef<path::Path>>(path: P) -> Option<ControlMap> {
    let spec: Option<StringControlSpec> = game_file::read_toml(path).ok();
    spec.as_ref().map(ControlMap::from)
}

pub fn to_file<P: AsRef<path::Path>>(path: P, map: &ControlMap) {
    game_file::write_toml(path, &StringControlSpec::from(map))
        .expect("Failed to write controls file");
}
<|endoftext|>


<commit_before>use std::io::IoResult;
use std::collections::hashmap::HashMap;
use std::str::from_utf8;

use super::{get_file_reader, get_file_writer};

macro_rules! parse_word(
    ($iter:ident, $word:ident, $breaker:pat, $next:expr) => (
        match $iter.next() {
            Some(Ok($breaker)) => break,
            Some(Ok(c)) => $word.push(c),
            Some(Err(e)) => return Err(e),
            None => $next
        }
    );
)

pub fn generate(list: Path, module: Path) -> IoResult<()> {
    let mut reader = get_file_reader(list);
    let mut writer = get_file_writer(module);

    try!(writer.write(
b"// This automatically generated file is included in response.rs.
use std::path::BytesContainer;

use http::headers::content_type::MediaType;

pub fn get_content_type(path: &Path) -> Option<MediaType> {
    let path_str = path.container_as_str().unwrap();
    let ext_pos = regex!(\".[a-z0-9]+$\").find(path_str);
    let mut ext;
    match ext_pos {
        Some((start, _)) => {
            ext = path_str.as_slice().slice_from(start);
        },
        None => return None
    }

    match ext {
"   ));

    /* Generated snippets will look like:
    "json" => Some(MediaType {
        type_: "application".to_str(),
        subtype: "json".to_str(),
        parameters: vec![]
    }),
    */

    let mut byter = reader.bytes();
    // avoid duplicates
    let mut seen = HashMap::new();
    'read: loop {
        let mut ext = vec![];
        let mut type_ = vec![];
        let mut subtype = vec![];

        loop { parse_word!(byter, ext, b' ', break 'read); }
        loop { parse_word!(byter, type_, b' ', break 'read); }
        loop{ parse_word!(byter, subtype, b'\n', break 'read); }

        if !seen.contains_key(&ext) {

            try!(write!(writer,
"    \"{}\" => Some(MediaType {{
        type_: \"{}\".to_str(),
        subtype: \"{}\".to_str(),
        parameters: vec![]
    }}),\n", from_utf8(ext.as_slice()).unwrap(),
             from_utf8(type_.as_slice()).unwrap(),
             from_utf8(subtype.as_slice()).unwrap()));

            seen.insert(ext, true);
        }
    }

    writer.write(b"        _ => None\n    }\n}\n")
}
<commit_msg>(feat) Refactored to modularize generator.<commit_after>use std::io::IoResult;
use std::collections::hashmap::HashMap;
use std::str::from_utf8;

use super::{get_file_reader, get_file_writer};

macro_rules! parse_word(
    ($iter:ident, $word:ident, $breaker:pat, $next:expr) => (
        // Loop to parse a word out of a line
        match $iter.next() {
            Some(Ok($breaker)) => break,
            Some(Ok(c)) => $word.push(c),
            Some(Err(e)) => return Err(e),
            None => $next
        }
    );
)

// Generate response/mimegen.rs
pub fn generate(list: Path, module: Path) -> IoResult<()> {
    let mut reader = get_file_reader(list);
    let mut writer = get_file_writer(module);

    try!(writer.write(
b"// This automatically generated file is included in response/mimes.rs.

use http::headers::content_type::MediaType;

pub fn get_generated_content_type(ext: &str) -> Option<MediaType> {
    match ext {
"   ));

    /* Generated snippets will look like:
    "json" => Some(MediaType {
        type_: "application".to_str(),
        subtype: "json".to_str(),
        parameters: vec![]
    }),
    */

    let mut byter = reader.bytes();
    // avoid duplicates
    let mut seen = HashMap::new();
    'read: loop {
        let mut ext = vec![];
        let mut type_ = vec![];
        let mut subtype = vec![];

        loop { parse_word!(byter, ext, b' ', break 'read); }
        loop { parse_word!(byter, type_, b' ', break 'read); }
        loop{ parse_word!(byter, subtype, b'\n', break 'read); }

        if !seen.contains_key(&ext) {

            try!(write!(writer,
"    \"{}\" => Some(MediaType {{
        type_: \"{}\".to_str(),
        subtype: \"{}\".to_str(),
        parameters: vec![]
    }}),\n", from_utf8(ext.as_slice()).unwrap(),
             from_utf8(type_.as_slice()).unwrap(),
             from_utf8(subtype.as_slice()).unwrap()));

            seen.insert(ext, true);
        }
    }

    writer.write(b"        _ => None\n    }\n}\n")
}
<|endoftext|>


<commit_before>extern crate termion;

use self::termion::event::Key;
use self::termion::input::TermRead;
use self::termion::raw::IntoRawMode;

use std::io::{Write, stdout, stdin};

pub fn main_loop() {

    let mut stdout = stdout().into_raw_mode().unwrap();

    write!(stdout,
           "{}{}",
           termion::cursor::Goto(1, 1),
           termion::clear::All)
        .unwrap();
    stdout.flush().unwrap();

    let mut quit = false;
    while !quit {
        let stdin = stdin();
        for c in stdin.keys() {

            write!(stdout,
                   "{}{}",
                   termion::cursor::Goto(1, 1),
                   termion::clear::All)
                .unwrap();

            // Print the key we type...
            match c.unwrap() {
                // Exit.
                Key::Char('q') => {
                    quit = true;
                    break;
                }
                Key::Char(c) => println!("{}", c),
                Key::Alt(c) => println!("Alt-{}", c),
                Key::Ctrl(c) => println!("Ctrl-{}", c),
                Key::Left => println!("<left>"),
                Key::Right => println!("<right>"),
                Key::Up => println!("<up>"),
                Key::Down => println!("<down>"),
                _ => println!("Other"),
            }

            // Flush again.
            stdout.flush().unwrap();
        }
    }
}
<commit_msg>continue to play with termion<commit_after>extern crate termion;

use self::termion::event::{Event, Key, MouseEvent};
use self::termion::input::{TermRead, MouseTerminal};
use self::termion::raw::IntoRawMode;
use self::termion::terminal_size;

use std::io::{self, Write, stdin};

pub fn main_loop() {

    let mut stdout = MouseTerminal::from(io::stdout().into_raw_mode().unwrap());

    write!(stdout,
           "{}{}",
           termion::cursor::Goto(1, 1),
           termion::clear::All)
        .unwrap();

    stdout.flush().unwrap();

    let mut quit = false;
    while !quit {
        let stdin = stdin();

        for evt in stdin.events() {
            let evt = evt.unwrap();

            write!(stdout,
                   "{}{}",
                   termion::clear::All,
                   termion::cursor::Goto(1, 1))
                .unwrap();

            let (width, height) = terminal_size().unwrap();

            println!("terminal size ({},{})\r", width, height);

            write!(stdout, "{}", termion::cursor::Goto(1, 2)).unwrap();

            // Print recieved Events...
            match evt {

                Event::Key(k) => {
                    match k {
                        // Exit.
                        Key::Char('q') => {
                            quit = true;
                            break;
                        }
                        Key::Char(c) => print!("{}", c),
                        Key::Alt(c) => print!("Alt-{}", c),
                        Key::Ctrl(c) => print!("Ctrl-{}", c),
                        Key::F(f) => print!("F{:?}", f),
                        Key::Left => print!("<left>"),
                        Key::Right => print!("<right>"),
                        Key::Up => print!("<up>"),
                        Key::Down => print!("<down>"),
                        Key::Backspace => print!("<backspace>"),
                        Key::Home => print!("<Home>"),
                        Key::End => print!("<End>"),
                        Key::PageUp => print!("<PageUp>"),
                        Key::PageDown => print!("<PageDown>"),
                        Key::Delete => print!("<Delete>"),
                        Key::Insert => print!("<Insert>"),
                        Key::Esc => print!("<Esc>"),

                        _ => print!("Other"),
                    }
                }

                Event::Mouse(m) => {
                    match m {
                        MouseEvent::Press(mb, x, y) => {
                            print!("MouseEvent::Press => MouseButton {:?} @ ({}, {})", mb, x, y);
                        }

                        MouseEvent::Release(x, y) => {
                            print!("MouseEvent::Release => @ ({}, {})", x, y);
                        }

                        MouseEvent::Hold(x, y) => {
                            print!("MouseEvent::Hold => @ ({}, {})", x, y);
                        }
                    }
                }

                Event::Unsupported(_) => {}
            }

            // Flush again.
            stdout.flush().unwrap();
        }
    }
}
<|endoftext|>