<commit_before>use ast::*;
use values::*;
use std::collections::HashMap;
use std::num::{Int, Float};

macro_rules! get_evald(
    ($parsed:expr) => ({
        match $parsed {
            Result::Ok(t) => t,
            Result::Err(e) => {return Result::Err(e);}
        }
    });
);

pub enum Result<T> {
    Ok(T),
    Err(String)
}

fn int_pow(lhs: i64, rhs: i64) -> i64 {
    if rhs >= 0 {
        lhs.pow(rhs as u32)
    } else {
        0
    }

}

fn eval_literal<'a>(literal: &'a Literal) -> Result<Value> {
    match literal {
        &Literal::Bool(b)       => Result::Ok(Value::Bool(b)),
        &Literal::Int(i)        => Result::Ok(Value::Int(i)),
        &Literal::Float(f)      => Result::Ok(Value::Float(f)),
        &Literal::String(s)     => Result::Ok(Value::String(Box::new(s.to_string()))),
        &Literal::Nil           => Result::Ok(Value::Nil),
        _ => panic!("literal not implemented yet!")
    }
}

fn get_value_from_scopes<'a>(scopes: &Vec<HashMap<&'a str, Value>>, name: &str) -> Option<Value>{
    for scope in scopes.iter().rev() {
        match scope.get(name) {
            Some(v) => {return Some((*v).clone())},
            None => {}
        }
    }
    None
}

pub fn eval_bin_op<'a>(lhs: &Value, rhs: &Value, op: &BinOp) -> Result<Value> {
    let result_val = match lhs {
        &Value::Int(lh_i) => {
            match *rhs {
                Value::Int(rh_i) => {
                    match op {
                        &BinOp::Add => Value::Int(lh_i + rh_i),
                        &BinOp::Sub => Value::Int(lh_i - rh_i),
                        &BinOp::Mul => Value::Int(lh_i * rh_i),
                        &BinOp::Div => Value::Int(lh_i / rh_i),
                        &BinOp::Mod => Value::Int(lh_i % rh_i),
                        &BinOp::Exp => Value::Int(int_pow(lh_i, rh_i)),
                        &BinOp::Lt => Value::Bool(lh_i < rh_i),
                        &BinOp::Lte => Value::Bool(lh_i <= rh_i),
                        &BinOp::Gt => Value::Bool(lh_i > rh_i),
                        &BinOp::Gte => Value::Bool(lh_i >= rh_i),
                        &BinOp::Eq => Value::Bool(lh_i == rh_i),
                        &BinOp::Neq => Value::Bool(lh_i != rh_i),
                        &BinOp::Same => Value::Bool(lh_i == rh_i),
                        &BinOp::Nsame => Value::Bool(lh_i != rh_i),
                        op => return Result::Err(format!("EVAL FAILURE: {:?} is not valid for integers", op))
                    }
                },
                _ => return Result::Err(format!("EVAL FAILURE: RHS is not an integer"))
            }
        },
        &Value::Float(lh_f) => {
            match *rhs {
                Value::Float(rh_f) => {
                    match op {
                        &BinOp::Add => Value::Float(lh_f + rh_f),
                        &BinOp::Sub => Value::Float(lh_f - rh_f),
                        &BinOp::Mul => Value::Float(lh_f * rh_f),
                        &BinOp::Div => Value::Float(lh_f / rh_f),
                        &BinOp::Mod => Value::Float(lh_f % rh_f),
                        &BinOp::Exp => Value::Float(lh_f.powf(rh_f)),
                        &BinOp::Lt => Value::Bool(lh_f < rh_f),
                        &BinOp::Lte => Value::Bool(lh_f <= rh_f),
                        &BinOp::Gt => Value::Bool(lh_f > rh_f),
                        &BinOp::Gte => Value::Bool(lh_f >= rh_f),
                        &BinOp::Eq => Value::Bool(lh_f == rh_f),
                        &BinOp::Neq => Value::Bool(lh_f != rh_f),
                        &BinOp::Same => Value::Bool(lh_f == rh_f),
                        &BinOp::Nsame => Value::Bool(lh_f != rh_f),
                        op => return Result::Err(format!("EVAL FAILURE: {:?} is not valid for floats", op))
                    }
                },
                _ => return Result::Err(format!("EVAL FAILURE: RHS is not a float"))
            }
        },
        &Value::Bool(lh_b) => {
            match *rhs {
                Value::Bool(rh_b) => {
                    match op {
                        &BinOp::Eq => Value::Bool(lh_b == rh_b),
                        &BinOp::Neq => Value::Bool(lh_b != rh_b),
                        &BinOp::Same => Value::Bool(lh_b == rh_b),
                        &BinOp::Nsame => Value::Bool(lh_b != rh_b),
                        &BinOp::And => Value::Bool(lh_b && rh_b),
                        &BinOp::Or => Value::Bool(lh_b || rh_b),
                        op => return Result::Err(format!("EVAL FAILURE: {:?} is not valid for bools", op))
                    }
                },
                _ => return Result::Err(format!("EVAL FAILURE: RHS is not a bool"))
            }
        },
        &Value::String(ref lh_s) => {
            match *rhs {
                Value::String(ref rh_s) => {
                    match op {
                        &BinOp::Add => Value::String(Box::new(*lh_s.clone() + rh_s.as_slice())),
                        &BinOp::Eq => Value::Bool(lh_s == rh_s),
                        &BinOp::Neq => Value::Bool(lh_s != rh_s),
                        &BinOp::Same => Value::Bool(lh_s == rh_s),
                        &BinOp::Nsame => Value::Bool(lh_s != rh_s),
                        op => return Result::Err(format!("EVAL FAILURE: {:?} is not valid for strings", op))
                    }
                },
                _ => return Result::Err(format!("EVAL FAILURE: RHS is not a string"))
            }
        },
        _ => panic!("bin op lhs not implemented yet")
    };
    Result::Ok(result_val)
}

pub fn eval_expr<'a>(expr: &'a Expr, scopes: &Vec<HashMap<&'a str, Value>>) -> Result<Value> {
    match expr {
        &Expr::Literal(ref l) => Result::Ok(get_evald!(eval_literal(l))),
        &Expr::Ident(ref s) => {
            let val = get_value_from_scopes(scopes, &(**s));
            match val {
                Some(v) => Result::Ok(v),
                None => Result::Err(format!("EVAL FAILURE: {} is not in the current scope", s))
            }
        },
        &Expr::BinOp(ref op, ref lhs, ref rhs) => {
            let lh_val = get_evald!(eval_expr(lhs, scopes));
            let rh_val = get_evald!(eval_expr(rhs, scopes));
            match (&lh_val, &rh_val) {
                (&Value::Tuple(ref lh_vec), &Value::Tuple(ref rh_vec)) => {
                    if lh_vec.len() != rh_vec.len() {
                        return Result::Err(format!("EVAL FAILURE: tuples are not the same length"));
                    }
                    let mut result_vec = Vec::new();
                    for (ref lh, ref rh) in lh_vec.iter().zip(rh_vec.iter()) {
                        result_vec.push(get_evald!(eval_bin_op(lh, rh, op)));
                    }
                    Result::Ok(Value::Tuple(result_vec))
                }
                (&Value::Tuple(_), _) | (_, &Value::Tuple(_)) => Result::Err(format!("EVAL FAILURE: both sides must be tuples")),
                (ref lhs, ref rhs) => {
                    eval_bin_op(lhs, rhs, op)
                }
            }
        }
        _ => panic!("expr not implemented yet!")
    }
}

fn eval_expr_as_ident<'a>(expr: &'a Expr) -> Result<&'a str> {
    match expr {
        &Expr::Ident(ref s) => Result::Ok(s),
        _ => panic!("expr as ident not implemented yet!")
    }
}

fn eval_stmt_item<'a>(stmt_item: &'a StmtItem, scopes: &Vec<HashMap<&'a str, Value>>) -> Result<Value> {
    match stmt_item {
        &StmtItem::Bare(ref expr) => eval_expr(expr, scopes),
        _ => panic!("stmt_item not implemented yet!")
    }
}

fn assign<'a>(stmt_item: &'a StmtItem, value: Value, scopes: &mut Vec<HashMap<&'a str, Value>>, curr_scope: usize) -> Result<()> {
    match stmt_item {
        &StmtItem::Bare(ref e) => {
            let ident = get_evald!(eval_expr_as_ident(e));
            for scope in scopes.iter_mut().rev() {
                if scope.contains_key(ident) {
                    scope.insert(ident, value);
                    return Result::Ok(());
                }
            }
            return Result::Err(format!("EVAL FAILURE: '{}' is not declared in the current scope", ident));
        },
        &StmtItem::Var(ref s) => {
            if scopes[curr_scope].contains_key(s) {
                return Result::Err(format!("EVAL FAILURE: '{}' is already declared in the current scope", s));
            } else {
                scopes[curr_scope].insert(s, value);
            }
        }
        &StmtItem::Def(ref e) => {
            let ident = get_evald!(eval_expr_as_ident(e));
            if scopes[curr_scope].contains_key(ident) {
                return Result::Err(format!("EVAL FAILURE: '{}' is already defined in the current scope", ident));
            } else {
                scopes[curr_scope].insert(ident, value);
            }
        }
    }
    Result::Ok(())
}

