<commit_before>use std;
use variables::*;
use variables::LpExpression::*;
use variables::Constraint::*;
use std::rc::Rc;
use std::collections::HashSet;

//use variables::LpExpression::{AddExpr, MulExpr};
use std::ops::{AddAssign};

//use std::collections::HashMap;

/// Enum helping to specify the objective function of the linear problem.
///
/// # Exemples:
///
/// ```
/// use lp_modeler::problem::{LpObjective, LpProblem};
///
/// let mut problem = LpProblem::new("One Problem", LpObjective::Maximize);
/// ```
#[derive(Debug)]
pub enum LpObjective {
    Minimize,
    Maximize
}

/// Structure used for creating the model and solving a linear problem.
///
/// # Exemples:
///
/// ```
/// use lp_modeler::problem::{LpObjective, LpProblem};
/// use lp_modeler::variables::{LpVariable, LpType, LpOperations};
///
/// let ref a = LpVariable::new("a", LpType::Integer);
/// let ref b = LpVariable::new("b", LpType::Integer);
///
/// let mut problem = LpProblem::new("One Problem", LpObjective::Maximize);
/// problem += (a + b).le(100);
/// problem += a.ge(b);
/// problem += 2*a + 3*b;
///
/// problem.solve();
/// ```
#[derive(Debug)]
pub struct LpProblem {
    name: &'static str,
    objective_type: LpObjective,
    obj_expr: Option<LpExpression>,
    constraints: Vec<LpConstraint>

}

impl LpProblem {

    /// Create a new problem
    pub fn new(name: &'static str, objective: LpObjective) -> LpProblem {
        LpProblem { name: name, objective_type: objective, obj_expr: None, constraints: Vec::new() }
    }

    // TODO: Call once and pass into parameter
    // TODO: Check variables on the objective function
    fn variables(&self) -> HashSet<&LpExpression> {

        fn var<'a>(expr: &'a LpExpression, lst: &mut Vec<&'a LpExpression>) {
            match expr {
                &BinaryVariable {..} | &IntegerVariable {..} | &ContinuousVariable {..} => { lst.push(expr); },
                &MulExpr(_, ref e) => { var(&*e, lst); },
                &AddExpr(ref e1, ref e2) | &SubExpr(ref e1, ref e2) => {
                    var(&*e1, lst);
                    var(&*e2, lst);
                },
                _ => ()
            }
        }

        let mut lst = Vec::new();
        for e in &self.constraints {
            var(&e.0, &mut lst);
        }
        lst.iter().map(|&x| x).collect::<HashSet<_>>()
    }

    fn dfs(expr: &LpExpression, lst: &mut String) {
        match expr {
            &MulExpr(ref e1, ref e2) => {
                Self::dfs(e1, lst);
                lst.push_str(" ");
                Self::dfs(e2, lst);
            },
            &AddExpr(ref e1, ref e2) => {
                Self::dfs(e1, lst);
                lst.push_str(" + ");
                Self::dfs(e2, lst);
            },
            &SubExpr(ref e1, ref e2) => {
                Self::dfs(e1, lst);
                lst.push_str(" - ");
                Self::dfs(e2, lst);
            },
            &BinaryVariable {name: ref n, .. } => {
                lst.push_str(n);
            },
            &IntegerVariable {name: ref n, .. } => {
                lst.push_str(n);
            },
            &ContinuousVariable {name: ref n, .. } => {
                lst.push_str(n);
            },
            &LitVal(n) => {
                lst.push_str(&n.to_string());
            },
            _ => ()
        }
    }

    fn objective_string(&self) -> String {

        let mut s = String::new();
        if let Some(ref expr) = self.obj_expr {
            Self::dfs(expr, &mut s);
        }
        s

    }

    fn constraints_string(&self) -> String {
        let mut res = String::new();
        let mut cstrs = self.constraints.iter();
        let mut index = 1;
        while let Some(&LpConstraint(ref e1, ref op, ref e2)) = cstrs.next() {
            res.push_str("  c");
            res.push_str(&index.to_string());
            res.push_str(": ");
            index += 1;
            Self::dfs(e1, &mut res);
            match op {
                //TODO: Remove > <, not standard
                &GreaterOrEqual => res.push_str(" >= "),
                &LessOrEqual => res.push_str(" <= "),
                &Equal => res.push_str(" = "),
            }
            Self::dfs(e2, &mut res);
            res.push_str("\n");
        }
        res
    }

    fn bounds_string(&self) -> String {
        let mut res = String::new();
        for v in self.variables() {
            match v {
                &IntegerVariable { ref name, lower_bound, upper_bound }
                    | &ContinuousVariable { ref name, lower_bound, upper_bound } => {
                    if let Some(l) = lower_bound {
                        res.push_str("  ");
                        res.push_str(&l.to_string());
                        res.push_str(" <= ");
                        res.push_str(&name);
                        if let Some(u) = upper_bound {
                            res.push_str(" <= ");
                            res.push_str(&u.to_string());
                        }
                        res.push_str("\n");
                    } else if let Some(u) = upper_bound {
                        res.push_str("  ");
                        res.push_str(&name);
                        res.push_str(" <= ");
                        res.push_str(&u.to_string());
                        res.push_str("\n");
                    } else {
                        match v {
                            &ContinuousVariable {..} => {
                                res.push_str("  ");
                                res.push_str(&name);
                                res.push_str(" free\n");
                            }, // TODO: IntegerVar => -INF to INF
                            _ => ()
                        }
                    }
                },
                _ => (),
            }
        }
        res
    }

    fn generals_string(&self) -> String {
        let mut res = String::new();
        for v in self.variables() {
            match v {
                &IntegerVariable { ref name, .. } => {
                    res.push_str(name);
                    res.push_str(" ");
                },
                _ => (),
            }
        }
        res
    }

    fn binaries_string(&self) -> String {
        let mut res = String::new();
        for v in self.variables() {
            match v {
                &BinaryVariable { ref name } => {
                    res.push_str(name);
                    res.push_str(" ");
                },
                _ => (),
            }
        }
        res
    }

    pub fn write_lp<T: Into<String>>(&self, file_name: T) -> std::io::Result<()> {
        use std::fs::File;
        use std::io::prelude::*;

        let mut buffer = try!(File::create(file_name.into()));

        try!(buffer.write("\\ ".as_bytes()));
        try!(buffer.write(self.name.as_bytes()));
        try!(buffer.write("\n\n".as_bytes()));

        // Write objectives
        match self.objective_type {
            LpObjective::Maximize => { try!(buffer.write(b"Maximize\n  ")); },
            LpObjective::Minimize => { try!(buffer.write(b"Minimize\n  ")); },
        }
        let obj_str = self.objective_string();
        try!(buffer.write(obj_str.as_bytes()));

        // Write constraints
        let cstr_str = self.constraints_string();
        if cstr_str.len() > 0 {
            try!(buffer.write(b"\n\nSubject To\n"));
            try!(buffer.write(cstr_str.as_bytes()));
        }

        // Write bounds for Integer and Continuous
        let bound_str = self.bounds_string();
        if bound_str.len() > 0 {
            try!(buffer.write(b"\nBounds\n"));
            try!(buffer.write(bound_str.as_bytes()));
        }

        // Write Integer vars
        let generals_str = self.generals_string();
        if generals_str.len() > 0 {
            try!(buffer.write(b"\nGenerals\n  "));
            try!(buffer.write(generals_str.as_bytes()));
            try!(buffer.write(b"\n"));
        }

        // Write Binaries vars
        let binaries_str = self.binaries_string();
        if binaries_str.len() > 0 {
            println!("----------------->{}", binaries_str.len());
            try!(buffer.write(b"\nBinary\n  "));
            try!(buffer.write(binaries_str.as_bytes()));
            try!(buffer.write(b"\n"));
        }

        try!(buffer.write(b"\nEnd"));

        Ok(())

    }

    /// Solve the LP model
    pub fn solve(&self) {
        println!("Mhmmmm, solving :-)");
    }

}

/// Add constraints
impl AddAssign<LpConstraint> for LpProblem {
    fn add_assign(&mut self, _rhs: LpConstraint) {
        self.constraints.push(_rhs);
    }
}

/// Add an expression as an objective function
impl<T> AddAssign<T> for LpProblem where T: Into<LpExpression>{
    fn add_assign(&mut self, _rhs: T) {
        //TODO: improve without cloning
        if let Some(e) = self.obj_expr.clone() {
            self.obj_expr = Some(AddExpr(Rc::new(_rhs.into()), Rc::new(e.clone())));
        } else {
            self.obj_expr = Some(_rhs.into());
        }
    }
}