fn eval_stmt<'a>(stmt: &'a Stmt, scopes: &mut Vec<HashMap<&'a str, Value>>) -> Result<Vec<Value>> {
    match stmt {
        &Stmt::Bare(ref items) => {
            let mut result_vec = vec![];
            for i in items.iter() {
                result_vec.push(get_evald!(eval_stmt_item(i, scopes)));
            }
            Result::Ok(result_vec)
        }
        &Stmt::Assignment(ref items, ref expr) => {
            let expr_value = get_evald!(eval_expr(expr, scopes));
            let curr_scope = scopes.len() - 1;
            match &expr_value {
                //TODO: the values shouldn't be cloned here - they should be moved directly into the scope
                &Value::Tuple(ref value_vec) => {
                    if items.len() == value_vec.len() {
                        for (i, e) in items.iter().zip(value_vec.iter()) {
                            get_evald!(assign(i, e.clone(), scopes, curr_scope));
                        }
                    } else if items.len() == 1 {
                        get_evald!(assign(&items[0], expr_value.clone(), scopes, curr_scope));
                    } else {
                        return Result::Err(format!("EVAL FAILURE: wrong arity for this assignment"));
                    }
                }
                _ => {
                    if items.len() == 1 {
                        get_evald!(assign(&items[0], expr_value.clone(), scopes, curr_scope));
                    } else {
                        return Result::Err(format!("EVAL FAILURE: too many idents to assign to"));
                    }
                }
            }
            Result::Ok(vec![])
        }
        &Stmt::While(ref e, ref stmt_list) => {
            scopes.push(HashMap::new());
            let mut result_vec = vec![];
            loop {
                let expr_val = get_evald!(eval_expr(e, scopes));
                match expr_val {
                    Value::Bool(b) => {
                        if !b {
                            break;
                        }
                    }
                    _ => {
                        return Result::Err(format!("EVAL FAILUTRE: while loops must contain a boolean expression"));
                    }
                }
                let vals = get_evald!(eval_stmt_list(stmt_list, scopes));
                for val in vals.into_iter() {
                    result_vec.push(val);
                }
            }
            Result::Ok(result_vec)
        }
        _ => panic!("stmt not implemented yet!")
    }
}

fn eval_stmt_list<'a>(stmt_list: &'a Vec<Stmt>, scopes: &mut Vec<HashMap<&'a str, Value>>) -> Result<Vec<Value>> {
    let mut ret_list = vec![];
    for st in stmt_list.iter() {
        let mut values = get_evald!(eval_stmt(st, scopes));
        ret_list.append(&mut values);
    }
    Result::Ok(ret_list)
}

pub fn eval_file_stmts<'a>(stmt_list: &'a Vec<Stmt>) -> Result<Vec<Value>> {
    let mut scopes = vec![HashMap::new()];
    eval_stmt_list(stmt_list, &mut scopes)
}
<commit_msg>Removed unnecessary cloning<commit_after>use ast::*;
use values::*;
use std::collections::HashMap;
use std::num::{Int, Float};

macro_rules! get_evald(
    ($parsed:expr) => ({
        match $parsed {
            Result::Ok(t) => t,
            Result::Err(e) => {return Result::Err(e);}
        }
    });
);

pub enum Result<T> {
    Ok(T),
    Err(String)
}

fn int_pow(lhs: i64, rhs: i64) -> i64 {
    if rhs >= 0 {
        lhs.pow(rhs as u32)
    } else {
        0
    }

}

fn eval_literal<'a>(literal: &'a Literal) -> Result<Value> {
    match literal {
        &Literal::Bool(b)       => Result::Ok(Value::Bool(b)),
        &Literal::Int(i)        => Result::Ok(Value::Int(i)),
        &Literal::Float(f)      => Result::Ok(Value::Float(f)),
        &Literal::String(s)     => Result::Ok(Value::String(Box::new(s.to_string()))),
        &Literal::Nil           => Result::Ok(Value::Nil),
        _ => panic!("literal not implemented yet!")
    }
}

fn get_value_from_scopes<'a>(scopes: &Vec<HashMap<&'a str, Value>>, name: &str) -> Option<Value>{
    for scope in scopes.iter().rev() {
        match scope.get(name) {
            Some(v) => {return Some((*v).clone())},
            None => {}
        }
    }
    None
}

pub fn eval_bin_op<'a>(lhs: &Value, rhs: &Value, op: &BinOp) -> Result<Value> {
    let result_val = match lhs {
        &Value::Int(lh_i) => {
            match *rhs {
                Value::Int(rh_i) => {
                    match op {
                        &BinOp::Add => Value::Int(lh_i + rh_i),
                        &BinOp::Sub => Value::Int(lh_i - rh_i),
                        &BinOp::Mul => Value::Int(lh_i * rh_i),
                        &BinOp::Div => Value::Int(lh_i / rh_i),
                        &BinOp::Mod => Value::Int(lh_i % rh_i),
                        &BinOp::Exp => Value::Int(int_pow(lh_i, rh_i)),
                        &BinOp::Lt => Value::Bool(lh_i < rh_i),
                        &BinOp::Lte => Value::Bool(lh_i <= rh_i),
                        &BinOp::Gt => Value::Bool(lh_i > rh_i),
                        &BinOp::Gte => Value::Bool(lh_i >= rh_i),
                        &BinOp::Eq => Value::Bool(lh_i == rh_i),
                        &BinOp::Neq => Value::Bool(lh_i != rh_i),
                        &BinOp::Same => Value::Bool(lh_i == rh_i),
                        &BinOp::Nsame => Value::Bool(lh_i != rh_i),
                        op => return Result::Err(format!("EVAL FAILURE: {:?} is not valid for integers", op))
                    }
                },
                _ => return Result::Err(format!("EVAL FAILURE: RHS is not an integer"))
            }
        },
        &Value::Float(lh_f) => {
            match *rhs {
                Value::Float(rh_f) => {
                    match op {
                        &BinOp::Add => Value::Float(lh_f + rh_f),
                        &BinOp::Sub => Value::Float(lh_f - rh_f),
                        &BinOp::Mul => Value::Float(lh_f * rh_f),
                        &BinOp::Div => Value::Float(lh_f / rh_f),
                        &BinOp::Mod => Value::Float(lh_f % rh_f),
                        &BinOp::Exp => Value::Float(lh_f.powf(rh_f)),
                        &BinOp::Lt => Value::Bool(lh_f < rh_f),
                        &BinOp::Lte => Value::Bool(lh_f <= rh_f),
                        &BinOp::Gt => Value::Bool(lh_f > rh_f),
                        &BinOp::Gte => Value::Bool(lh_f >= rh_f),
                        &BinOp::Eq => Value::Bool(lh_f == rh_f),
                        &BinOp::Neq => Value::Bool(lh_f != rh_f),
                        &BinOp::Same => Value::Bool(lh_f == rh_f),
                        &BinOp::Nsame => Value::Bool(lh_f != rh_f),
                        op => return Result::Err(format!("EVAL FAILURE: {:?} is not valid for floats", op))
                    }
                },
                _ => return Result::Err(format!("EVAL FAILURE: RHS is not a float"))
            }
        },
        &Value::Bool(lh_b) => {
            match *rhs {
                Value::Bool(rh_b) => {
                    match op {
                        &BinOp::Eq => Value::Bool(lh_b == rh_b),
                        &BinOp::Neq => Value::Bool(lh_b != rh_b),
                        &BinOp::Same => Value::Bool(lh_b == rh_b),
                        &BinOp::Nsame => Value::Bool(lh_b != rh_b),
                        &BinOp::And => Value::Bool(lh_b && rh_b),
                        &BinOp::Or => Value::Bool(lh_b || rh_b),
                        op => return Result::Err(format!("EVAL FAILURE: {:?} is not valid for bools", op))
                    }
                },
                _ => return Result::Err(format!("EVAL FAILURE: RHS is not a bool"))
            }
        },
        &Value::String(ref lh_s) => {
            match *rhs {
                Value::String(ref rh_s) => {
                    match op {
                        &BinOp::Add => Value::String(Box::new(*lh_s.clone() + rh_s.as_slice())),
                        &BinOp::Eq => Value::Bool(lh_s == rh_s),
                        &BinOp::Neq => Value::Bool(lh_s != rh_s),
                        &BinOp::Same => Value::Bool(lh_s == rh_s),
                        &BinOp::Nsame => Value::Bool(lh_s != rh_s),
                        op => return Result::Err(format!("EVAL FAILURE: {:?} is not valid for strings", op))
                    }
                },
                _ => return Result::Err(format!("EVAL FAILURE: RHS is not a string"))
            }
        },
        _ => panic!("bin op lhs not implemented yet")
    };
    Result::Ok(result_val)
}