#[cfg(test)]
fn test(){
    assert!(false);
}
<commit_msg>LpExpression has ToString impl trait<commit_after>use std;
use variables::*;
use variables::LpExpression::*;
use variables::Constraint::*;
use std::rc::Rc;
use std::collections::HashSet;

//use variables::LpExpression::{AddExpr, MulExpr};
use std::ops::{AddAssign};

//use std::collections::HashMap;

/// Enum helping to specify the objective function of the linear problem.
///
/// # Exemples:
///
/// ```
/// use lp_modeler::problem::{LpObjective, LpProblem};
///
/// let mut problem = LpProblem::new("One Problem", LpObjective::Maximize);
/// ```
#[derive(Debug)]
pub enum LpObjective {
    Minimize,
    Maximize
}

/// Structure used for creating the model and solving a linear problem.
///
/// # Exemples:
///
/// ```
/// use lp_modeler::problem::{LpObjective, LpProblem};
/// use lp_modeler::variables::{LpVariable, LpType, LpOperations};
///
/// let ref a = LpVariable::new("a", LpType::Integer);
/// let ref b = LpVariable::new("b", LpType::Integer);
///
/// let mut problem = LpProblem::new("One Problem", LpObjective::Maximize);
/// problem += (a + b).le(100);
/// problem += a.ge(b);
/// problem += 2*a + 3*b;
///
/// problem.solve();
/// ```
#[derive(Debug)]
pub struct LpProblem {
    name: &'static str,
    objective_type: LpObjective,
    obj_expr: Option<LpExpression>,
    constraints: Vec<LpConstraint>

}

impl LpProblem {

    /// Create a new problem
    pub fn new(name: &'static str, objective: LpObjective) -> LpProblem {
        LpProblem { name: name, objective_type: objective, obj_expr: None, constraints: Vec::new() }
    }

    // TODO: Call once and pass into parameter
    // TODO: Check variables on the objective function
    fn variables(&self) -> HashSet<&LpExpression> {

        fn var<'a>(expr: &'a LpExpression, lst: &mut Vec<&'a LpExpression>) {
            match expr {
                &BinaryVariable {..} | &IntegerVariable {..} | &ContinuousVariable {..} => { lst.push(expr); },
                &MulExpr(_, ref e) => { var(&*e, lst); },
                &AddExpr(ref e1, ref e2) | &SubExpr(ref e1, ref e2) => {
                    var(&*e1, lst);
                    var(&*e2, lst);
                },
                _ => ()
            }
        }

        let mut lst = Vec::new();
        for e in &self.constraints {
            var(&e.0, &mut lst);
        }
        lst.iter().map(|&x| x).collect::<HashSet<_>>()
    }

    fn objective_string(&self) -> String {

        if let Some(ref expr) = self.obj_expr {
            expr.to_string()
        } else {
            String::new()
        }
    }

    fn constraints_string(&self) -> String {
        let mut res = String::new();
        let mut cstrs = self.constraints.iter();
        let mut index = 1;
        while let Some(&LpConstraint(ref e1, ref op, ref e2)) = cstrs.next() {
            res.push_str("  c");
            res.push_str(&index.to_string());
            res.push_str(": ");
            index += 1;
            res.push_str(&e1.to_string());
            match op {
                &GreaterOrEqual => res.push_str(" >= "),
                &LessOrEqual => res.push_str(" <= "),
                &Equal => res.push_str(" = "),
            }
            res.push_str(&e2.to_string());
            res.push_str("\n");
        }
        res
    }

    fn bounds_string(&self) -> String {
        let mut res = String::new();
        for v in self.variables() {
            match v {
                &IntegerVariable { ref name, lower_bound, upper_bound }
                    | &ContinuousVariable { ref name, lower_bound, upper_bound } => {
                    if let Some(l) = lower_bound {
                        res.push_str("  ");
                        res.push_str(&l.to_string());
                        res.push_str(" <= ");
                        res.push_str(&name);
                        if let Some(u) = upper_bound {
                            res.push_str(" <= ");
                            res.push_str(&u.to_string());
                        }
                        res.push_str("\n");
                    } else if let Some(u) = upper_bound {
                        res.push_str("  ");
                        res.push_str(&name);
                        res.push_str(" <= ");
                        res.push_str(&u.to_string());
                        res.push_str("\n");
                    } else {
                        match v {
                            &ContinuousVariable {..} => {
                                res.push_str("  ");
                                res.push_str(&name);
                                res.push_str(" free\n");
                            }, // TODO: IntegerVar => -INF to INF
                            _ => ()
                        }
                    }
                },
                _ => (),
            }
        }
        res
    }

    fn generals_string(&self) -> String {
        let mut res = String::new();
        for v in self.variables() {
            match v {
                &IntegerVariable { ref name, .. } => {
                    res.push_str(name);
                    res.push_str(" ");
                },
                _ => (),
            }
        }
        res
    }

    fn binaries_string(&self) -> String {
        let mut res = String::new();
        for v in self.variables() {
            match v {
                &BinaryVariable { ref name } => {
                    res.push_str(name);
                    res.push_str(" ");
                },
                _ => (),
            }
        }
        res
    }

    pub fn write_lp<T: Into<String>>(&self, file_name: T) -> std::io::Result<()> {
        use std::fs::File;
        use std::io::prelude::*;

        let mut buffer = try!(File::create(file_name.into()));

        try!(buffer.write("\\ ".as_bytes()));
        try!(buffer.write(self.name.as_bytes()));
        try!(buffer.write("\n\n".as_bytes()));

        // Write objectives
        match self.objective_type {
            LpObjective::Maximize => { try!(buffer.write(b"Maximize\n  ")); },
            LpObjective::Minimize => { try!(buffer.write(b"Minimize\n  ")); },
        }
        let obj_str = self.objective_string();
        try!(buffer.write(obj_str.as_bytes()));

        // Write constraints
        let cstr_str = self.constraints_string();
        if cstr_str.len() > 0 {
            try!(buffer.write(b"\n\nSubject To\n"));
            try!(buffer.write(cstr_str.as_bytes()));
        }

        // Write bounds for Integer and Continuous
        let bound_str = self.bounds_string();
        if bound_str.len() > 0 {
            try!(buffer.write(b"\nBounds\n"));
            try!(buffer.write(bound_str.as_bytes()));
        }

        // Write Integer vars
        let generals_str = self.generals_string();
        if generals_str.len() > 0 {
            try!(buffer.write(b"\nGenerals\n  "));
            try!(buffer.write(generals_str.as_bytes()));
            try!(buffer.write(b"\n"));
        }

        // Write Binaries vars
        let binaries_str = self.binaries_string();
        if binaries_str.len() > 0 {
            println!("----------------->{}", binaries_str.len());
            try!(buffer.write(b"\nBinary\n  "));
            try!(buffer.write(binaries_str.as_bytes()));
            try!(buffer.write(b"\n"));
        }

        try!(buffer.write(b"\nEnd"));

        Ok(())

    }

    /// Solve the LP model
    pub fn solve(&self) {
        println!("Mhmmmm, solving :-)");
    }

}

/// Add constraints
impl AddAssign<LpConstraint> for LpProblem {
    fn add_assign(&mut self, _rhs: LpConstraint) {
        self.constraints.push(_rhs);
    }
}

/// Add an expression as an objective function
impl<T> AddAssign<T> for LpProblem where T: Into<LpExpression>{
    fn add_assign(&mut self, _rhs: T) {
        //TODO: improve without cloning
        if let Some(e) = self.obj_expr.clone() {
            self.obj_expr = Some(AddExpr(Rc::new(_rhs.into()), Rc::new(e.clone())));
        } else {
            self.obj_expr = Some(_rhs.into());
        }
    }
}

impl ToString for LpExpression {
    fn to_string(&self) -> String {

        fn dfs(expr: &LpExpression, acc: &String) -> String {
            match expr {
                &MulExpr(ref e1, ref e2) => {
                    e1.to_string() + " " + &e2.to_string()
                },
                &AddExpr(ref e1, ref e2) => {
                    e1.to_string() + " + " + &e2.to_string()
                },
                &SubExpr(ref e1, ref e2) => {
                    e1.to_string() + " - " + &e2.to_string()
                },
                &BinaryVariable {name: ref n, .. } => {
                    acc.clone() + n
                },
                &IntegerVariable {name: ref n, .. } => {
                    acc.clone() + n
                },
                &ContinuousVariable {name: ref n, .. } => {
                    acc.clone() + n
                },
                &LitVal(n) => {
                    acc.clone() + &n.to_string()
                },
                _ => acc.clone()
            }
        }

        println!("{:?}", self);
        dfs(self, &String::new())
    }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::rc::Rc;

use voodoo::color::ColorValue;
use voodoo::window::{Point, TermCell, Window};

pub struct Program {
    pub position: Point,
    tail: Vec<Point>,
    pub name: String,
    pub abilities: Vec<String>,
    pub max_tail: usize,
}

pub type ProgramRef = Rc<RefCell<Program>>;

impl Program {
    pub fn new(position: Point, name: &str) -> Program {
        Program {
            position: position,
            tail: vec![],
            name: name.to_owned(),
            abilities: vec![],
            max_tail: 4,
        }
    }