pub fn eval_expr<'a>(expr: &'a Expr, scopes: &Vec<HashMap<&'a str, Value>>) -> Result<Value> {
    match expr {
        &Expr::Literal(ref l) => Result::Ok(get_evald!(eval_literal(l))),
        &Expr::Ident(ref s) => {
            let val = get_value_from_scopes(scopes, &(**s));
            match val {
                Some(v) => Result::Ok(v),
                None => Result::Err(format!("EVAL FAILURE: {} is not in the current scope", s))
            }
        },
        &Expr::BinOp(ref op, ref lhs, ref rhs) => {
            let lh_val = get_evald!(eval_expr(lhs, scopes));
            let rh_val = get_evald!(eval_expr(rhs, scopes));
            match (&lh_val, &rh_val) {
                (&Value::Tuple(ref lh_vec), &Value::Tuple(ref rh_vec)) => {
                    if lh_vec.len() != rh_vec.len() {
                        return Result::Err(format!("EVAL FAILURE: tuples are not the same length"));
                    }
                    let mut result_vec = Vec::new();
                    for (ref lh, ref rh) in lh_vec.iter().zip(rh_vec.iter()) {
                        result_vec.push(get_evald!(eval_bin_op(lh, rh, op)));
                    }
                    Result::Ok(Value::Tuple(result_vec))
                }
                (&Value::Tuple(_), _) | (_, &Value::Tuple(_)) => Result::Err(format!("EVAL FAILURE: both sides must be tuples")),
                (ref lhs, ref rhs) => {
                    eval_bin_op(lhs, rhs, op)
                }
            }
        }
        _ => panic!("expr not implemented yet!")
    }
}

fn eval_expr_as_ident<'a>(expr: &'a Expr) -> Result<&'a str> {
    match expr {
        &Expr::Ident(ref s) => Result::Ok(s),
        _ => panic!("expr as ident not implemented yet!")
    }
}

fn eval_stmt_item<'a>(stmt_item: &'a StmtItem, scopes: &Vec<HashMap<&'a str, Value>>) -> Result<Value> {
    match stmt_item {
        &StmtItem::Bare(ref expr) => eval_expr(expr, scopes),
        _ => panic!("stmt_item not implemented yet!")
    }
}

fn assign<'a>(stmt_item: &'a StmtItem, value: Value, scopes: &mut Vec<HashMap<&'a str, Value>>, curr_scope: usize) -> Result<()> {
    match stmt_item {
        &StmtItem::Bare(ref e) => {
            let ident = get_evald!(eval_expr_as_ident(e));
            for scope in scopes.iter_mut().rev() {
                if scope.contains_key(ident) {
                    scope.insert(ident, value);
                    return Result::Ok(());
                }
            }
            return Result::Err(format!("EVAL FAILURE: '{}' is not declared in the current scope", ident));
        },
        &StmtItem::Var(ref s) => {
            if scopes[curr_scope].contains_key(s) {
                return Result::Err(format!("EVAL FAILURE: '{}' is already declared in the current scope", s));
            } else {
                scopes[curr_scope].insert(s, value);
            }
        }
        &StmtItem::Def(ref e) => {
            let ident = get_evald!(eval_expr_as_ident(e));
            if scopes[curr_scope].contains_key(ident) {
                return Result::Err(format!("EVAL FAILURE: '{}' is already defined in the current scope", ident));
            } else {
                scopes[curr_scope].insert(ident, value);
            }
        }
    }
    Result::Ok(())
}

fn eval_stmt<'a>(stmt: &'a Stmt, scopes: &mut Vec<HashMap<&'a str, Value>>) -> Result<Vec<Value>> {
    match stmt {
        &Stmt::Bare(ref items) => {
            let mut result_vec = vec![];
            for i in items.iter() {
                result_vec.push(get_evald!(eval_stmt_item(i, scopes)));
            }
            Result::Ok(result_vec)
        }
        &Stmt::Assignment(ref items, ref expr) => {
            let expr_value = get_evald!(eval_expr(expr, scopes));
            let curr_scope = scopes.len() - 1;
            match expr_value {
                Value::Tuple(value_vec) => {
                    if items.len() == value_vec.len() {
                        for (i, e) in items.iter().zip(value_vec.into_iter()) {
                            get_evald!(assign(i, e, scopes, curr_scope));
                        }
                    } else if items.len() == 1 {
                        get_evald!(assign(&items[0], Value::Tuple(value_vec), scopes, curr_scope));
                    } else {
                        return Result::Err(format!("EVAL FAILURE: wrong arity for this assignment"));
                    }
                }
                _ => {
                    if items.len() == 1 {
                        get_evald!(assign(&items[0], expr_value, scopes, curr_scope));
                    } else {
                        return Result::Err(format!("EVAL FAILURE: too many idents to assign to"));
                    }
                }
            }
            Result::Ok(vec![])
        }
        &Stmt::While(ref e, ref stmt_list) => {
            scopes.push(HashMap::new());
            let mut result_vec = vec![];
            loop {
                let expr_val = get_evald!(eval_expr(e, scopes));
                match expr_val {
                    Value::Bool(b) => {
                        if !b {
                            break;
                        }
                    }
                    _ => {
                        return Result::Err(format!("EVAL FAILUTRE: while loops must contain a boolean expression"));
                    }
                }
                let vals = get_evald!(eval_stmt_list(stmt_list, scopes));
                for val in vals.into_iter() {
                    result_vec.push(val);
                }
            }
            Result::Ok(result_vec)
        }
        _ => panic!("stmt not implemented yet!")
    }
}

fn eval_stmt_list<'a>(stmt_list: &'a Vec<Stmt>, scopes: &mut Vec<HashMap<&'a str, Value>>) -> Result<Vec<Value>> {
    let mut ret_list = vec![];
    for st in stmt_list.iter() {
        let mut values = get_evald!(eval_stmt(st, scopes));
        ret_list.append(&mut values);
    }
    Result::Ok(ret_list)
}

pub fn eval_file_stmts<'a>(stmt_list: &'a Vec<Stmt>) -> Result<Vec<Value>> {
    let mut scopes = vec![HashMap::new()];
    eval_stmt_list(stmt_list, &mut scopes)
}
<|endoftext|>


<commit_before>use std::io::File;
use std::io::fs::PathExtensions;
use std::collections::HashMap;
use calx::color;
use calx::Context;
use calx::Event;
use calx::Key;
use calx::{Fonter, V2};
use world;
use world::action;
use world::action::{Step, Melee};
use world::Dir6;
use world::Dir6::*;
use world::{Entity};
use worldview;
use sprite::{WorldSprites, GibSprite};
use tilecache;
use tilecache::icon;

pub struct GameState {
    world_spr: WorldSprites,
    /// Counters for entities with flashing damage animation.
    damage_timers: HashMap<Entity, uint>,

    // TODO: Probably going to need a general "ongoing activity" system at
    // some point.
    exploring: bool,
}

impl GameState {
    pub fn new(seed: Option<u32>) -> GameState {
        world::init_world(seed);
        GameState {
            world_spr: WorldSprites::new(),
            damage_timers: HashMap::new(),
            exploring: false,
        }
    }

    fn draw_player_ui(&mut self, ctx: &mut Context, player: Entity) {
        let hp = player.hp();
        let max_hp = player.max_hp();

        // Draw heart containers.
        for i in range(0, (max_hp + 1) / 2) {
            let pos = V2(i * 8, 8);
            let idx = if hp >= (i + 1) * 2 { icon::HEART }
                else if hp == i * 2 + 1 { icon::HALF_HEART }
                else { icon::NO_HEART };
            ctx.draw_image(pos, 0.0, tilecache::get(idx), &color::FIREBRICK);
        }
    }

    /// Repaint view, update game world if needed.
    pub fn update(&mut self, ctx: &mut Context) {
        ctx.clear(&color::BLACK);
        let camera = world::camera();

        // Process events
        loop {
            match world::pop_msg() {
                Some(world::Gib(loc)) => {
                    self.world_spr.add(box GibSprite::new(loc));
                }
                Some(world::Damage(entity)) => {
                    self.damage_timers.insert(entity, 2);
                }
                Some(x) => {
                    println!("Unhandled Msg type {}", x);
                }
                None => break
            }
        }

        worldview::draw_world(&camera, ctx, &self.damage_timers);

        // TODO use FOV for sprite draw.
        self.world_spr.draw(|x| (camera + x).fov_status() == Some(world::Seen), &camera, ctx);
        self.world_spr.update();

        if let Some(player) = action::player() {
            self.draw_player_ui(ctx, player);
        }

        let fps = 1.0 / ctx.render_duration;
        let _ = write!(&mut ctx.text_writer(V2(0, 16), 0.1, color::LIGHTGREEN)
                       .set_border(color::BLACK),
                       "FPS {:.0}", fps);

        if action::control_state() == action::ReadyToUpdate {
            action::update();
        }

        if self.exploring {
            if action::control_state() == action::AwaitingInput {
                self.exploring = self.autoexplore();
            }
        }

        self.damage_timers = self.damage_timers.clone().into_iter()
            .filter(|&(_, t)| t > 0u)
            .map(|(e, t)| (e, t - 1))
            .collect();
    }

    pub fn save_game(&self) {
        let save_data = world::save();
        let mut file = File::create(&Path::new("/tmp/magog_save.json"));
        file.write_str(save_data.as_slice()).unwrap();
    }

    pub fn load_game(&mut self) {
        let path = Path::new("/tmp/magog_save.json");
        if !path.exists() { return; }
        let save_data = File::open(&path).read_to_string().unwrap();
        // TODO: Handle failed load nicely.
        world::load(save_data.as_slice()).unwrap();
    }

    fn smart_move(&mut self, dir: Dir6) {
        let player = action::player().unwrap();
        let target_loc = player.location().unwrap() + dir.to_v2();
        if target_loc.has_mobs() {
            action::input(Melee(dir));
        } else {
            action::input(Step(dir));
        }
    }

    fn autoexplore(&mut self) -> bool {
        let player = action::player().unwrap();
        if player.is_threatened() {
            return false;
        }
        if let Some(pathing) = action::autoexplore_map() {
            let loc = player.location().unwrap();
            let steps = pathing.sorted_neighbors(&loc);
            if steps.len() == 0 {
                return false;
            }

            action::input(Step(loc.dir6_towards(steps[0]).unwrap()));
            return true;
        }

        false
    }

    /// Process a player control keypress.
    pub fn process_key(&mut self, key: Key) -> bool {
        if action::control_state() != action::AwaitingInput {
            return false;
        }

        if self.exploring {
            self.exploring = false;
        }

        match key {
            Key::Q | Key::Pad7 => { self.smart_move(NorthWest); }
            Key::W | Key::Pad8 | Key::Up => { self.smart_move(North); }
            Key::E | Key::Pad9 => { self.smart_move(NorthEast); }
            Key::A | Key::Pad1 => { self.smart_move(SouthWest); }
            Key::S | Key::Pad2 | Key::Down => { self.smart_move(South); }
            Key::D | Key::Pad3 => { self.smart_move(SouthEast); }
            Key::F5 => { self.save_game(); }
            Key::F9 => { self.load_game(); }
            Key::X => { self.exploring = true; }
            _ => { return false; }
        }
        return true;
    }

    pub fn process(&mut self, event: Event) -> bool {
        match event {
            Event::Render(ctx) => {
                self.update(ctx);
            }
            Event::KeyPressed(Key::Escape) => {
                return false;
            }
            Event::KeyPressed(k) => {
                self.process_key(k);
            }
            _ => ()
        }
        true
    }
}
<commit_msg>Debug command for skipping to next level<commit_after>use std::io::File;
use std::io::fs::PathExtensions;
use std::collections::HashMap;
use calx::color;
use calx::Context;
use calx::Event;
use calx::Key;
use calx::{Fonter, V2};
use world;
use world::action;
use world::action::{Step, Melee};
use world::Dir6;
use world::Dir6::*;
use world::{Entity};
use worldview;
use sprite::{WorldSprites, GibSprite};
use tilecache;
use tilecache::icon;

pub struct GameState {
    world_spr: WorldSprites,
    /// Counters for entities with flashing damage animation.
    damage_timers: HashMap<Entity, uint>,

    // TODO: Probably going to need a general "ongoing activity" system at
    // some point.
    exploring: bool,
}

impl GameState {
    pub fn new(seed: Option<u32>) -> GameState {
        world::init_world(seed);
        GameState {
            world_spr: WorldSprites::new(),
            damage_timers: HashMap::new(),
            exploring: false,
        }
    }

    fn draw_player_ui(&mut self, ctx: &mut Context, player: Entity) {
        let hp = player.hp();
        let max_hp = player.max_hp();

        // Draw heart containers.
        for i in range(0, (max_hp + 1) / 2) {
            let pos = V2(i * 8, 8);
            let idx = if hp >= (i + 1) * 2 { icon::HEART }
                else if hp == i * 2 + 1 { icon::HALF_HEART }
                else { icon::NO_HEART };
            ctx.draw_image(pos, 0.0, tilecache::get(idx), &color::FIREBRICK);
        }
    }

    /// Repaint view, update game world if needed.
    pub fn update(&mut self, ctx: &mut Context) {
        ctx.clear(&color::BLACK);
        let camera = world::camera();

        // Process events
        loop {
            match world::pop_msg() {
                Some(world::Gib(loc)) => {
                    self.world_spr.add(box GibSprite::new(loc));
                }
                Some(world::Damage(entity)) => {
                    self.damage_timers.insert(entity, 2);
                }
                Some(x) => {
                    println!("Unhandled Msg type {}", x);
                }
                None => break
            }
        }

        worldview::draw_world(&camera, ctx, &self.damage_timers);

        // TODO use FOV for sprite draw.
        self.world_spr.draw(|x| (camera + x).fov_status() == Some(world::Seen), &camera, ctx);
        self.world_spr.update();

        if let Some(player) = action::player() {
            self.draw_player_ui(ctx, player);
        }

        let fps = 1.0 / ctx.render_duration;
        let _ = write!(&mut ctx.text_writer(V2(0, 16), 0.1, color::LIGHTGREEN)
                       .set_border(color::BLACK),
                       "FPS {:.0}", fps);

        if action::control_state() == action::ReadyToUpdate {
            action::update();
        }

        if self.exploring {
            if action::control_state() == action::AwaitingInput {
                self.exploring = self.autoexplore();
            }
        }

        self.damage_timers = self.damage_timers.clone().into_iter()
            .filter(|&(_, t)| t > 0u)
            .map(|(e, t)| (e, t - 1))
            .collect();
    }

    pub fn save_game(&self) {
        let save_data = world::save();
        let mut file = File::create(&Path::new("/tmp/magog_save.json"));
        file.write_str(save_data.as_slice()).unwrap();
    }

    pub fn load_game(&mut self) {
        let path = Path::new("/tmp/magog_save.json");
        if !path.exists() { return; }
        let save_data = File::open(&path).read_to_string().unwrap();
        // TODO: Handle failed load nicely.
        world::load(save_data.as_slice()).unwrap();
    }

    fn smart_move(&mut self, dir: Dir6) {
        let player = action::player().unwrap();
        let target_loc = player.location().unwrap() + dir.to_v2();
        if target_loc.has_mobs() {
            action::input(Melee(dir));
        } else {
            action::input(Step(dir));
        }
    }

    fn autoexplore(&mut self) -> bool {
        let player = action::player().unwrap();
        if player.is_threatened() {
            return false;
        }
        if let Some(pathing) = action::autoexplore_map() {
            let loc = player.location().unwrap();
            let steps = pathing.sorted_neighbors(&loc);
            if steps.len() == 0 {
                return false;
            }

            action::input(Step(loc.dir6_towards(steps[0]).unwrap()));
            return true;
        }

        false
    }

    /// Process a player control keypress.
    pub fn process_key(&mut self, key: Key) -> bool {
        if action::control_state() != action::AwaitingInput {
            return false;
        }

        if self.exploring {
            self.exploring = false;
        }

        match key {
            Key::Q | Key::Pad7 => { self.smart_move(NorthWest); }
            Key::W | Key::Pad8 | Key::Up => { self.smart_move(North); }
            Key::E | Key::Pad9 => { self.smart_move(NorthEast); }
            Key::A | Key::Pad1 => { self.smart_move(SouthWest); }
            Key::S | Key::Pad2 | Key::Down => { self.smart_move(South); }
            Key::D | Key::Pad3 => { self.smart_move(SouthEast); }
            Key::F5 => { self.save_game(); }
            Key::F9 => { self.load_game(); }
            Key::X => { self.exploring = true; }
            _ => { return false; }
        }
        return true;
    }

    pub fn process(&mut self, event: Event) -> bool {
        match event {
            Event::Render(ctx) => {
                self.update(ctx);
            }
            Event::KeyPressed(Key::Escape) => {
                return false;
            }
            Event::KeyPressed(k) => {
                self.process_key(k);
            }

            Event::Char(ch) => {
                // TODO: Chars and keypresses in same lookup (use variants?)
                match ch {
                    // Debug
                    '>' => { action::next_level(); }
                    _ => ()
                }
            }

            _ => ()
        }
        true
    }
}
<|endoftext|>


<commit_before>use clap::{App, Arg};

// This Struct is later given to our main program,
// it contains all the needed information to make suggestions of films
#[derive(Debug, Clone)]
pub struct SearchParams {
    genres: Vec<String>,
    movies: Vec<String>,
    actors: Vec<String>,
    rating: Vec<f32>,
}

impl SearchParams {
    // initialize a SearchParams type with empty fields
    fn init() -> Self {
        SearchParams {
            genres: Vec::new(),
            movies: Vec::new(),
            actors: Vec::new(),
            rating: Vec::new(),
        }
    }
}

// Creates struct SearchParams in which all given parameters are included.
pub fn get_search_params() -> SearchParams {
    // status of program
    println!("[Getting Commandline Input]");

    // later given to main program, contains all arguments given in
    // command line
    let mut search_params = SearchParams::init();

    // our matches, we can later use those to handle our commandline input
    let matches = App::new("FOM")
        .arg(Arg::with_name("genre")
            .short("g")
            .takes_value(true)
            .multiple(true))
        .arg(Arg::with_name("actor")
            .short("a")
            .takes_value(true))
        .arg(Arg::with_name("movie")
            .short("m")
            .takes_value(true)
            .multiple(true))
        .arg(Arg::with_name("rating")
            .short("r")
            .takes_value(true))
        .get_matches();

    // If a genre was given, save it in our SearchParams Type
    if matches.is_present("genre") {
        let genres: Vec<String> = match matches.values_of("genre") {
            Some(vals) => {
                vals.map(|x| x.to_string())
                    .collect()
            }
            None => panic!(),
        };
        search_params.genres = genres;
        // Debug
        // println!("Genre: {}", genre);
    }

    // If an actor was given, save it in our SearchParams Type
    if matches.is_present("actor") {
        let actor = match matches.value_of("actor") {
            Some(actor) => actor,
            None => panic!(),
        };
        search_params.actors.push(actor.into());
        // Debug
        // println!("Actor: {}", actor);
    }

    // If a genre was given, save it in our SearchParams Type
    if matches.is_present("movie") {
        let movies: Vec<String> = match matches.values_of("movie") {
            Some(vals) => {
                vals.map(|x| x.to_string())
                    .collect()
            }
            None => panic!(),
        };
        search_params.movies = movies;
        // Debug
        // println!("Movies: {:?}", search_params.genre);
    }

    if matches.is_present("rating") {
        let val = match matches.value_of("rating") {
            Some(vals) => vals,
            None => panic!(),
        };
        search_params.rating.push(val.parse().unwrap());
        // Debug
        // println!("Rating: {:?}", search_params.rating);
    }
    // Debug
    // println!("{:?}", search_params);
    search_params
}
<commit_msg>exit() instead of panic!(), better error handling<commit_after>use clap::{App, Arg};
use std::process;