    pub fn move_to(&mut self, point: Point) {
        self.tail.push(self.position);
        if self.tail.len() >= self.max_tail {
            self.tail.remove(0);
        }
        self.position = point;
    }

    pub fn display_color(&self, color: ColorValue, window: &mut Window) {
        let mut tc: TermCell = '◘'.into();
        tc.bg = Some(color);
        window.put_at(self.position, tc);
        for point in self.tail.iter() {
            window.put_at(*point, tc);
        }
    }

    pub fn intersects(&self, point: Point) -> bool {
        for t in self.tail.iter() {
            if *t == point {
                return true;
            }
        }
        self.position == point
    }
}
<commit_msg>feat: properly render tail<commit_after>use std::cell::RefCell;
use std::rc::Rc;

use voodoo::color::ColorValue;
use voodoo::window::{Point, TermCell, Window};

pub struct Program {
    pub position: Point,
    tail: Vec<Point>,
    pub name: String,
    pub abilities: Vec<String>,
    pub max_tail: usize,
}

pub type ProgramRef = Rc<RefCell<Program>>;

impl Program {
    pub fn new(position: Point, name: &str) -> Program {
        Program {
            position: position,
            tail: vec![],
            name: name.to_owned(),
            abilities: vec![],
            max_tail: 4,
        }
    }

    pub fn move_to(&mut self, point: Point) {
        self.tail.push(self.position);
        if self.tail.len() >= self.max_tail {
            self.tail.remove(0);
        }
        self.position = point;
    }

    pub fn display_color(&self, color: ColorValue, window: &mut Window) {
        let mut prev: Option<Point> = None;
        let mut cells = self.tail.to_vec();
        cells.push(self.position);
        for w in cells.windows(2) {
            let (cur, next) = (w[0], w[1]);
            let (x1, y1) = (cur.x as i32, cur.y as i32);
            let (x2, y2) = (next.x as i32, next.y as i32);
            let dx = x2 - x1;
            let dy = y2 - y1;

            let pdx = prev.map(|p| x1 - p.x as i32);
            let pdy = prev.map(|p| y1 - p.y as i32);

            let mut c: TermCell = match (pdx, pdy, dx, dy) {
                (None, None, 1, 0) | (None, None, -1, 0) | (Some(1), _, 1, 0) | (Some(-1), _, -1, 0) => '═',
                (None, None, 0, 1) | (None, None, 0, -1) | (_, Some(1), 0, 1) | (_, Some(-1), 0, -1) => '║',
                (Some(1), _, 0, 1) | (_, Some(-1), -1, 0) => '╗',
                (Some(1), _, 0, -1) | (_, Some(1), -1, 0) => '╝',
                (Some(-1), _, 0, -1) | (_, Some(1), 1, 0) => '╚',
                (Some(-1), _, 0, 1) | (_, Some(-1), 1, 0) => '╔',
                _ => '+',
            }.into();
            c.bg = Some(color);
            window.put_at(cur, c);
            prev = Some(cur);
        }

        let mut tc: TermCell = '◘'.into();
        tc.bg = Some(color);
        window.put_at(self.position, tc);
        // let mut tc: TermCell = '+'.into();
        // tc.bg = Some(color);
        // for point in self.tail.iter() {
        //     window.put_at(*point, tc);
        // }
    }

    pub fn intersects(&self, point: Point) -> bool {
        for t in self.tail.iter() {
            if *t == point {
                return true;
            }
        }
        self.position == point
    }
}
<|endoftext|>


<commit_before>//! Proper testing, with QuickCheck.

use {Trie, TrieKey};
use std::iter::FromIterator;
use std::collections::HashSet;
use quickcheck::{quickcheck, Gen, Arbitrary};
use rand::Rng;

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
struct Key(Vec<u8>);

#[derive(Clone, Debug)]
struct RandomKeys(HashSet<Key>);

const MAX_KEYS: usize = 512;
const KEY_RUN_LEN: usize = 8;
const KEY_MAX_VAL: u8 = 4;

impl Arbitrary for Key {
    fn arbitrary<G: Gen>(g: &mut G) -> Key {
        let len = g.gen::<usize>() % KEY_RUN_LEN;
        let mut key = Vec::with_capacity(len);
        for _ in 0 .. len {
            key.push(g.gen::<u8>() % KEY_MAX_VAL);
        }
        Key(key)
    }
}

impl Key {
    fn extend_random<G: Gen>(&self, g: &mut G) -> Key {
        let mut key = self.clone();
        key.0.extend(Key::arbitrary(g).0);
        key
    }

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

impl TrieKey for Key {
    fn encode(&self) -> Vec<u8> {
        self.0.clone()
    }
}

impl Arbitrary for RandomKeys {
    fn arbitrary<G: Gen>(g: &mut G) -> RandomKeys {
        let num_keys = g.gen::<usize>() % MAX_KEYS;
        let mut keys = Vec::with_capacity(num_keys);
        keys.push(Key::arbitrary(g));

        for _ in 0 .. num_keys {
            match g.gen::<u8>() % 10 {
                // Generate a new random key.
                1 => keys.push(Key::arbitrary(g)),
                // Extend an existing key.
                _ => {
                    let i = g.gen::<usize>() % keys.len();
                    let key = keys[i].extend_random(g);
                    keys.push(key);
                }
            }
        }

        RandomKeys(HashSet::from_iter(keys))
    }
}

#[test]
fn insert_all_remove_all() {
    fn prop(RandomKeys(keys): RandomKeys) -> bool {
        let mut trie = Trie::new();
        let mut length = 0;

        for k in &keys {
            if trie.insert(k.clone(), k.len()).is_some() {
                return false;
            }
            length += 1;
            if trie.len() != length { return false }
        }

        if !trie.check_integrity() { return false }

        for k in &keys {
            if trie.get(&k) != Some(&k.len()) {
                return false;
            }
            if trie.remove(&k) != Some(k.len()) {
                return false;
            }
            length -= 1;
            if trie.len() != length { return false }
            if trie.get(&k).is_some() { return false }
        }
        if !trie.check_integrity() { return false }
        true
    }

    quickcheck(prop as fn(RandomKeys) -> bool);
}

#[test]
fn get_node() {
    fn prop(RandomKeys(keys): RandomKeys) -> bool {
        let half = keys.len() / 2;
        let first_half = keys.iter().take(half).map(|k| (k.clone(), k.len()));
        let trie = Trie::from_iter(first_half);

        // Check node existence for inserted keys.
        for k in keys.iter().take(half) {
            match trie.get_node(&k) {
                Some(node) => if node.value() != Some(&k.len()) { return false },
                None => return false
            }
        }

        // Check that nodes for non-inserted keys don't have values.
        for k in keys.iter().skip(half) {
            if let Some(node) = trie.get_node(&k) {
                if node.value().is_some() { return false }
            }
        }

        true
    }

    quickcheck(prop as fn(RandomKeys) -> bool);
}
<commit_msg>Add some QuickCheck tests for the iterators.<commit_after>//! Proper testing, with QuickCheck.

use {Trie, TrieKey};
use std::iter::FromIterator;
use std::collections::{HashSet, HashMap};
use quickcheck::{quickcheck, Gen, Arbitrary};
use rand::Rng;

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
struct Key(Vec<u8>);

#[derive(Clone, Debug)]
struct RandomKeys(HashSet<Key>);

const MAX_KEYS: usize = 512;
const KEY_RUN_LEN: usize = 8;
const KEY_MAX_VAL: u8 = 4;

impl Arbitrary for Key {
    fn arbitrary<G: Gen>(g: &mut G) -> Key {
        let len = g.gen::<usize>() % KEY_RUN_LEN;
        let mut key = Vec::with_capacity(len);
        for _ in 0 .. len {
            key.push(g.gen::<u8>() % KEY_MAX_VAL);
        }
        Key(key)
    }
}

impl Key {
    fn extend_random<G: Gen>(&self, g: &mut G) -> Key {
        let mut key = self.clone();
        key.0.extend(Key::arbitrary(g).0);
        key
    }

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

impl TrieKey for Key {
    fn encode(&self) -> Vec<u8> {
        self.0.clone()
    }
}

impl Arbitrary for RandomKeys {
    fn arbitrary<G: Gen>(g: &mut G) -> RandomKeys {
        let num_keys = g.gen::<usize>() % MAX_KEYS;
        let mut keys = Vec::with_capacity(num_keys);
        keys.push(Key::arbitrary(g));

        for _ in 0 .. num_keys {
            match g.gen::<u8>() % 10 {
                // Generate a new random key.
                1 => keys.push(Key::arbitrary(g)),
                // Extend an existing key.
                _ => {
                    let i = g.gen::<usize>() % keys.len();
                    let key = keys[i].extend_random(g);
                    keys.push(key);
                }
            }
        }

        RandomKeys(HashSet::from_iter(keys))
    }
}

#[test]
fn insert_all_remove_all() {
    fn prop(RandomKeys(keys): RandomKeys) -> bool {
        let mut trie = Trie::new();
        let mut length = 0;

        for k in &keys {
            if trie.insert(k.clone(), k.len()).is_some() {
                return false;
            }
            length += 1;
            if trie.len() != length { return false }
        }

        if !trie.check_integrity() { return false }

        for k in &keys {
            if trie.get(&k) != Some(&k.len()) {
                return false;
            }
            if trie.remove(&k) != Some(k.len()) {
                return false;
            }
            length -= 1;
            if trie.len() != length { return false }
            if trie.get(&k).is_some() { return false }
        }
        if !trie.check_integrity() { return false }
        true
    }

    quickcheck(prop as fn(RandomKeys) -> bool);
}

#[test]
fn get_node() {
    fn prop(RandomKeys(keys): RandomKeys) -> bool {
        let half = keys.len() / 2;
        let first_half = keys.iter().take(half).map(|k| (k.clone(), k.len()));
        let trie = Trie::from_iter(first_half);

        // Check node existence for inserted keys.
        for k in keys.iter().take(half) {
            match trie.get_node(&k) {
                Some(node) => if node.value() != Some(&k.len()) { return false },
                None => return false
            }
        }

        // Check that nodes for non-inserted keys don't have values.
        for k in keys.iter().skip(half) {
            if let Some(node) = trie.get_node(&k) {
                if node.value().is_some() { return false }
            }
        }

        true
    }

    quickcheck(prop as fn(RandomKeys) -> bool);
}

// Construct a trie from a set of keys, with each key mapped to its length.
fn length_trie(keys: HashSet<Key>) -> Trie<Key, usize> {
    let mut t = Trie::new();
    for k in keys {
        let len = k.len();
        t.insert(k, len);
    }
    t
}

#[test]
fn keys_iter() {
    fn prop(RandomKeys(keys): RandomKeys) -> bool {
        let trie = length_trie(keys.clone());
        let trie_keys: HashSet<Key> = trie.keys().cloned().collect();
        trie_keys == keys
    }
    quickcheck(prop as fn(RandomKeys) -> bool);
}

#[test]
fn values_iter() {
    // Create a map of values to frequencies.
    fn frequency_map<I: Iterator<Item=usize>>(values: I) -> HashMap<usize, u64> {
        let mut map = HashMap::new();
        for v in values {
            let current_val = map.entry(v).or_insert(0);
            *current_val += 1;
        }
        map
    }

    fn prop(RandomKeys(keys): RandomKeys) -> bool {
        let trie = length_trie(keys.clone());
        let trie_values: HashMap<usize, u64> = frequency_map(trie.values().cloned());
        let key_values = frequency_map(keys.into_iter().map(|k| k.len()));
        trie_values == key_values
    }
    quickcheck(prop as fn(RandomKeys) -> bool);
}
<|endoftext|>


<commit_before>//! Endpoints for getting and synchronizing events.

/// GET /_matrix/client/r0/sync
///
/// [Matrix spec link](http://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-sync)
pub mod sync {
    use ruma_identifiers::RoomId;
    use ruma_events::collections::only;
    use std::collections::HashMap;