// This Struct is later given to our main program,
// it contains all the needed information to make suggestions of films
#[derive(Debug, Clone)]
pub struct SearchParams {
    genres: Vec<String>,
    movies: Vec<String>,
    actors: Vec<String>,
    rating: Vec<f32>,
}

impl SearchParams {
    // initialize a SearchParams type with empty fields
    fn init() -> Self {
        SearchParams {
            genres: Vec::new(),
            movies: Vec::new(),
            actors: Vec::new(),
            rating: Vec::new(),
        }
    }
}

// Creates struct SearchParams in which all given parameters are included.
pub fn get_search_params() -> SearchParams {
    // status of program
    println!("Getting Commandline Input ...");

    // later given to main program, contains all arguments given in
    // command line
    let mut search_params = SearchParams::init();

    // our matches, we can later use those to handle our commandline input
    let matches = App::new("Film-O-Mat")
        .arg(Arg::with_name("genre")
            .short("g")
            .help("Takes one or more genres")
            .takes_value(true)
            .multiple(true))
        .arg(Arg::with_name("actor")
            .short("a")
            .help("Takes an actor")
            .takes_value(true))
        .arg(Arg::with_name("movie")
            .short("m")
            .help("Takes one or more movies. e.g. \u{0022}Schindler's List\u{0022}")
            .takes_value(true)
            .multiple(true))
        .arg(Arg::with_name("rating")
            .short("r")
            .help("Takes a rating")
            .takes_value(true))
        .get_matches();

    // If a genre was given, save it in our SearchParams Type
    if matches.is_present("genre") {
        let genres: Vec<String> = match matches.values_of("genre") {
            Some(vals) => {
                vals.map(|x| x.to_string())
                    .collect()
            }
            None => {
                println!("Invalid Genre");
                process::exit(0);
            }
        };
        search_params.genres = genres;
        // Debug
        // println!("Genre: {}", genre);
    }

    // If an actor was given, save it in our SearchParams Type
    if matches.is_present("actor") {
        let actor = match matches.value_of("actor") {
            Some(actor) => actor,
            None => {
                println!("Invalid Actor");
                process::exit(0);
            }
        };
        search_params.actors.push(actor.into());
        // Debug
        // println!("Actor: {}", actor);
    }

    // If a genre was given, save it in our SearchParams Type
    if matches.is_present("movie") {
        let movies: Vec<String> = match matches.values_of("movie") {
            Some(vals) => {
                vals.map(|x| x.to_string())
                    .collect()
            }
            None => {
                println!("Invalid Movie");
                process::exit(0);
            }
        };
        search_params.movies = movies;
        // Debug
        // println!("Movies: {:?}", search_params.genre);
    }

    if matches.is_present("rating") {
        let val = match matches.value_of("rating") {
            Some(vals) => vals,
            None => {
                println!("Invalid Rating");
                process::exit(0);
            }
        };
        search_params.rating.push(
            match val.parse() {
                Ok(val) => val,
                Err(err) => {
                    println!("{:?}", err);
                    process::exit(0);
                }
            }
        );
        // Debug
        // println!("Rating: {:?}", search_params.rating);
    }

    // Debug
    // println!("{:?}", search_params);
    search_params
}
<|endoftext|>


<commit_before>#![crate_name = "uu_join"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Konstantin Pospelov <kupospelov@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate getopts;

#[macro_use]
extern crate uucore;

use std::fs::File;
use std::io::{BufRead, BufReader, Lines, Read, stdin};
use std::cmp::Ordering;

static NAME: &'static str = "join";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");

#[derive(PartialEq)]
enum FileNum {
    None,
    File1,
    File2,
}

struct Settings {
    key1: usize,
    key2: usize,
    print_unpaired: FileNum,
    ignore_case: bool,
}

impl Default for Settings {
    fn default() -> Settings {
        Settings {
            key1: 0,
            key2: 0,
            print_unpaired: FileNum::None,
            ignore_case: false,
        }
    }
}

struct Line {
    fields: Vec<String>,
}

impl Line {
    fn new(string: String) -> Line {
        Line { fields: string.split_whitespace().map(|s| String::from(s)).collect() }
    }

    /// Get field at index.
    fn get_field(&self, index: usize) -> &str {
        if index < self.fields.len() {
            &self.fields[index]
        } else {
            ""
        }
    }

    /// Iterate each field except the one at the index.
    fn foreach_except<F>(&self, index: usize, f: &F)
    where
        F: Fn(&String),
    {
        for (i, field) in self.fields.iter().enumerate() {
            if i != index {
                f(&field);
            }
        }
    }
}

struct State {
    key: usize,
    print_unpaired: bool,
    lines: Lines<BufReader<Box<Read>>>,
    seq: Vec<Line>,
}

impl State {
    fn new(name: &str, key: usize, print_unpaired: bool) -> State {
        let f: Box<Read> = if name == "-" {
            Box::new(stdin()) as Box<Read>
        } else {
            match File::open(name) {
                Ok(file) => Box::new(file) as Box<Read>,
                Err(err) => crash!(1, "{}: {}", name, err),
            }
        };

        State {
            key: key,
            print_unpaired: print_unpaired,
            lines: BufReader::new(f).lines(),
            seq: Vec::new(),
        }
    }

    /// Compare the key fields of the two current lines.
    fn compare(&self, other: &State, ignore_case: bool) -> Ordering {
        let key1 = self.seq[0].get_field(self.key);
        let key2 = other.seq[0].get_field(other.key);

        compare(key1, key2, ignore_case)
    }

    /// Skip the current unpaired line.
    fn skip_line(&mut self) {
        if self.print_unpaired {
            self.print_unpaired_line(&self.seq[0]);
        }

        self.next_line();
    }

    /// Move to the next line, if any.
    fn next_line(&mut self) {
        match self.read_line() {
            Some(line) => {
                self.seq[0] = line;
            }
            None => {
                self.seq.clear();
            }
        }
    }

    /// Keep reading line sequence until the key does not change, return
    /// the first line whose key differs.
    fn extend(&mut self, ignore_case: bool) -> Option<Line> {
        while let Some(line) = self.read_line() {
            let diff = compare(
                self.seq[0].get_field(self.key),
                line.get_field(self.key),
                ignore_case,
            );

            if diff == Ordering::Equal {
                self.seq.push(line);
            } else {
                return Some(line);
            }
        }

        return None;
    }

    /// Combine two line sequences.
    fn combine(&self, other: &State) {
        let key = self.seq[0].get_field(self.key);

        for line1 in &self.seq {
            for line2 in &other.seq {
                print!("{}", key);
                line1.foreach_except(self.key, &print_field);
                line2.foreach_except(other.key, &print_field);
                println!();
            }
        }
    }

    /// Reset with the next line.
    fn reset(&mut self, next_line: Option<Line>) {
        self.seq.clear();

        if let Some(line) = next_line {
            self.seq.push(line);
        }
    }

    fn has_line(&self) -> bool {
        !self.seq.is_empty()
    }

    fn initialize(&mut self) {
        if let Some(line) = self.read_line() {
            self.seq.push(line);
        }
    }

    fn finalize(&mut self) {
        if self.has_line() && self.print_unpaired {
            self.print_unpaired_line(&self.seq[0]);

            while let Some(line) = self.read_line() {
                self.print_unpaired_line(&line);
            }
        }
    }

    fn read_line(&mut self) -> Option<Line> {
        match self.lines.next() {
            Some(value) => Some(Line::new(value.expect("error reading file"))),
            None => None,
        }
    }

    fn print_unpaired_line(&self, line: &Line) {
        print!("{}", line.get_field(self.key));
        line.foreach_except(self.key, &print_field);
        println!();
    }
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut settings: Settings = Default::default();
    let mut opts = getopts::Options::new();