    /// Details about this API endpoint.
    pub struct Endpoint;

    /// Wether to set presence or not during sync
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub enum SetPresence {
        #[serde(rename="offline")]
        Offline
    }

    /// This API endpoint's query parameters.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct QueryParams {
        #[serde(skip_serializing_if = "Option::is_none")]
        pub filter: Option<String>,
        #[serde(skip_serializing_if = "Option::is_none")]
        pub since: Option<String>,
        #[serde(skip_serializing_if = "Option::is_none")]
        pub full_state: Option<bool>,
        #[serde(skip_serializing_if = "Option::is_none")]
        pub set_presence: Option<SetPresence>,
        #[serde(skip_serializing_if = "Option::is_none")]
        pub timeout: Option<u64>
    }

    /// Updates to rooms
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct Rooms {
        pub leave: HashMap<RoomId, LeftRoom>,
        pub join: HashMap<RoomId, JoinedRoom>,
        pub invite: HashMap<RoomId, InvitedRoom>
    }

    /// Historical updates to left rooms
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct LeftRoom {
        pub timeline: Timeline,
        pub state: State
    }

    /// Updates to joined rooms
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct JoinedRoom {
        pub unread_notifications: UnreadNotificationsCount,
        pub timeline: Timeline,
        pub state: State,
        pub account_data: AccountData,
        pub ephemeral: Ephemeral
    }

    /// unread notifications count
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct UnreadNotificationsCount {
        pub highlight_count: u64,
        pub notification_count: u64
    }

    /// timeline
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct Timeline {
        pub limited: bool,
        pub prev_batch: String,
        pub events: only::RoomEvent
    }

    /// state
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct State {
        pub events: only::StateEvent
    }

    /// account data
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct AccountData {
        pub events: only::Event
    }

    /// ephemeral
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct Ephemeral {
        pub events: only::Event
    }

    /// invited room updates
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct InvitedRoom {
        pub invite_state: InviteState
    }

    /// invite state
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct InviteState {
        pub events: only::StateEvent
    }

    /// presence
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct Presence {
        pub events: only::Event
    }

    /// This API endpoint's reponse.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct Response {
        pub next_batch: String,
        pub rooms: Rooms,
        pub presence: Presence
    }

    impl ::Endpoint for Endpoint {
        type BodyParams = ();
        type PathParams = ();
        type QueryParams = QueryParams;
        type Response = Response;

        fn method() -> ::Method {
            ::Method::Get
        }

        fn request_path(_params: Self::PathParams) -> String {
            "/_matrix/client/r0/sync".to_string()
        }

        fn router_path() -> String {
            "/_matrix/client/r0/sync".to_string()
        }
    }
}
<commit_msg>The filter parameter to /sync can be a full filter definition or a filter ID.<commit_after>//! Endpoints for getting and synchronizing events.

/// GET /_matrix/client/r0/sync
///
/// [Matrix spec link](http://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-sync)
pub mod sync {
    use ruma_events::collections::only;
    use ruma_identifiers::RoomId;

    use std::collections::HashMap;

    use r0::filter::FilterDefinition;

    /// Details about this API endpoint.
    pub struct Endpoint;

    /// Whether to set presence or not during sync.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub enum SetPresence {
        #[serde(rename="offline")]
        Offline
    }

    /// A filter represented either as its full JSON definition or the ID of a saved filter.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub enum Filter {
        /// A complete filter definition serialized to JSON.
        FilterDefinition(FilterDefinition),
        /// The ID of a filter saved on the server.
        FilterId(String),
    }

    /// This API endpoint's query parameters.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct QueryParams {
        #[serde(skip_serializing_if = "Option::is_none")]
        pub filter: Option<Filter>,
        #[serde(skip_serializing_if = "Option::is_none")]
        pub since: Option<String>,
        #[serde(skip_serializing_if = "Option::is_none")]
        pub full_state: Option<bool>,
        #[serde(skip_serializing_if = "Option::is_none")]
        pub set_presence: Option<SetPresence>,
        #[serde(skip_serializing_if = "Option::is_none")]
        pub timeout: Option<u64>
    }

    /// Updates to rooms
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct Rooms {
        pub leave: HashMap<RoomId, LeftRoom>,
        pub join: HashMap<RoomId, JoinedRoom>,
        pub invite: HashMap<RoomId, InvitedRoom>
    }

    /// Historical updates to left rooms
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct LeftRoom {
        pub timeline: Timeline,
        pub state: State
    }

    /// Updates to joined rooms
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct JoinedRoom {
        pub unread_notifications: UnreadNotificationsCount,
        pub timeline: Timeline,
        pub state: State,
        pub account_data: AccountData,
        pub ephemeral: Ephemeral
    }

    /// unread notifications count
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct UnreadNotificationsCount {
        pub highlight_count: u64,
        pub notification_count: u64
    }

    /// timeline
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct Timeline {
        pub limited: bool,
        pub prev_batch: String,
        pub events: only::RoomEvent
    }

    /// state
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct State {
        pub events: only::StateEvent
    }

    /// account data
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct AccountData {
        pub events: only::Event
    }

    /// ephemeral
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct Ephemeral {
        pub events: only::Event
    }

    /// invited room updates
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct InvitedRoom {
        pub invite_state: InviteState
    }

    /// invite state
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct InviteState {
        pub events: only::StateEvent
    }

    /// presence
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct Presence {
        pub events: only::Event
    }

    /// This API endpoint's reponse.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct Response {
        pub next_batch: String,
        pub rooms: Rooms,
        pub presence: Presence
    }

    impl ::Endpoint for Endpoint {
        type BodyParams = ();
        type PathParams = ();
        type QueryParams = QueryParams;
        type Response = Response;

        fn method() -> ::Method {
            ::Method::Get
        }

        fn request_path(_params: Self::PathParams) -> String {
            "/_matrix/client/r0/sync".to_string()
        }

        fn router_path() -> String {
            "/_matrix/client/r0/sync".to_string()
        }
    }
}
<|endoftext|>


<commit_before>use redis;
use redis::{RedisResult, Value, Nil, Okay};
use std::io::{File, IoResult};
use std::io::timer::sleep;
use std::time::duration::Duration;
use std::rand;
use std::rand::distributions::{IndependentSample, Range};
use time;

const DEFAULT_RETRY_COUNT : int = 3;
const DEFAULT_RETRY_DELAY : int = 200;
const CLOCK_DRIFT_FACTOR : f32 = 0.01;
const UNLOCK_SCRIPT : &'static str = r"if redis.call('get',KEYS[1]) == ARGV[1] then
                                        return redis.call('del',KEYS[1])
                                      else
                                        return 0
                                      end";

/// The lock manager.
///
/// Implements the necessary functionality to acquire and release locks
/// and handles the Redis connections.
pub struct RedLock {
    /// List of all Redis clients
    pub servers: Vec<redis::Client>,
    quorum: uint,
    retry_count: int,
    retry_delay: int
}

pub struct Lock<'a> {
    /// The resource to lock. Will be used as the key in Redis.
    pub resource: &'a [u8],
    /// The value for this lock.
    pub val: Vec<u8>,
    /// Time the lock is still valid.
    /// Should only be slightly smaller than the requested TTL.
    pub validity_time: uint
}

impl RedLock {
    /// Create a new lock manager instance, defined by the given Redis connection uris.
    /// Quorum is defined to be N/2+1, with N being the number of given Redis instances.
    ///
    /// Sample URI: `"redis://127.0.0.1:6379"`
    pub fn new(uris: Vec<&str>) -> RedLock {
        let quorum = uris.len() / 2 + 1;
        let mut servers = Vec::with_capacity(uris.len());

        for &uri in uris.iter() {
            servers.push(redis::Client::open(uri).unwrap())
        }

        RedLock {
            servers: servers,
            quorum: quorum,
            retry_count: DEFAULT_RETRY_COUNT,
            retry_delay: DEFAULT_RETRY_DELAY
        }
    }

    /// Get 20 random bytes from `/dev/urandom`.
    pub fn get_unique_lock_id(&self) -> IoResult<Vec<u8>> {
        let mut file = File::open(&Path::new("/dev/urandom"));
        file.read_exact(20)
    }

    /// Set retry count and retry delay.
    ///
    /// Retry count defaults to `3`.
    /// Retry delay defaults to `200`.
    pub fn set_retry(&mut self, count: int, delay: int) {
        self.retry_count = count;
        self.retry_delay = delay;
    }

    fn lock_instance(&self, client: &redis::Client, resource: &[u8], val: &[u8], ttl: uint) -> bool {
        let con = match client.get_connection() {
            Err(_) => return false,
            Ok(val) => val
        };
        let result : RedisResult<Value> = redis::cmd("SET").arg(resource).arg(val).arg("nx").arg("px").arg(ttl).query(&con);
        match result {
            Ok(Okay) => return true,
            Ok(Nil)  => return false,
            Ok(_)    => return false,
            Err(_)   => return false
        }
    }

    fn get_time(&self) -> i64 {
        let time = time::get_time();

        time.sec * 1000 + ((time.nsec/1000000) as i64)
    }

    /// Acquire the lock for the given resource and the requested TTL.
    ///
    /// If it succeeds, a `Lock` instance is returned,
    /// including the value and the validity time
    ///
    /// If it fails. `None` is returned.
    /// A user should retry after a short wait time.
    pub fn lock<'a>(&'a self, resource: &'a [u8], ttl: uint) -> Option<Lock> {
        let val = self.get_unique_lock_id().unwrap();

        let between = Range::new(0, self.retry_delay);
        let mut rng = rand::task_rng();

        for _ in range(0, self.retry_count) {
            let mut n = 0;
            let start_time = self.get_time();
            for &ref client in self.servers.iter() {
                if self.lock_instance(client, resource, val.as_slice(), ttl) {
                    n += 1;
                }
            }

            let drift = (ttl as f32 * CLOCK_DRIFT_FACTOR) as int + 2;
            let validity_time = (ttl as i64 - ((self.get_time() - start_time)) - drift as i64) as uint;

            if n >= self.quorum && validity_time > 0 {
                return Some(Lock {
                    resource: resource.clone(),
                    val: val,
                    validity_time: validity_time
                });
            } else {
                for &ref client in self.servers.iter() {
                    self.unlock_instance(client, resource, val.as_slice());
                }
            }

            let n = between.ind_sample(&mut rng);
            sleep(Duration::milliseconds(n as i64));
        }
        return None
    }

    fn unlock_instance(&self, client: &redis::Client, resource: &[u8], val: &[u8]) -> bool {
        let con = match client.get_connection() {
            Err(_) => return false,
            Ok(val) => val
        };
        let script = redis::Script::new(UNLOCK_SCRIPT);
        let result : RedisResult<int> = script.key(resource).arg(val).invoke(&con);
        match result {
            Ok(val) => return val == 1,
            Err(_)  => return false
        }
    }

    /// Unlock the given lock.
    ///
    /// Unlock is best effort. It will simply try to contact all instances
    /// and remove the key.
    pub fn unlock(&self, lock: &Lock) {
        for &ref client in self.servers.iter() {
            self.unlock_instance(client, lock.resource, lock.val.as_slice());
        }
    }
}

#[test]
fn test_redlock_get_unique_id() {
    let rl = RedLock::new(vec![]);

    match rl.get_unique_lock_id() {
        Ok(id) => {
            assert_eq!(20, id.len());
        },
        err => fail!("Error thrown: {}", err)
    }
}

#[test]
fn test_redlock_get_unique_id_uniqueness() {
    let rl = RedLock::new(vec![]);

    let id1 = rl.get_unique_lock_id().unwrap();
    let id2 = rl.get_unique_lock_id().unwrap();

    assert_eq!(20, id1.len());
    assert_eq!(20, id2.len());
    assert!(id1 != id2);
}

#[test]
fn test_redlock_valid_instance() {
    let rl = RedLock::new(vec!["redis://127.0.0.1:6380/", "redis://127.0.0.1:6381/", "redis://127.0.0.1:6382/", ]);
    assert_eq!(3, rl.servers.len());
    assert_eq!(2, rl.quorum);
}

#[test]
fn test_redlock_direct_unlock_fails() {
    let rl = RedLock::new(vec!["redis://127.0.0.1:6380/", "redis://127.0.0.1:6381/", "redis://127.0.0.1:6382/", ]);
    let key = rl.get_unique_lock_id().unwrap();

    let val = rl.get_unique_lock_id().unwrap();
    assert_eq!(false, rl.unlock_instance(&rl.servers[0], key[], val[]))
}

#[test]
fn test_redlock_direct_unlock_succeeds() {
    let rl = RedLock::new(vec!["redis://127.0.0.1:6380/", "redis://127.0.0.1:6381/", "redis://127.0.0.1:6382/", ]);
    let key = rl.get_unique_lock_id().unwrap();

    let val = rl.get_unique_lock_id().unwrap();
    let con = rl.servers[0].get_connection().unwrap();
    redis::cmd("SET").arg(key[]).arg(val[]).execute(&con);

    assert_eq!(true, rl.unlock_instance(&rl.servers[0], key[], val[]))
}

#[test]
fn test_redlock_direct_lock_succeeds() {
    let rl = RedLock::new(vec!["redis://127.0.0.1:6380/", "redis://127.0.0.1:6381/", "redis://127.0.0.1:6382/", ]);
    let key = rl.get_unique_lock_id().unwrap();

    let val = rl.get_unique_lock_id().unwrap();
    let con = rl.servers[0].get_connection().unwrap();

    redis::cmd("DEL").arg(key[]).execute(&con);
    assert_eq!(true, rl.lock_instance(&rl.servers[0], key[], val[], 1000))
}