    opts.optflag("h", "help", "display this help and exit");
    opts.optopt(
        "a",
        "",
        "also print unpairable lines from file FILENUM, where FILENUM is 1 or 2, corresponding to FILE1 or FILE2",
        "FILENUM"
    );
    opts.optflag(
        "i",
        "ignore-case",
        "ignore differences in case when comparing fields",
    );
    opts.optopt("j", "", "equivalent to '-1 FIELD -2 FIELD'", "FIELD");
    opts.optopt("1", "", "join on this FIELD of file 1", "FIELD");
    opts.optopt("2", "", "join on this FIELD of file 2", "FIELD");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => crash!(1, "Invalid options\n{}", f),
    };

    if matches.opt_present("help") {
        let msg = format!(
            "{0} {1}
Usage:
 {0} [OPTION]... FILE1 FILE2

For each pair of input lines with identical join fields, write a line to
standard output. The default join field is the first, delimited by blanks.",
            NAME,
            VERSION
        );
        print!("{}", opts.usage(&msg));
        return 0;
    }

    let keys = parse_field_number(matches.opt_str("j"));
    let key1 = parse_field_number(matches.opt_str("1"));
    let key2 = parse_field_number(matches.opt_str("2"));

    settings.print_unpaired = match matches.opt_str("a") {
        Some(value) => {
            match &value[..] {
                "1" => FileNum::File1,
                "2" => FileNum::File2,
                value => crash!(1, "invalid file number: {}", value),
            }
        }
        None => FileNum::None,
    };
    settings.ignore_case = matches.opt_present("ignore-case");
    settings.key1 = get_field_number(keys, key1);
    settings.key2 = get_field_number(keys, key2);

    let files = matches.free;
    let file_count = files.len();

    if file_count < 1 {
        crash!(1, "missing operand");
    } else if file_count < 2 {
        crash!(1, "missing operand after '{}'", files[0]);
    } else if file_count > 2 {
        crash!(1, "extra operand '{}'", files[2]);
    }

    if files[0] == "-" && files[1] == "-" {
        crash!(1, "both files cannot be standard input");
    }

    exec(files, &settings)
}

fn exec(files: Vec<String>, settings: &Settings) -> i32 {
    let mut state1 = State::new(
        &files[0],
        settings.key1,
        settings.print_unpaired == FileNum::File1,
    );

    let mut state2 = State::new(
        &files[1],
        settings.key2,
        settings.print_unpaired == FileNum::File2,
    );

    state1.initialize();
    state2.initialize();

    while state1.has_line() && state2.has_line() {
        let diff = state1.compare(&state2, settings.ignore_case);

        match diff {
            Ordering::Less => {
                state1.skip_line();
            }
            Ordering::Greater => {
                state2.skip_line();
            }
            Ordering::Equal => {
                let next_line1 = state1.extend(settings.ignore_case);
                let next_line2 = state2.extend(settings.ignore_case);

                state1.combine(&state2);

                state1.reset(next_line1);
                state2.reset(next_line2);
            }
        }
    }

    state1.finalize();
    state2.finalize();

    0
}

/// Check that keys for both files and for a particular file are not
/// contradictory and return the zero-based key index.
fn get_field_number(keys: Option<usize>, key: Option<usize>) -> usize {
    if let Some(keys) = keys {
        if let Some(key) = key {
            if keys != key {
                crash!(1, "incompatible join fields {}, {}", keys, key);
            }
        }

        return keys - 1;
    }

    match key {
        Some(key) => key - 1,
        None => 0,
    }
}

/// Parse the specified field string as a natural number and return it.
fn parse_field_number(value: Option<String>) -> Option<usize> {
    match value {
        Some(value) => {
            match value.parse() {
                Ok(result) if result > 0 => Some(result),
                _ => crash!(1, "invalid field number: '{}'", value),
            }
        }
        None => None,
    }
}

fn compare(field1: &str, field2: &str, ignore_case: bool) -> Ordering {
    if ignore_case {
        field1.to_lowercase().cmp(&field2.to_lowercase())
    } else {
        field1.cmp(field2)
    }
}

fn print_field(field: &String) {
    print!("{}{}", ' ', field);
}
<commit_msg>join: minor review points<commit_after>#![crate_name = "uu_join"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Konstantin Pospelov <kupospelov@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate getopts;

#[macro_use]
extern crate uucore;

use std::fs::File;
use std::io::{BufRead, BufReader, Lines, Read, stdin};
use std::cmp::Ordering;

static NAME: &'static str = "join";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");

#[derive(PartialEq)]
enum FileNum {
    None,
    File1,
    File2,
}

struct Settings {
    key1: usize,
    key2: usize,
    print_unpaired: FileNum,
    ignore_case: bool,
}

impl Default for Settings {
    fn default() -> Settings {
        Settings {
            key1: 0,
            key2: 0,
            print_unpaired: FileNum::None,
            ignore_case: false,
        }
    }
}

struct Line {
    fields: Vec<String>,
}

impl Line {
    fn new(string: String) -> Line {
        Line { fields: string.split_whitespace().map(|s| String::from(s)).collect() }
    }

    /// Get field at index.
    fn get_field(&self, index: usize) -> &str {
        if index < self.fields.len() {
            &self.fields[index]
        } else {
            ""
        }
    }

    /// Iterate each field except the one at the index.
    fn foreach_except<F>(&self, index: usize, f: &F)
    where
        F: Fn(&String),
    {
        for (i, field) in self.fields.iter().enumerate() {
            if i != index {
                f(&field);
            }
        }
    }
}

struct State {
    key: usize,
    print_unpaired: bool,
    lines: Lines<BufReader<Box<Read>>>,
    seq: Vec<Line>,
}

impl State {
    fn new(name: &str, key: usize, print_unpaired: bool) -> State {
        let f: Box<Read> = if name == "-" {
            Box::new(stdin()) as Box<Read>
        } else {
            match File::open(name) {
                Ok(file) => Box::new(file) as Box<Read>,
                Err(err) => crash!(1, "{}: {}", name, err),
            }
        };

        State {
            key: key,
            print_unpaired: print_unpaired,
            lines: BufReader::new(f).lines(),
            seq: Vec::new(),
        }
    }

    /// Compare the key fields of the two current lines.
    fn compare(&self, other: &State, ignore_case: bool) -> Ordering {
        let key1 = self.seq[0].get_field(self.key);
        let key2 = other.seq[0].get_field(other.key);

        compare(key1, key2, ignore_case)
    }

    /// Skip the current unpaired line.
    fn skip_line(&mut self) {
        if self.print_unpaired {
            self.print_unpaired_line(&self.seq[0]);
        }

        self.next_line();
    }

    /// Move to the next line, if any.
    fn next_line(&mut self) {
        match self.read_line() {
            Some(line) => self.seq[0] = line,
            None => self.seq.clear()
        }
    }

    /// Keep reading line sequence until the key does not change, return
    /// the first line whose key differs.
    fn extend(&mut self, ignore_case: bool) -> Option<Line> {
        while let Some(line) = self.read_line() {
            let diff = compare(
                self.seq[0].get_field(self.key),
                line.get_field(self.key),
                ignore_case,
            );

            if diff == Ordering::Equal {
                self.seq.push(line);
            } else {
                return Some(line);
            }
        }

        return None;
    }

    /// Combine two line sequences.
    fn combine(&self, other: &State) {
        let key = self.seq[0].get_field(self.key);

        for line1 in &self.seq {
            for line2 in &other.seq {
                print!("{}", key);
                line1.foreach_except(self.key, &print_field);
                line2.foreach_except(other.key, &print_field);
                println!();
            }
        }
    }

    /// Reset with the next line.
    fn reset(&mut self, next_line: Option<Line>) {
        self.seq.clear();

        if let Some(line) = next_line {
            self.seq.push(line);
        }
    }

    fn has_line(&self) -> bool {
        !self.seq.is_empty()
    }

    fn initialize(&mut self) {
        if let Some(line) = self.read_line() {
            self.seq.push(line);
        }
    }

    fn finalize(&mut self) {
        if self.has_line() && self.print_unpaired {
            self.print_unpaired_line(&self.seq[0]);

            while let Some(line) = self.read_line() {
                self.print_unpaired_line(&line);
            }
        }
    }

    fn read_line(&mut self) -> Option<Line> {
        match self.lines.next() {
            Some(value) => Some(Line::new(crash_if_err!(1, value))),
            None => None,
        }
    }

    fn print_unpaired_line(&self, line: &Line) {
        print!("{}", line.get_field(self.key));
        line.foreach_except(self.key, &print_field);
        println!();
    }
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut settings: Settings = Default::default();
    let mut opts = getopts::Options::new();

    opts.optflag("h", "help", "display this help and exit");
    opts.optopt(
        "a",
        "",
        "also print unpairable lines from file FILENUM, where FILENUM is 1 or 2, corresponding to FILE1 or FILE2",
        "FILENUM"
    );
    opts.optflag(
        "i",
        "ignore-case",
        "ignore differences in case when comparing fields",
    );
    opts.optopt("j", "", "equivalent to '-1 FIELD -2 FIELD'", "FIELD");
    opts.optopt("1", "", "join on this FIELD of file 1", "FIELD");
    opts.optopt("2", "", "join on this FIELD of file 2", "FIELD");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => crash!(1, "Invalid options\n{}", f),
    };

    if matches.opt_present("help") {
        let msg = format!(
            "{0} {1}
Usage:
 {0} [OPTION]... FILE1 FILE2

For each pair of input lines with identical join fields, write a line to
standard output. The default join field is the first, delimited by blanks.",
            NAME,
            VERSION
        );
        print!("{}", opts.usage(&msg));
        return 0;
    }

    let keys = parse_field_number(matches.opt_str("j"));
    let key1 = parse_field_number(matches.opt_str("1"));
    let key2 = parse_field_number(matches.opt_str("2"));

    settings.print_unpaired = match matches.opt_str("a") {
        Some(value) => {
            match &value[..] {
                "1" => FileNum::File1,
                "2" => FileNum::File2,
                value => crash!(1, "invalid file number: {}", value),
            }
        }
        None => FileNum::None,
    };
    settings.ignore_case = matches.opt_present("ignore-case");
    settings.key1 = get_field_number(keys, key1);
    settings.key2 = get_field_number(keys, key2);

    let files = matches.free;
    let file_count = files.len();

    if file_count < 1 {
        crash!(1, "missing operand");
    } else if file_count < 2 {
        crash!(1, "missing operand after '{}'", files[0]);
    } else if file_count > 2 {
        crash!(1, "extra operand '{}'", files[2]);
    }

    if files[0] == "-" && files[1] == "-" {
        crash!(1, "both files cannot be standard input");
    }

    exec(files, &settings)
}