#[test]
fn test_redlock_unlock() {
    let rl = RedLock::new(vec!["redis://127.0.0.1:6380/", "redis://127.0.0.1:6381/", "redis://127.0.0.1:6382/", ]);
    let key = rl.get_unique_lock_id().unwrap();

    let val = rl.get_unique_lock_id().unwrap();
    let con = rl.servers[0].get_connection().unwrap();
    let _ : () = redis::cmd("SET").arg(key[]).arg(val[]).query(&con).unwrap();

    let lock = Lock { resource: key[], val: val, validity_time: 0 };
    assert_eq!((), rl.unlock(&lock))
}

#[test]
fn test_redlock_lock() {
    let rl = RedLock::new(vec!["redis://127.0.0.1:6380/", "redis://127.0.0.1:6381/", "redis://127.0.0.1:6382/", ]);

    let key = rl.get_unique_lock_id().unwrap();
    match rl.lock(key[], 1000) {
        Some(lock) => {
            assert_eq!(key[], lock.resource);
            assert_eq!(20, lock.val.len());
            assert!(lock.validity_time > 900);
        },
        None => fail!("Lock failed")
    }
}

#[test]
fn test_redlock_lock_unlock() {
    let rl = RedLock::new(vec!["redis://127.0.0.1:6380/", "redis://127.0.0.1:6381/", "redis://127.0.0.1:6382/", ]);
    let rl2 = RedLock::new(vec!["redis://127.0.0.1:6380/", "redis://127.0.0.1:6381/", "redis://127.0.0.1:6382/", ]);

    let key = rl.get_unique_lock_id().unwrap();

    let lock = rl.lock(key[], 1000).unwrap();
    assert!(lock.validity_time > 900);

    match rl2.lock(key[], 1000) {
        Some(l) => fail!("Lock acquired, even though it should be locked"),
        None => ()
    }

    rl.unlock(&lock);

    match rl2.lock(key[], 1000) {
        Some(l) => assert!(l.validity_time > 900),
        None => fail!("Lock couldn't be acquired")
    }
}
<commit_msg>Patch to work with latest Rust nightly again<commit_after>use redis;
use redis::{RedisResult,Value};
use redis::Value::{Nil, Okay};
use std::io::{File, IoResult};
use std::io::timer::sleep;
use std::time::duration::Duration;
use std::rand;
use std::rand::distributions::{IndependentSample, Range};
use time;

const DEFAULT_RETRY_COUNT : int = 3;
const DEFAULT_RETRY_DELAY : int = 200;
const CLOCK_DRIFT_FACTOR : f32 = 0.01;
const UNLOCK_SCRIPT : &'static str = r"if redis.call('get',KEYS[1]) == ARGV[1] then
                                        return redis.call('del',KEYS[1])
                                      else
                                        return 0
                                      end";

/// The lock manager.
///
/// Implements the necessary functionality to acquire and release locks
/// and handles the Redis connections.
pub struct RedLock {
    /// List of all Redis clients
    pub servers: Vec<redis::Client>,
    quorum: uint,
    retry_count: int,
    retry_delay: int
}

pub struct Lock<'a> {
    /// The resource to lock. Will be used as the key in Redis.
    pub resource: &'a [u8],
    /// The value for this lock.
    pub val: Vec<u8>,
    /// Time the lock is still valid.
    /// Should only be slightly smaller than the requested TTL.
    pub validity_time: uint
}

impl RedLock {
    /// Create a new lock manager instance, defined by the given Redis connection uris.
    /// Quorum is defined to be N/2+1, with N being the number of given Redis instances.
    ///
    /// Sample URI: `"redis://127.0.0.1:6379"`
    pub fn new(uris: Vec<&str>) -> RedLock {
        let quorum = uris.len() / 2 + 1;
        let mut servers = Vec::with_capacity(uris.len());

        for &uri in uris.iter() {
            servers.push(redis::Client::open(uri).unwrap())
        }

        RedLock {
            servers: servers,
            quorum: quorum,
            retry_count: DEFAULT_RETRY_COUNT,
            retry_delay: DEFAULT_RETRY_DELAY
        }
    }

    /// Get 20 random bytes from `/dev/urandom`.
    pub fn get_unique_lock_id(&self) -> IoResult<Vec<u8>> {
        let mut file = File::open(&Path::new("/dev/urandom"));
        file.read_exact(20)
    }

    /// Set retry count and retry delay.
    ///
    /// Retry count defaults to `3`.
    /// Retry delay defaults to `200`.
    pub fn set_retry(&mut self, count: int, delay: int) {
        self.retry_count = count;
        self.retry_delay = delay;
    }

    fn lock_instance(&self, client: &redis::Client, resource: &[u8], val: &[u8], ttl: uint) -> bool {
        let con = match client.get_connection() {
            Err(_) => return false,
            Ok(val) => val
        };
        let result : RedisResult<Value> = redis::cmd("SET").arg(resource).arg(val).arg("nx").arg("px").arg(ttl).query(&con);
        match result {
            Ok(Okay) => return true,
            Ok(Nil)  => return false,
            Ok(_)    => return false,
            Err(_)   => return false
        }
    }

    fn get_time(&self) -> i64 {
        let time = time::get_time();

        time.sec * 1000 + ((time.nsec/1000000) as i64)
    }

    /// Acquire the lock for the given resource and the requested TTL.
    ///
    /// If it succeeds, a `Lock` instance is returned,
    /// including the value and the validity time
    ///
    /// If it fails. `None` is returned.
    /// A user should retry after a short wait time.
    pub fn lock<'a>(&'a self, resource: &'a [u8], ttl: uint) -> Option<Lock> {
        let val = self.get_unique_lock_id().unwrap();

        let between = Range::new(0, self.retry_delay);
        let mut rng = rand::task_rng();

        for _ in range(0, self.retry_count) {
            let mut n = 0;
            let start_time = self.get_time();
            for &ref client in self.servers.iter() {
                if self.lock_instance(client, resource, val.as_slice(), ttl) {
                    n += 1;
                }
            }

            let drift = (ttl as f32 * CLOCK_DRIFT_FACTOR) as int + 2;
            let validity_time = (ttl as i64 - ((self.get_time() - start_time)) - drift as i64) as uint;

            if n >= self.quorum && validity_time > 0 {
                return Some(Lock {
                    resource: resource.clone(),
                    val: val,
                    validity_time: validity_time
                });
            } else {
                for &ref client in self.servers.iter() {
                    self.unlock_instance(client, resource, val.as_slice());
                }
            }

            let n = between.ind_sample(&mut rng);
            sleep(Duration::milliseconds(n as i64));
        }
        return None
    }

    fn unlock_instance(&self, client: &redis::Client, resource: &[u8], val: &[u8]) -> bool {
        let con = match client.get_connection() {
            Err(_) => return false,
            Ok(val) => val
        };
        let script = redis::Script::new(UNLOCK_SCRIPT);
        let result : RedisResult<int> = script.key(resource).arg(val).invoke(&con);
        match result {
            Ok(val) => return val == 1,
            Err(_)  => return false
        }
    }

    /// Unlock the given lock.
    ///
    /// Unlock is best effort. It will simply try to contact all instances
    /// and remove the key.
    pub fn unlock(&self, lock: &Lock) {
        for &ref client in self.servers.iter() {
            self.unlock_instance(client, lock.resource, lock.val.as_slice());
        }
    }
}

#[test]
fn test_redlock_get_unique_id() {
    let rl = RedLock::new(vec![]);

    match rl.get_unique_lock_id() {
        Ok(id) => {
            assert_eq!(20, id.len());
        },
        err => panic!("Error thrown: {}", err)
    }
}

#[test]
fn test_redlock_get_unique_id_uniqueness() {
    let rl = RedLock::new(vec![]);

    let id1 = rl.get_unique_lock_id().unwrap();
    let id2 = rl.get_unique_lock_id().unwrap();

    assert_eq!(20, id1.len());
    assert_eq!(20, id2.len());
    assert!(id1 != id2);
}

#[test]
fn test_redlock_valid_instance() {
    let rl = RedLock::new(vec!["redis://127.0.0.1:6380/", "redis://127.0.0.1:6381/", "redis://127.0.0.1:6382/", ]);
    assert_eq!(3, rl.servers.len());
    assert_eq!(2, rl.quorum);
}

#[test]
fn test_redlock_direct_unlock_fails() {
    let rl = RedLock::new(vec!["redis://127.0.0.1:6380/", "redis://127.0.0.1:6381/", "redis://127.0.0.1:6382/", ]);
    let key = rl.get_unique_lock_id().unwrap();

    let val = rl.get_unique_lock_id().unwrap();
    assert_eq!(false, rl.unlock_instance(&rl.servers[0], key[], val[]))
}

#[test]
fn test_redlock_direct_unlock_succeeds() {
    let rl = RedLock::new(vec!["redis://127.0.0.1:6380/", "redis://127.0.0.1:6381/", "redis://127.0.0.1:6382/", ]);
    let key = rl.get_unique_lock_id().unwrap();

    let val = rl.get_unique_lock_id().unwrap();
    let con = rl.servers[0].get_connection().unwrap();
    redis::cmd("SET").arg(key[]).arg(val[]).execute(&con);

    assert_eq!(true, rl.unlock_instance(&rl.servers[0], key[], val[]))
}

#[test]
fn test_redlock_direct_lock_succeeds() {
    let rl = RedLock::new(vec!["redis://127.0.0.1:6380/", "redis://127.0.0.1:6381/", "redis://127.0.0.1:6382/", ]);
    let key = rl.get_unique_lock_id().unwrap();

    let val = rl.get_unique_lock_id().unwrap();
    let con = rl.servers[0].get_connection().unwrap();

    redis::cmd("DEL").arg(key[]).execute(&con);
    assert_eq!(true, rl.lock_instance(&rl.servers[0], key[], val[], 1000))
}

#[test]
fn test_redlock_unlock() {
    let rl = RedLock::new(vec!["redis://127.0.0.1:6380/", "redis://127.0.0.1:6381/", "redis://127.0.0.1:6382/", ]);
    let key = rl.get_unique_lock_id().unwrap();

    let val = rl.get_unique_lock_id().unwrap();
    let con = rl.servers[0].get_connection().unwrap();
    let _ : () = redis::cmd("SET").arg(key[]).arg(val[]).query(&con).unwrap();

    let lock = Lock { resource: key[], val: val, validity_time: 0 };
    assert_eq!((), rl.unlock(&lock))
}

#[test]
fn test_redlock_lock() {
    let rl = RedLock::new(vec!["redis://127.0.0.1:6380/", "redis://127.0.0.1:6381/", "redis://127.0.0.1:6382/", ]);

    let key = rl.get_unique_lock_id().unwrap();
    match rl.lock(key[], 1000) {
        Some(lock) => {
            assert_eq!(key[], lock.resource);
            assert_eq!(20, lock.val.len());
            assert!(lock.validity_time > 900);
        },
        None => panic!("Lock failed")
    }
}

#[test]
fn test_redlock_lock_unlock() {
    let rl = RedLock::new(vec!["redis://127.0.0.1:6380/", "redis://127.0.0.1:6381/", "redis://127.0.0.1:6382/", ]);
    let rl2 = RedLock::new(vec!["redis://127.0.0.1:6380/", "redis://127.0.0.1:6381/", "redis://127.0.0.1:6382/", ]);

    let key = rl.get_unique_lock_id().unwrap();

    let lock = rl.lock(key[], 1000).unwrap();
    assert!(lock.validity_time > 900);

    match rl2.lock(key[], 1000) {
        Some(_l) => panic!("Lock acquired, even though it should be locked"),
        None => ()
    }

    rl.unlock(&lock);

    match rl2.lock(key[], 1000) {
        Some(l) => assert!(l.validity_time > 900),
        None => panic!("Lock couldn't be acquired")
    }
}
<|endoftext|>


<commit_before>use std::io::IoResult;
use std::io::net::ip;
use {Header, HTTPVersion, Method, Response, StatusCode};

/// Represents an HTTP request made by a client.
///
/// A `Request` object is what is produced by the server, and is your what
///  your code must analyse and answer.
///
/// This object implements the `Send` trait, therefore you can dispatch your requests to
///  worker threads.
///
/// It is possible that multiple requests objects are simultaneously linked to the same client,
///  but don't worry: tiny-http automatically handles synchronization of the answers.
///
/// If a `Request` object is destroyed without `into_writer` or `respond` being called,
///  an empty response with a 500 status code (internal server error) will automatically be
///  sent back to the client.
/// This means that if your code fails during the handling of a request, this "internal server
///  error" response will automatically be sent during the stack unwinding.
#[unstable]
pub struct Request {
    // where to read the body from
    data_reader: Box<Reader + Send>,

    // if this writer is empty, then the request has been answered
    response_writer: Option<Box<Writer + Send>>,

    remote_addr: ip::SocketAddr,

    method: Method,

    path: ::url::Path,

    http_version: HTTPVersion,

    headers: Vec<Header>,

    body_length: Option<uint>,
}

// this trait is to make sure that Request implements Send
trait MustBeSendDummy : Send {}
impl MustBeSendDummy for Request {}

/// Builds a new request
pub fn new_request<R: Reader + Send, W: Writer + Send>(method: Method, path: ::url::Path,
                             version: HTTPVersion, headers: Vec<Header>,
                             remote_addr: ip::SocketAddr, mut source_data: R, writer: W)
    -> IoResult<Request>
{
    // finding length of body
    // TODO: handle transfer-encoding
    let body_length = headers.iter()
        .find(|h: &&Header| h.field.equiv(&"Content-Length"))
        .and_then(|h| from_str::<uint>(h.value.as_slice()))
        .unwrap_or(0u);

    let reader =
        if body_length == 0 {
            use std::io::util::NullReader;
            box NullReader as Box<Reader + Send>

        } else if body_length <= 1024 {
            use std::io::MemReader;
            let data = try!(source_data.read_exact(body_length));
            box MemReader::new(data) as Box<Reader + Send>

        } else {
            use util::EqualReader;
            let (data_reader, _) = EqualReader::new(source_data, body_length);   // TODO:
            box data_reader as Box<Reader + Send>
        };

    Ok(Request {
        data_reader: reader,
        response_writer: Some(box writer as Box<Writer + Send>),
        remote_addr: remote_addr,
        method: method,
        path: path,
        http_version: version,
        headers: headers,
        body_length: Some(body_length),
    })
}

impl Request {
    /// Returns the method requested by the client (eg. `GET`, `POST`, etc.).
    #[stable]
    pub fn get_method<'a>(&'a self) -> &'a Method {
        &self.method
    }

    /// Returns the resource requested by the client.
    #[unstable]
    pub fn get_url<'a>(&'a self) -> &'a ::url::Path {
        &self.path
    }

    /// Returns a list of all headers sent by the client.
    #[stable]
    pub fn get_headers<'a>(&'a self) -> &'a [Header] {
        self.headers.as_slice()
    }

    /// Returns the HTTP version of the request.
    #[unstable]
    pub fn get_http_version<'a>(&'a self) -> &'a HTTPVersion {
        &self.http_version
    }

    /// Returns the length of the body in bytes.
    ///
    /// Returns `None` if the length is unknown.
    #[unstable]
    pub fn get_body_length(&self) -> Option<uint> {
        self.body_length
    }

    /// Returns the length of the body in bytes.
    #[stable]
    pub fn get_remote_addr<'a>(&'a self) -> &'a ip::SocketAddr {
        &self.remote_addr
    }

    /// Allows to read the body of the request.
    ///
    /// # Example
    ///
    /// ```
    /// let request = server.recv();
    ///
    /// if get_content_type(&request) == "application/json" {
    ///     let json: Json = from_str(request.as_reader().read_to_string()).unwrap();
    /// }
    /// ```
    #[unstable]
    pub fn as_reader<'a>(&'a mut self) -> &'a mut Reader {
        fn passthrough<'a>(r: &'a mut Reader) -> &'a mut Reader { r }
        passthrough(self.data_reader)
    }

    /// Turns the `Request` into a writer.
    ///
    /// The writer has a raw access to the stream to the user.
    /// This function is useful for things like CGI.
    ///
    /// Note that the destruction of the `Writer` object may trigger
    ///  some events. For exemple if a client has sent multiple requests and the requests
    ///  have been processed in parallel, the destruction of a writer will trigger
    ///  the writing of the next response.
    /// Therefore you should always destroy the `Writer` as soon as possible.
    #[stable]
    pub fn into_writer(mut self) -> Box<Writer + Send> {
        self.into_writer_impl()
    }

    fn into_writer_impl(&mut self) -> Box<Writer + Send> {
        use std::mem;

        assert!(self.response_writer.is_some());

        let mut writer = None;
        mem::swap(&mut self.response_writer, &mut writer);
        writer.unwrap()
    }

    /// Sends a response to this request.
    #[unstable]
    pub fn respond<R: Reader>(mut self, response: Response<R>) {
        self.respond_impl(response)
    }

    fn respond_impl<R: Reader>(&mut self, response: Response<R>) {
        use std::io;

        fn passthrough<'a>(w: &'a mut Writer) -> &'a mut Writer { w }
        let mut writer = self.into_writer_impl();

        let do_not_send_body = self.method.equiv(&"HEAD");

        match response.raw_print(passthrough(writer),
                                self.http_version, self.headers.as_slice(),
                                do_not_send_body)
        {
            Ok(_) => (),
            Err(ref err) if err.kind == io::Closed => (),
            Err(ref err) if err.kind == io::BrokenPipe => (),
            Err(ref err) if err.kind == io::ConnectionAborted => (),
            Err(ref err) if err.kind == io::ConnectionRefused => (),
            Err(ref err) if err.kind == io::ConnectionReset => (),
            Err(ref err) =>
                println!("error while sending answer: {}", err)     // TODO: handle better?
        };

        writer.flush().ok();
    }
}