fn exec(files: Vec<String>, settings: &Settings) -> i32 {
    let mut state1 = State::new(
        &files[0],
        settings.key1,
        settings.print_unpaired == FileNum::File1,
    );

    let mut state2 = State::new(
        &files[1],
        settings.key2,
        settings.print_unpaired == FileNum::File2,
    );

    state1.initialize();
    state2.initialize();

    while state1.has_line() && state2.has_line() {
        let diff = state1.compare(&state2, settings.ignore_case);

        match diff {
            Ordering::Less => {
                state1.skip_line();
            }
            Ordering::Greater => {
                state2.skip_line();
            }
            Ordering::Equal => {
                let next_line1 = state1.extend(settings.ignore_case);
                let next_line2 = state2.extend(settings.ignore_case);

                state1.combine(&state2);

                state1.reset(next_line1);
                state2.reset(next_line2);
            }
        }
    }

    state1.finalize();
    state2.finalize();

    0
}

/// Check that keys for both files and for a particular file are not
/// contradictory and return the zero-based key index.
fn get_field_number(keys: Option<usize>, key: Option<usize>) -> usize {
    if let Some(keys) = keys {
        if let Some(key) = key {
            if keys != key {
                crash!(1, "incompatible join fields {}, {}", keys, key);
            }
        }

        return keys - 1;
    }

    match key {
        Some(key) => key - 1,
        None => 0,
    }
}

/// Parse the specified field string as a natural number and return it.
fn parse_field_number(value: Option<String>) -> Option<usize> {
    match value {
        Some(value) => {
            match value.parse() {
                Ok(result) if result > 0 => Some(result),
                _ => crash!(1, "invalid field number: '{}'", value),
            }
        }
        None => None,
    }
}

fn compare(field1: &str, field2: &str, ignore_case: bool) -> Ordering {
    if ignore_case {
        field1.to_lowercase().cmp(&field2.to_lowercase())
    } else {
        field1.cmp(field2)
    }
}

fn print_field(field: &String) {
    print!("{}{}", ' ', field);
}
<|endoftext|>


<commit_before>//! Tests for the join code.

use configuration::*;
use join::*;
use rand::{Rng, SeedableRng, XorShiftRng};
use thread_pool::*;
use unwind;

fn quick_sort<T: PartialOrd + Send>(v: &mut [T]) {
    if v.len() <= 1 {
        return;
    }

    let mid = partition(v);
    let (lo, hi) = v.split_at_mut(mid);
    join(|| quick_sort(lo), || quick_sort(hi));
}

fn partition<T: PartialOrd + Send>(v: &mut [T]) -> usize {
    let pivot = v.len() - 1;
    let mut i = 0;
    for j in 0..pivot {
        if v[j] <= v[pivot] {
            v.swap(i, j);
            i += 1;
        }
    }
    v.swap(i, pivot);
    i
}

#[test]
fn sort() {
    let mut rng = XorShiftRng::from_seed([0, 1, 2, 3]);
    let mut data: Vec<_> = (0..6 * 1024).map(|_| rng.next_u32()).collect();

    let result = initialize(Configuration::new());

    match result {
        Ok(_) => {
            quick_sort(&mut data);

            let mut sorted_data = data.clone();
            sorted_data.sort();

            assert_eq!(data, sorted_data);
        }
        Err(e) => panic!("expected InitOk, but got {:?}", e),
    }
}

#[test]
fn sort_in_pool() {
    let mut rng = XorShiftRng::from_seed([0, 1, 2, 3]);
    let mut data: Vec<_> = (0..12 * 1024).map(|_| rng.next_u32()).collect();

    let result = ThreadPool::new(Configuration::new());

    match result {
        Ok(pool) => {
            pool.install(|| {
                quick_sort(&mut data);
            });

            let mut sorted_data = data.clone();
            sorted_data.sort();

            assert_eq!(data, sorted_data);
        }
        Err(_) => panic!("expected Ok() but got Err()"),
    }
}

#[test]
#[should_panic(expected = "Hello, world!")]
fn panic_propagate_a() {
    join(|| panic!("Hello, world!"), || ());
}

#[test]
#[should_panic(expected = "Hello, world!")]
fn panic_propagate_b() {
    join(|| (), || panic!("Hello, world!"));
}

#[test]
#[should_panic(expected = "Hello, world!")]
fn panic_propagate_both() {
    join(|| panic!("Hello, world!"), || panic!("Goodbye, world!"));
}

#[test]
fn panic_b_still_executes() {
    let mut x = false;
    match unwind::halt_unwinding(|| join(|| panic!("Hello, world!"), || x = true)) {
        Ok(_) => panic!("failed to propagate panic from closure A,"),
        Err(_) => assert!(x, "closure b failed to execute"),
    }
}
<commit_msg>clone data and compute expected results before mutating data via quick_sort<commit_after>//! Tests for the join code.

use configuration::*;
use join::*;
use rand::{Rng, SeedableRng, XorShiftRng};
use thread_pool::*;
use unwind;

fn quick_sort<T: PartialOrd + Send>(v: &mut [T]) {
    if v.len() <= 1 {
        return;
    }

    let mid = partition(v);
    let (lo, hi) = v.split_at_mut(mid);
    join(|| quick_sort(lo), || quick_sort(hi));
}

fn partition<T: PartialOrd + Send>(v: &mut [T]) -> usize {
    let pivot = v.len() - 1;
    let mut i = 0;
    for j in 0..pivot {
        if v[j] <= v[pivot] {
            v.swap(i, j);
            i += 1;
        }
    }
    v.swap(i, pivot);
    i
}

#[test]
fn sort() {
    let mut rng = XorShiftRng::from_seed([0, 1, 2, 3]);
    let mut data: Vec<_> = (0..6 * 1024).map(|_| rng.next_u32()).collect();

    let result = initialize(Configuration::new());

    match result {
        Ok(_) => {
            let mut sorted_data = data.clone();
            sorted_data.sort();

            quick_sort(&mut data);

            assert_eq!(data, sorted_data);
        }
        Err(e) => panic!("expected InitOk, but got {:?}", e),
    }
}

#[test]
fn sort_in_pool() {
    let mut rng = XorShiftRng::from_seed([0, 1, 2, 3]);
    let mut data: Vec<_> = (0..12 * 1024).map(|_| rng.next_u32()).collect();

    let result = ThreadPool::new(Configuration::new());

    match result {
        Ok(pool) => {
            let mut sorted_data = data.clone();
            sorted_data.sort();

            pool.install(|| {
                quick_sort(&mut data);
            });

            assert_eq!(data, sorted_data);
        }
        Err(_) => panic!("expected Ok() but got Err()"),
    }
}

#[test]
#[should_panic(expected = "Hello, world!")]
fn panic_propagate_a() {
    join(|| panic!("Hello, world!"), || ());
}

#[test]
#[should_panic(expected = "Hello, world!")]
fn panic_propagate_b() {
    join(|| (), || panic!("Hello, world!"));
}

#[test]
#[should_panic(expected = "Hello, world!")]
fn panic_propagate_both() {
    join(|| panic!("Hello, world!"), || panic!("Goodbye, world!"));
}

#[test]
fn panic_b_still_executes() {
    let mut x = false;
    match unwind::halt_unwinding(|| join(|| panic!("Hello, world!"), || x = true)) {
        Ok(_) => panic!("failed to propagate panic from closure A,"),
        Err(_) => assert!(x, "closure b failed to execute"),
    }
}
<|endoftext|>


<commit_before>
pub const SOF: u32           = 1 << 3;
pub const EARLY_SUSPEND: u32 = 1 << 10;
pub const USB_SUSPEND: u32   = 1 << 11;
pub const USB_RESET: u32     = 1 << 12;
pub const ENUM_DONE: u32     = 1 << 13;
pub const IEPINT: u32     = 1 << 18;
pub const OEPINT: u32     = 1 << 19;
pub const GOUTNAKEFF: u32     = 1 << 7;
pub const GINNAKEFF: u32     = 1 << 6;

const MAX_CONTROL_ENDPOINTS: u16 = 3;
const MAX_NORMAL_ENDPOINTS: u16  = 16;
const MAX_PACKET_SIZE: u16        = 64;
//const FIFO_RAM_DEPTH: u16        = 1024;

pub const RX_FIFO_SIZE: u16 = (4 * MAX_CONTROL_ENDPOINTS + 6) +
                              (2 * (MAX_PACKET_SIZE / 4 + 1)) +
                              (2 * MAX_NORMAL_ENDPOINTS) + 1;