impl ::std::fmt::Show for Request {
    fn fmt(&self, formatter: &mut ::std::fmt::Formatter)
        -> Result<(), ::std::fmt::FormatError>
    {
        (format!("Request({} {} from {})",
            self.method, self.path, self.remote_addr.ip)).fmt(formatter)
    }
}

impl Drop for Request {
    fn drop(&mut self) {
        if self.response_writer.is_some() {
            let response = Response::new_empty(StatusCode(500));
            self.respond_impl(response);
        }
    }
}
<commit_msg>Experimental implementation of decoding input chunks<commit_after>use std::io::IoResult;
use std::io::net::ip;
use {Header, HTTPVersion, Method, Response, StatusCode};

/// Represents an HTTP request made by a client.
///
/// A `Request` object is what is produced by the server, and is your what
///  your code must analyse and answer.
///
/// This object implements the `Send` trait, therefore you can dispatch your requests to
///  worker threads.
///
/// It is possible that multiple requests objects are simultaneously linked to the same client,
///  but don't worry: tiny-http automatically handles synchronization of the answers.
///
/// If a `Request` object is destroyed without `into_writer` or `respond` being called,
///  an empty response with a 500 status code (internal server error) will automatically be
///  sent back to the client.
/// This means that if your code fails during the handling of a request, this "internal server
///  error" response will automatically be sent during the stack unwinding.
#[unstable]
pub struct Request {
    // where to read the body from
    data_reader: Box<Reader + Send>,

    // if this writer is empty, then the request has been answered
    response_writer: Option<Box<Writer + Send>>,

    remote_addr: ip::SocketAddr,

    method: Method,

    path: ::url::Path,

    http_version: HTTPVersion,

    headers: Vec<Header>,

    body_length: Option<uint>,
}

// this trait is to make sure that Request implements Send
trait MustBeSendDummy : Send {}
impl MustBeSendDummy for Request {}

/// Builds a new request
pub fn new_request<R: Reader + Send, W: Writer + Send>(method: Method, path: ::url::Path,
                             version: HTTPVersion, headers: Vec<Header>,
                             remote_addr: ip::SocketAddr, mut source_data: R, writer: W)
    -> IoResult<Request>
{
    // finding the transfer-encoding header
    let transfer_encoding = headers.iter()
        .find(|h: &&Header| h.field.equiv(&"Transfer-Encoding"))
        .map(|h| h.value.clone());

    // finding the content-length header
    let content_length = if transfer_encoding.is_some() {
        // if transfer-encoding is specified, the Content-Length
        //  header must be ignored (RFC2616 #4.4)
        None

    } else {
        headers.iter()
            .find(|h: &&Header| h.field.equiv(&"Content-Length"))
            .and_then(|h| from_str::<uint>(h.value.as_slice()))
    };

    // building the reader depending on
    //  transfer-encoding and content-length
    let reader =
        if content_length.is_some() {
            let content_length = content_length.as_ref().unwrap().clone();

            if content_length == 0 {
                use std::io::util::NullReader;
                box NullReader as Box<Reader + Send>

            } else if content_length <= 1024 {
                use std::io::MemReader;
                let data = try!(source_data.read_exact(content_length));
                box MemReader::new(data) as Box<Reader + Send>

            } else {
                use util::EqualReader;
                let (data_reader, _) = EqualReader::new(source_data, content_length);   // TODO:
                box data_reader as Box<Reader + Send>
            }

        } else if transfer_encoding.is_some() {
            // if a transfer-encoding was specified, then "chunked"
            //  is ALWAYS applied over the message (RFC2616 #3.6)
            use util::ChunksDecoder;
            box ChunksDecoder::new(source_data) as Box<Reader + Send>

        } else {
            // if we have neither a Content-Length nor a Transfer-Encoding,
            //  assuming that we have no data
            // TODO: could also be multipart/byteranges
            use std::io::util::NullReader;
            box NullReader as Box<Reader + Send>
        };

    Ok(Request {
        data_reader: reader,
        response_writer: Some(box writer as Box<Writer + Send>),
        remote_addr: remote_addr,
        method: method,
        path: path,
        http_version: version,
        headers: headers,
        body_length: content_length,
    })
}

impl Request {
    /// Returns the method requested by the client (eg. `GET`, `POST`, etc.).
    #[stable]
    pub fn get_method<'a>(&'a self) -> &'a Method {
        &self.method
    }

    /// Returns the resource requested by the client.
    #[unstable]
    pub fn get_url<'a>(&'a self) -> &'a ::url::Path {
        &self.path
    }

    /// Returns a list of all headers sent by the client.
    #[stable]
    pub fn get_headers<'a>(&'a self) -> &'a [Header] {
        self.headers.as_slice()
    }

    /// Returns the HTTP version of the request.
    #[unstable]
    pub fn get_http_version<'a>(&'a self) -> &'a HTTPVersion {
        &self.http_version
    }

    /// Returns the length of the body in bytes.
    ///
    /// Returns `None` if the length is unknown.
    #[unstable]
    pub fn get_body_length(&self) -> Option<uint> {
        self.body_length
    }

    /// Returns the length of the body in bytes.
    #[stable]
    pub fn get_remote_addr<'a>(&'a self) -> &'a ip::SocketAddr {
        &self.remote_addr
    }

    /// Allows to read the body of the request.
    ///
    /// # Example
    ///
    /// ```
    /// let request = server.recv();
    ///
    /// if get_content_type(&request) == "application/json" {
    ///     let json: Json = from_str(request.as_reader().read_to_string()).unwrap();
    /// }
    /// ```
    #[unstable]
    pub fn as_reader<'a>(&'a mut self) -> &'a mut Reader {
        fn passthrough<'a>(r: &'a mut Reader) -> &'a mut Reader { r }
        passthrough(self.data_reader)
    }

    /// Turns the `Request` into a writer.
    ///
    /// The writer has a raw access to the stream to the user.
    /// This function is useful for things like CGI.
    ///
    /// Note that the destruction of the `Writer` object may trigger
    ///  some events. For exemple if a client has sent multiple requests and the requests
    ///  have been processed in parallel, the destruction of a writer will trigger
    ///  the writing of the next response.
    /// Therefore you should always destroy the `Writer` as soon as possible.
    #[stable]
    pub fn into_writer(mut self) -> Box<Writer + Send> {
        self.into_writer_impl()
    }

    fn into_writer_impl(&mut self) -> Box<Writer + Send> {
        use std::mem;

        assert!(self.response_writer.is_some());

        let mut writer = None;
        mem::swap(&mut self.response_writer, &mut writer);
        writer.unwrap()
    }

    /// Sends a response to this request.
    #[unstable]
    pub fn respond<R: Reader>(mut self, response: Response<R>) {
        self.respond_impl(response)
    }

    fn respond_impl<R: Reader>(&mut self, response: Response<R>) {
        use std::io;

        fn passthrough<'a>(w: &'a mut Writer) -> &'a mut Writer { w }
        let mut writer = self.into_writer_impl();

        let do_not_send_body = self.method.equiv(&"HEAD");

        match response.raw_print(passthrough(writer),
                                self.http_version, self.headers.as_slice(),
                                do_not_send_body)
        {
            Ok(_) => (),
            Err(ref err) if err.kind == io::Closed => (),
            Err(ref err) if err.kind == io::BrokenPipe => (),
            Err(ref err) if err.kind == io::ConnectionAborted => (),
            Err(ref err) if err.kind == io::ConnectionRefused => (),
            Err(ref err) if err.kind == io::ConnectionReset => (),
            Err(ref err) =>
                println!("error while sending answer: {}", err)     // TODO: handle better?
        };

        writer.flush().ok();
    }
}

impl ::std::fmt::Show for Request {
    fn fmt(&self, formatter: &mut ::std::fmt::Formatter)
        -> Result<(), ::std::fmt::FormatError>
    {
        (format!("Request({} {} from {})",
            self.method, self.path, self.remote_addr.ip)).fmt(formatter)
    }
}

impl Drop for Request {
    fn drop(&mut self) {
        if self.response_writer.is_some() {
            let response = Response::new_empty(StatusCode(500));
            self.respond_impl(response);
        }
    }
}
<|endoftext|>