pub const TX_FIFO_SIZE: u16 = 2 * MAX_PACKET_SIZE / 4;
// const ENDPOINT_STATUS_SIZE = 4 * MAX_NORMAL_ENDPOINTS * 2;
<commit_msg>Expose MAX_USB_PACKETS from constants module<commit_after>
pub const SOF: u32           = 1 << 3;
pub const EARLY_SUSPEND: u32 = 1 << 10;
pub const USB_SUSPEND: u32   = 1 << 11;
pub const USB_RESET: u32     = 1 << 12;
pub const ENUM_DONE: u32     = 1 << 13;
pub const IEPINT: u32     = 1 << 18;
pub const OEPINT: u32     = 1 << 19;
pub const GOUTNAKEFF: u32     = 1 << 7;
pub const GINNAKEFF: u32     = 1 << 6;

const MAX_CONTROL_ENDPOINTS: u16 = 3;
const MAX_NORMAL_ENDPOINTS: u16  = 16;
pub const MAX_PACKET_SIZE: u16        = 64;
//const FIFO_RAM_DEPTH: u16        = 1024;

pub const RX_FIFO_SIZE: u16 = (4 * MAX_CONTROL_ENDPOINTS + 6) +
                              (2 * (MAX_PACKET_SIZE / 4 + 1)) +
                              (2 * MAX_NORMAL_ENDPOINTS) + 1;
pub const TX_FIFO_SIZE: u16 = 2 * MAX_PACKET_SIZE / 4;
// const ENDPOINT_STATUS_SIZE = 4 * MAX_NORMAL_ENDPOINTS * 2;

<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]

use anyhow::{bail, format_err, Result};
use libra_logger::info;
use rusoto_autoscaling::{
    AutoScalingGroupNamesType, Autoscaling, AutoscalingClient, SetDesiredCapacityType,
};
use rusoto_core::Region;
use rusoto_sts::WebIdentityProvider;

/// set_asg_size sets the size of the given autoscaling group
#[allow(clippy::collapsible_if)]
pub async fn set_asg_size(
    min_desired_capacity: i64,
    buffer_percent: f64,
    asg_name: &str,
    wait_for_completion: bool,
    scaling_down: bool,
) -> Result<()> {
    let buffer = if scaling_down {
        0
    } else {
        ((min_desired_capacity as f64 * buffer_percent) / 100_f64).ceil() as i64
    };
    info!(
        "Scaling to min_desired_capacity : {}, buffer: {}, asg_name: {}",
        min_desired_capacity, buffer, asg_name
    );
    let set_desired_capacity_type = SetDesiredCapacityType {
        auto_scaling_group_name: asg_name.to_string(),
        desired_capacity: min_desired_capacity + buffer,
        honor_cooldown: Some(false),
    };
    let credentials_provider = WebIdentityProvider::from_k8s_env();

    let dispatcher = rusoto_core::HttpClient::new().expect("failed to create request dispatcher");
    let asc = AutoscalingClient::new_with(dispatcher, credentials_provider, Region::UsWest2);
    asc.set_desired_capacity(set_desired_capacity_type)
        .await
        .map_err(|e| format_err!("set_desired_capacity failed: {:?}", e))?;
    if !wait_for_completion {
        return Ok(());
    }
    libra_retrier::retry_async(libra_retrier::fixed_retry_strategy(10_000, 30), || {
        let asc_clone = asc.clone();
        Box::pin(async move {
            let mut total = 0;
            let mut current_token = None;
            loop {
                let current_token_clone = current_token.clone();
                let auto_scaling_group_names_type = AutoScalingGroupNamesType {
                    auto_scaling_group_names: Some(vec![asg_name.to_string()]),
                    // https://docs.aws.amazon.com/autoscaling/ec2/APIReference/API_DescribeAutoScalingGroups.html
                    // max value is 100
                    max_records: Some(100),
                    next_token: current_token_clone,
                };
                let asgs = asc_clone
                    .describe_auto_scaling_groups(auto_scaling_group_names_type)
                    .await?;
                if asgs.auto_scaling_groups.is_empty() {
                    bail!("asgs.auto_scaling_groups.is_empty()");
                }
                let asg = &asgs.auto_scaling_groups[0];
                if scaling_down {
                    total += asg
                        .instances
                        .clone()
                        .ok_or_else(|| format_err!("instances not found for auto_scaling_group"))?
                        .len() as i64;
                } else {
                    total += asg
                        .instances
                        .clone()
                        .ok_or_else(|| format_err!("instances not found for auto_scaling_group"))?
                        .iter()
                        .filter(|instance| instance.lifecycle_state == "InService")
                        .count() as i64;
                }
                if asgs.next_token.is_none() {
                    break;
                }
                current_token = asgs.next_token;
            }
            info!(
                "Waiting for scaling to complete. Current size: {}, Min Desired Size: {}",
                total, min_desired_capacity
            );
            if scaling_down {
                if total > min_desired_capacity {
                    bail!(
                    "Waiting for scale-down to complete. Current size: {}, Min Desired Size: {}",
                    total,
                    min_desired_capacity
                );
                } else {
                    info!("Scale down completed");
                    Ok(())
                }
            } else {
                if total < min_desired_capacity {
                    bail!(
                        "Waiting for scale-up to complete. Current size: {}, Min Desired Size: {}",
                        total,
                        min_desired_capacity
                    );
                } else {
                    info!("Scale up completed");
                    Ok(())
                }
            }
        })
    })
    .await
}
<commit_msg>[cluster_test] Increase scaling timeout<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]

use anyhow::{bail, format_err, Result};
use libra_logger::info;
use rusoto_autoscaling::{
    AutoScalingGroupNamesType, Autoscaling, AutoscalingClient, SetDesiredCapacityType,
};
use rusoto_core::Region;
use rusoto_sts::WebIdentityProvider;

/// set_asg_size sets the size of the given autoscaling group
#[allow(clippy::collapsible_if)]
pub async fn set_asg_size(
    min_desired_capacity: i64,
    buffer_percent: f64,
    asg_name: &str,
    wait_for_completion: bool,
    scaling_down: bool,
) -> Result<()> {
    let buffer = if scaling_down {
        0
    } else {
        ((min_desired_capacity as f64 * buffer_percent) / 100_f64).ceil() as i64
    };
    info!(
        "Scaling to min_desired_capacity : {}, buffer: {}, asg_name: {}",
        min_desired_capacity, buffer, asg_name
    );
    let set_desired_capacity_type = SetDesiredCapacityType {
        auto_scaling_group_name: asg_name.to_string(),
        desired_capacity: min_desired_capacity + buffer,
        honor_cooldown: Some(false),
    };
    let credentials_provider = WebIdentityProvider::from_k8s_env();

    let dispatcher = rusoto_core::HttpClient::new().expect("failed to create request dispatcher");
    let asc = AutoscalingClient::new_with(dispatcher, credentials_provider, Region::UsWest2);
    asc.set_desired_capacity(set_desired_capacity_type)
        .await
        .map_err(|e| format_err!("set_desired_capacity failed: {:?}", e))?;
    if !wait_for_completion {
        return Ok(());
    }
    libra_retrier::retry_async(libra_retrier::fixed_retry_strategy(10_000, 60), || {
        let asc_clone = asc.clone();
        Box::pin(async move {
            let mut total = 0;
            let mut current_token = None;
            loop {
                let current_token_clone = current_token.clone();
                let auto_scaling_group_names_type = AutoScalingGroupNamesType {
                    auto_scaling_group_names: Some(vec![asg_name.to_string()]),
                    // https://docs.aws.amazon.com/autoscaling/ec2/APIReference/API_DescribeAutoScalingGroups.html
                    // max value is 100
                    max_records: Some(100),
                    next_token: current_token_clone,
                };
                let asgs = asc_clone
                    .describe_auto_scaling_groups(auto_scaling_group_names_type)
                    .await?;
                if asgs.auto_scaling_groups.is_empty() {
                    bail!("asgs.auto_scaling_groups.is_empty()");
                }
                let asg = &asgs.auto_scaling_groups[0];
                if scaling_down {
                    total += asg
                        .instances
                        .clone()
                        .ok_or_else(|| format_err!("instances not found for auto_scaling_group"))?
                        .len() as i64;
                } else {
                    total += asg
                        .instances
                        .clone()
                        .ok_or_else(|| format_err!("instances not found for auto_scaling_group"))?
                        .iter()
                        .filter(|instance| instance.lifecycle_state == "InService")
                        .count() as i64;
                }
                if asgs.next_token.is_none() {
                    break;
                }
                current_token = asgs.next_token;
            }
            info!(
                "Waiting for scaling to complete. Current size: {}, Min Desired Size: {}",
                total, min_desired_capacity
            );
            if scaling_down {
                if total > min_desired_capacity {
                    bail!(
                    "Waiting for scale-down to complete. Current size: {}, Min Desired Size: {}",
                    total,
                    min_desired_capacity
                );
                } else {
                    info!("Scale down completed");
                    Ok(())
                }
            } else {
                if total < min_desired_capacity {
                    bail!(
                        "Waiting for scale-up to complete. Current size: {}, Min Desired Size: {}",
                        total,
                        min_desired_capacity
                    );
                } else {
                    info!("Scale up completed");
                    Ok(())
                }
            }
        })
    })
    .await
}
<|endoftext|>