<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", Objective::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).lt(100);
/// problem += a.gt(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>Fix documentation examples<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 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);
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::process::{Command, Stdio};
use std::io::prelude::*;
use std::io::BufReader;

const PROBLEMS_DIR: &'static str = "problems";
const INPUT_DIR: &'static str = "input";
const OUTPUT_DIR: &'static str = "output";

pub struct Problem {
	str_id: String,
	statement: Vec<String>,
	name: Vec<String>,
	authors: Vec<String>,
}

enum State {
	Default,
	Name,
	Statement,
	Authors,
}

impl Problem {
	pub fn new(str_id: String) -> Problem {
		let mut statement = vec![];
		let mut name = vec![];
		let mut authors = vec![];
		match File::open(format!("{}/{}/info.txt", PROBLEMS_DIR, str_id)) {
			Ok(file) => {
				let buf = BufReader::new(&file);
				let mut state = State::Default;
				for line in buf.lines()  {
					let l = line.unwrap();
					match l.as_ref() {
						"[authors]" => state = State::Authors,
						"[name]" => state = State::Name,
						"[statement]" => state = State::Statement,
						"[end]" => break,
						_ => {
							match state {
								State::Authors => authors.push(l.trim().to_string()),
								State::Name => name.push(l.trim().to_string()),
								State::Statement => statement.push(l.trim().to_string()),
								_ => continue
							}
						}
					}
				}
			},
			Err(err) => println!("Unable to load problem \"{}\" info: {}", str_id, err),
		};
		Problem {
			str_id: str_id,
			statement: statement,
			name: name,
			authors: authors,
		}
	}

	pub fn run(&self) {
		let builder = Command::new("rustc")
			.arg(format!("{}/{}/{}.rs", PROBLEMS_DIR, self.str_id, self.str_id))
			.arg("--out-dir")
			.arg(format!("{}/{}", PROBLEMS_DIR, self.str_id))
			.output()
			.unwrap_or_else(|e| { panic!("failed to execute process: {}", e) });

		if builder.status.success() {
			self.run_test(1);
		} else {
			let s = String::from_utf8_lossy(&builder.stderr);
			panic!("rustc failed to build problem {}:\n{}", self.str_id, s);
		}
	}

	fn run_test(&self, test_no: u32) {
		let mut input = File::open(format!("{}/{}/{}/{}.txt", PROBLEMS_DIR, self.str_id, INPUT_DIR, test_no))
			.unwrap_or_else(|e| { panic!("failed to load test \"{}\": {}", test_no, e) });
		let mut s = String::new(); // passing throw String coz as_slice still unstable
		input.read_to_string(&mut s)
			.unwrap_or_else(|e| { panic!("couldn't read test \"{}\" file: {}", test_no, e) });

		let problem = Command::new(format!("{}/{}/{}", PROBLEMS_DIR, self.str_id, self.str_id))
			.stdin(Stdio::piped())
        	.stdout(Stdio::piped())
			.spawn()
			.unwrap_or_else(|e| { panic!("failed to execute test \"{}\": {}", test_no, e) });

        problem.stdin.unwrap().write_all(s.as_bytes())
        	.unwrap_or_else(|e| { panic!("couldn't write stdin test \"{}\": {}", test_no, e) });
        {
		    let mut s = String::new(); // passing throw String coz as_slice still unstable
		    problem.stdout.unwrap().read_to_string(&mut s)
		    	.unwrap_or_else(|e| { panic!("couldn't read stdout test \"{}\": {}", test_no, e) });

		    let mut output = File::create(format!("{}/{}/{}/{}.txt", PROBLEMS_DIR, self.str_id, OUTPUT_DIR, test_no))
				.unwrap_or_else(|e| { panic!("failed to save test \"{}\" output: {}", test_no, e) });

			output.write_all(s.as_bytes())
				.unwrap_or_else(|e| { panic!("couldn't write test \"{}\" answer: {}", test_no, e) });
		}
	}
}

#[test]
fn read_test() {
	let p = Problem::new("test".to_string());
	assert_eq!(p.str_id, "test");
	assert_eq!(p.authors, vec!["Testhor", "qwerty"]);
	assert_eq!(p.name, vec!["Test name", "check"]);
	assert_eq!(p.statement, vec!["Test statement", "3", "4"]);
	p.run();
}<commit_msg>Fixed tabs<commit_after>use std::fs::File;
use std::process::{Command, Stdio};
use std::io::prelude::*;
use std::io::BufReader;

const PROBLEMS_DIR: &'static str = "problems";
const INPUT_DIR: &'static str = "input";
const OUTPUT_DIR: &'static str = "output";

pub struct Problem {
	str_id: String,
	statement: Vec<String>,
	name: Vec<String>,
	authors: Vec<String>,
}

enum State {
	Default,
	Name,
	Statement,
	Authors,
}

impl Problem {
	pub fn new(str_id: String) -> Problem {
		let mut statement = vec![];
		let mut name = vec![];
		let mut authors = vec![];
		match File::open(format!("{}/{}/info.txt", PROBLEMS_DIR, str_id)) {
			Ok(file) => {
				let buf = BufReader::new(&file);
				let mut state = State::Default;
				for line in buf.lines()  {
					let l = line.unwrap();
					match l.as_ref() {
						"[authors]" => state = State::Authors,
						"[name]" => state = State::Name,
						"[statement]" => state = State::Statement,
						"[end]" => break,
						_ => {
							match state {
								State::Authors => authors.push(l.trim().to_string()),
								State::Name => name.push(l.trim().to_string()),
								State::Statement => statement.push(l.trim().to_string()),
								_ => continue
							}
						}
					}
				}
			},
			Err(err) => println!("Unable to load problem \"{}\" info: {}", str_id, err),
		};
		Problem {
			str_id: str_id,
			statement: statement,
			name: name,
			authors: authors,
		}
	}

	pub fn run(&self) {
		let builder = Command::new("rustc")
			.arg(format!("{}/{}/{}.rs", PROBLEMS_DIR, self.str_id, self.str_id))
			.arg("--out-dir")
			.arg(format!("{}/{}", PROBLEMS_DIR, self.str_id))
			.output()
			.unwrap_or_else(|e| { panic!("failed to execute process: {}", e) });

		if builder.status.success() {
			self.run_test(1);
		} else {
			let s = String::from_utf8_lossy(&builder.stderr);
			panic!("rustc failed to build problem {}:\n{}", self.str_id, s);
		}
	}

	fn run_test(&self, test_no: u32) {
		let mut input = File::open(format!("{}/{}/{}/{}.txt", PROBLEMS_DIR, self.str_id, INPUT_DIR, test_no))
			.unwrap_or_else(|e| { panic!("failed to load test \"{}\": {}", test_no, e) });
		let mut s = String::new(); // passing throw String coz as_slice still unstable
		input.read_to_string(&mut s)
			.unwrap_or_else(|e| { panic!("couldn't read test \"{}\" file: {}", test_no, e) });

		let problem = Command::new(format!("{}/{}/{}", PROBLEMS_DIR, self.str_id, self.str_id))
			.stdin(Stdio::piped())
			.stdout(Stdio::piped())
			.spawn()
			.unwrap_or_else(|e| { panic!("failed to execute test \"{}\": {}", test_no, e) });

		problem.stdin.unwrap().write_all(s.as_bytes())
			.unwrap_or_else(|e| { panic!("couldn't write stdin test \"{}\": {}", test_no, e) });
		{
			let mut s = String::new(); // passing throw String coz as_slice still unstable
			problem.stdout.unwrap().read_to_string(&mut s)
				.unwrap_or_else(|e| { panic!("couldn't read stdout test \"{}\": {}", test_no, e) });

			let mut output = File::create(format!("{}/{}/{}/{}.txt", PROBLEMS_DIR, self.str_id, OUTPUT_DIR, test_no))
				.unwrap_or_else(|e| { panic!("failed to save test \"{}\" output: {}", test_no, e) });

			output.write_all(s.as_bytes())
				.unwrap_or_else(|e| { panic!("couldn't write test \"{}\" answer: {}", test_no, e) });
		}
	}
}

#[test]
fn read_test() {
	let p = Problem::new("test".to_string());
	assert_eq!(p.str_id, "test");
	assert_eq!(p.authors, vec!["Testhor", "qwerty"]);
	assert_eq!(p.name, vec!["Test name", "check"]);
	assert_eq!(p.statement, vec!["Test statement", "3", "4"]);
	p.run();
}<|endoftext|>


<commit_before>use std::path::PathBuf;

pub use self::imp::*;

#[cfg(target_family = "unix")]
mod imp {
    use std::io::Result;
    use std::path::PathBuf;
    use std::process::Command;

    pub struct Process {
        pid: i32,
    }

    impl Process {
        pub fn new(cmd: &str, updated_paths: Vec<PathBuf>) -> Result<Process> {
            use std::io;
            use std::os::unix::process::CommandExt;
            use nix::unistd::*;

            let mut command = Command::new("sh");
            command.arg("-c").arg(cmd);

            if let Some(single_path) = super::get_single_updated_path(&updated_paths) {
                command.env("WATCHEXEC_UPDATED_PATH", single_path);
            }

            if let Some(common_path) = super::get_longest_common_path(&updated_paths) {
                command.env("WATCHEXEC_COMMON_PATH", common_path);
            }

            // Until process_exec lands in stable, handle fork/exec ourselves
            //command.before_exec(|| setpgid(0, 0).map_err(io::Error::from))
                //.spawn()
                //.and_then(|p| Ok(Process { pid: p.id() as i32 }))

            match fork() {
                Ok(ForkResult::Parent {child, .. }) => {
                    Ok(Process {
                        pid: child as i32
                    })
                },
                Ok(ForkResult::Child) => {
                    let _ = setpgid(0, 0);
                    let e = command.exec();

                    Err(e)
                }
                Err(e) => { Err(io::Error::from(e)) }
            }
        }

        pub fn kill(&self) {
            use libc;

            extern "C" {
                fn killpg(pgrp: libc::pid_t, sig: libc::c_int) -> libc::c_int;
            }

            unsafe {
                killpg(self.pid, libc::SIGTERM);
            }
        }

        pub fn wait(&self) {
            use nix::sys::wait::waitpid;

            let _ = waitpid(-self.pid, None);
        }
    }
}

#[cfg(target_family = "windows")]
mod imp {
    use std::io;
    use std::io::Result;
    use std::mem;
    use std::path::PathBuf;
    use std::process::Command;
    use kernel32::*;
    use winapi::*;

    pub struct Process {
        job: HANDLE,
    }

    impl Process {
        pub fn new(cmd: &str, updated_paths: Vec<PathBuf>) -> Result<Process> {
            use std::os::windows::io::IntoRawHandle;

            fn last_err() -> io::Error {
                io::Error::last_os_error()
            }

            let job = unsafe { CreateJobObjectW(0 as *mut _, 0 as *const _) };
            if job.is_null() {
                panic!("failed to create job object: {}", last_err());
            }

            let mut info: JOBOBJECT_EXTENDED_LIMIT_INFORMATION = unsafe { mem::zeroed() };
            info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
            let r = unsafe {
                SetInformationJobObject(job,
                                        JobObjectExtendedLimitInformation,
                                        &mut info as *mut _ as LPVOID,
                                        mem::size_of_val(&info) as DWORD)
            };
            if r == 0 {
                panic!("failed to set job info: {}", last_err());
            }

            let mut command = Command::new("cmd.exe");
            command.arg("/C").arg(cmd);

            if let Some(single_path) = super::get_single_updated_path(&updated_paths) {
                command.env("WATCHEXEC_UPDATED_PATH", single_path);
            }

            if let Some(common_path) = super::get_longest_common_path(&updated_paths) {
                command.env("WATCHEXEC_COMMON_PATH", common_path);
            }

            command.spawn()
                .and_then(|p| {
                    let r = unsafe { AssignProcessToJobObject(job, p.into_raw_handle()) };
                    if r == 0 {
                        panic!("failed to add to job object: {}", last_err());
                    }

                    Ok(Process { job: job })
                })
        }

        pub fn kill(&self) {
            unsafe {
                let _ = TerminateJobObject(self.job, 1);
            }
        }

        pub fn wait(&self) {
            unsafe {
                let _ = WaitForSingleObject(self.job, INFINITE);
            }
        }
    }

    impl Drop for Process {
        fn drop(&mut self) {
            unsafe {
                let _ = CloseHandle(self.job);
            }
        }
    }

    unsafe impl Send for Process {}
    unsafe impl Sync for Process {}
}

fn get_single_updated_path(paths: &[PathBuf]) -> Option<&str> {
    paths.get(0).and_then(|p| p.to_str())
}

fn get_longest_common_path(paths: &[PathBuf]) -> Option<String> {
    match paths.len() {
        0 => return None,
        1 => return paths[0].to_str().map(|ref_val| ref_val.to_string()),
        _ => {}
    };

    let mut longest_path: Vec<_> = paths[0].components().collect();

    for path in &paths[1..] {
        let mut greatest_distance = 0;
        for component_pair in path.components().zip(longest_path.iter()) {
            if component_pair.0 != *component_pair.1 {
                break;
            }

            greatest_distance += 1;
        }

        if greatest_distance != longest_path.len() {
            longest_path.truncate(greatest_distance);
        }
    }

    let mut result = PathBuf::new();
    for component in longest_path {
        result.push(component.as_os_str());
    }

    result.to_str().map(|ref_val| ref_val.to_string())
}

#[cfg(test)]
#[cfg(target_family = "unix")]
mod tests {
    use std::path::{Path, PathBuf};
    use std::thread;
    use std::time::Duration;

    use mktemp::Temp;

    use super::imp::Process;
    use super::get_longest_common_path;

    fn file_contents(path: &Path) -> String {
        use std::fs::File;
        use std::io::Read;

        let mut f = File::open(path).unwrap();
        let mut s = String::new();
        f.read_to_string(&mut s).unwrap();

        s
    }

    #[test]
    fn test_start() {
        let process = Process::new("echo hi", vec![]);

        assert!(process.is_ok());
    }

    #[test]
    fn test_wait() {
        let file = Temp::new_file().unwrap();
        let path = file.to_path_buf();
        let process = Process::new(&format!("echo hi > {}", path.to_str().unwrap()), vec![])
            .unwrap();
        process.wait();

        assert!(file_contents(&path).starts_with("hi"));
    }

    #[test]
    fn test_kill() {
        let file = Temp::new_file().unwrap();
        let path = file.to_path_buf();

        let process = Process::new(&format!("sleep 20; echo hi > {}", path.to_str().unwrap()),
                                       vec![])
            .unwrap();
        thread::sleep(Duration::from_millis(250));
        process.kill();
        process.wait();

        assert!(file_contents(&path) == "");
    }

    #[test]
    fn longest_common_path_should_return_correct_value() {
        let single_path = vec![PathBuf::from("/tmp/random/")];
        let single_result = get_longest_common_path(&single_path).unwrap();
        assert_eq!(single_result, "/tmp/random/");

        let common_paths = vec![PathBuf::from("/tmp/logs/hi"),
                                PathBuf::from("/tmp/logs/bye"),
                                PathBuf::from("/tmp/logs/bye"),
                                PathBuf::from("/tmp/logs/fly")];

        let common_result = get_longest_common_path(&common_paths).unwrap();
        assert_eq!(common_result, "/tmp/logs");

        let diverging_paths = vec![PathBuf::from("/tmp/logs/hi"), PathBuf::from("/var/logs/hi")];

        let diverging_result = get_longest_common_path(&diverging_paths).unwrap();
        assert_eq!(diverging_result, "/");

        let uneven_paths = vec![PathBuf::from("/tmp/logs/hi"),
                                PathBuf::from("/tmp/logs/"),
                                PathBuf::from("/tmp/logs/bye")];

        let uneven_result = get_longest_common_path(&uneven_paths).unwrap();
        assert_eq!(uneven_result, "/tmp/logs");
    }
}
<commit_msg>Die quietly if exec() fails<commit_after>use std::path::PathBuf;

pub use self::imp::*;

#[cfg(target_family = "unix")]
mod imp {
    use std::io::Result;
    use std::path::PathBuf;
    use std::process::Command;

    pub struct Process {
        pid: i32,
    }

    impl Process {
        pub fn new(cmd: &str, updated_paths: Vec<PathBuf>) -> Result<Process> {
            use std::io;
            use std::os::unix::process::CommandExt;
            use libc::exit;
            use nix::unistd::*;

            let mut command = Command::new("sh");
            command.arg("-c").arg(cmd);

            if let Some(single_path) = super::get_single_updated_path(&updated_paths) {
                command.env("WATCHEXEC_UPDATED_PATH", single_path);
            }

            if let Some(common_path) = super::get_longest_common_path(&updated_paths) {
                command.env("WATCHEXEC_COMMON_PATH", common_path);
            }

            // Until process_exec lands in stable, handle fork/exec ourselves
            //command.before_exec(|| setpgid(0, 0).map_err(io::Error::from))
                //.spawn()
                //.and_then(|p| Ok(Process { pid: p.id() as i32 }))

            match fork() {
                Ok(ForkResult::Parent {child, .. }) => {
                    Ok(Process {
                        pid: child as i32
                    })
                },
                Ok(ForkResult::Child) => {
                    let _ = setpgid(0, 0);
                    let _ = command.exec();

                    // If we get here, there isn't much we can do
                    unsafe {
                        exit(1);
                    }
                }
                Err(e) => { Err(io::Error::from(e)) }
            }
        }

        pub fn kill(&self) {
            use libc;

            extern "C" {
                fn killpg(pgrp: libc::pid_t, sig: libc::c_int) -> libc::c_int;
            }

            unsafe {
                killpg(self.pid, libc::SIGTERM);
            }
        }

        pub fn wait(&self) {
            use nix::sys::wait::waitpid;

            let _ = waitpid(-self.pid, None);
        }
    }
}

#[cfg(target_family = "windows")]
mod imp {
    use std::io;
    use std::io::Result;
    use std::mem;
    use std::path::PathBuf;
    use std::process::Command;
    use kernel32::*;
    use winapi::*;

    pub struct Process {
        job: HANDLE,
    }

    impl Process {
        pub fn new(cmd: &str, updated_paths: Vec<PathBuf>) -> Result<Process> {
            use std::os::windows::io::IntoRawHandle;

            fn last_err() -> io::Error {
                io::Error::last_os_error()
            }

            let job = unsafe { CreateJobObjectW(0 as *mut _, 0 as *const _) };
            if job.is_null() {
                panic!("failed to create job object: {}", last_err());
            }

            let mut info: JOBOBJECT_EXTENDED_LIMIT_INFORMATION = unsafe { mem::zeroed() };
            info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
            let r = unsafe {
                SetInformationJobObject(job,
                                        JobObjectExtendedLimitInformation,
                                        &mut info as *mut _ as LPVOID,
                                        mem::size_of_val(&info) as DWORD)
            };
            if r == 0 {
                panic!("failed to set job info: {}", last_err());
            }

            let mut command = Command::new("cmd.exe");
            command.arg("/C").arg(cmd);

            if let Some(single_path) = super::get_single_updated_path(&updated_paths) {
                command.env("WATCHEXEC_UPDATED_PATH", single_path);
            }

            if let Some(common_path) = super::get_longest_common_path(&updated_paths) {
                command.env("WATCHEXEC_COMMON_PATH", common_path);
            }

            command.spawn()
                .and_then(|p| {
                    let r = unsafe { AssignProcessToJobObject(job, p.into_raw_handle()) };
                    if r == 0 {
                        panic!("failed to add to job object: {}", last_err());
                    }

                    Ok(Process { job: job })
                })
        }

        pub fn kill(&self) {
            unsafe {
                let _ = TerminateJobObject(self.job, 1);
            }
        }

        pub fn wait(&self) {
            unsafe {
                let _ = WaitForSingleObject(self.job, INFINITE);
            }
        }
    }

    impl Drop for Process {
        fn drop(&mut self) {
            unsafe {
                let _ = CloseHandle(self.job);
            }
        }
    }

    unsafe impl Send for Process {}
    unsafe impl Sync for Process {}
}

fn get_single_updated_path(paths: &[PathBuf]) -> Option<&str> {
    paths.get(0).and_then(|p| p.to_str())
}

fn get_longest_common_path(paths: &[PathBuf]) -> Option<String> {
    match paths.len() {
        0 => return None,
        1 => return paths[0].to_str().map(|ref_val| ref_val.to_string()),
        _ => {}
    };

    let mut longest_path: Vec<_> = paths[0].components().collect();

    for path in &paths[1..] {
        let mut greatest_distance = 0;
        for component_pair in path.components().zip(longest_path.iter()) {
            if component_pair.0 != *component_pair.1 {
                break;
            }

            greatest_distance += 1;
        }

        if greatest_distance != longest_path.len() {
            longest_path.truncate(greatest_distance);
        }
    }

    let mut result = PathBuf::new();
    for component in longest_path {
        result.push(component.as_os_str());
    }

    result.to_str().map(|ref_val| ref_val.to_string())
}

#[cfg(test)]
#[cfg(target_family = "unix")]
mod tests {
    use std::path::{Path, PathBuf};
    use std::thread;
    use std::time::Duration;

    use mktemp::Temp;

    use super::imp::Process;
    use super::get_longest_common_path;

    fn file_contents(path: &Path) -> String {
        use std::fs::File;
        use std::io::Read;

        let mut f = File::open(path).unwrap();
        let mut s = String::new();
        f.read_to_string(&mut s).unwrap();

        s
    }

    #[test]
    fn test_start() {
        let process = Process::new("echo hi", vec![]);

        assert!(process.is_ok());
    }

    #[test]
    fn test_wait() {
        let file = Temp::new_file().unwrap();
        let path = file.to_path_buf();
        let process = Process::new(&format!("echo hi > {}", path.to_str().unwrap()), vec![])
            .unwrap();
        process.wait();

        assert!(file_contents(&path).starts_with("hi"));
    }

    #[test]
    fn test_kill() {
        let file = Temp::new_file().unwrap();
        let path = file.to_path_buf();

        let process = Process::new(&format!("sleep 20; echo hi > {}", path.to_str().unwrap()),
                                       vec![])
            .unwrap();
        thread::sleep(Duration::from_millis(250));
        process.kill();
        process.wait();

        assert!(file_contents(&path) == "");
    }

    #[test]
    fn longest_common_path_should_return_correct_value() {
        let single_path = vec![PathBuf::from("/tmp/random/")];
        let single_result = get_longest_common_path(&single_path).unwrap();
        assert_eq!(single_result, "/tmp/random/");

        let common_paths = vec![PathBuf::from("/tmp/logs/hi"),
                                PathBuf::from("/tmp/logs/bye"),
                                PathBuf::from("/tmp/logs/bye"),
                                PathBuf::from("/tmp/logs/fly")];

        let common_result = get_longest_common_path(&common_paths).unwrap();
        assert_eq!(common_result, "/tmp/logs");

        let diverging_paths = vec![PathBuf::from("/tmp/logs/hi"), PathBuf::from("/var/logs/hi")];

        let diverging_result = get_longest_common_path(&diverging_paths).unwrap();
        assert_eq!(diverging_result, "/");

        let uneven_paths = vec![PathBuf::from("/tmp/logs/hi"),
                                PathBuf::from("/tmp/logs/"),
                                PathBuf::from("/tmp/logs/bye")];

        let uneven_result = get_longest_common_path(&uneven_paths).unwrap();
        assert_eq!(uneven_result, "/tmp/logs");
    }
}
<|endoftext|>


<commit_before>#[derive(Debug)]
pub enum Region {
    UsEast1,
    UsWest1,
    UsWest2,
    EuWest1,
    EuCentral1,
    ApSoutheast1,
    ApNortheast1,
    ApSoutheast2,
    SaEast1,
}

pub fn region_in_aws_format(region: &Region) -> String {
    match region {
        &Region::UsEast1 => "us-east-1".to_string(),
        &Region::UsWest1 => "us-west-1".to_string(),
        &Region::UsWest2 => return "us-west-2".to_string(),
        &Region::EuWest1 => return "eu-west-1".to_string(),
        &Region::EuCentral1 => return "eu-central-1".to_string(),
        &Region::ApSoutheast1 => return "ap-southeast-1".to_string(),
        &Region::ApNortheast1 => return "ap-northeast-1".to_string(),
        &Region::ApSoutheast2 => return "ap-southeast-2".to_string(),
        &Region::SaEast1 => return "sa-east-1".to_string(),
    }
}

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

	#[test]
	fn regions_correctly_map_to_aws_strings() {
        let mut region = Region::UsEast1;
        if region_in_aws_format(&region) != "us-east-1" {
            panic!("Couldn't map us-east-1 enum right.");
        }
        region = Region::UsWest1;
        if region_in_aws_format(&region) != "us-west-1" {
            panic!("Couldn't map us-west-1 enum right.");
        }
        region = Region::UsWest2;
        if region_in_aws_format(&region) != "us-west-2" {
            panic!("Couldn't map us-west-2 enum right.");
        }
        region = Region::EuWest1;
        if region_in_aws_format(&region) != "eu-west-1" {
            panic!("Couldn't map eu-west-1 enum right.");
        }
        region = Region::EuCentral1;
        if region_in_aws_format(&region) != "eu-central-1" {
            panic!("Couldn't map eu-central-1 enum right.");
        }
        region = Region::ApSoutheast1;
        if region_in_aws_format(&region) != "ap-southeast-1" {
            panic!("Couldn't map ap-southeast-1 enum right.");
        }
        region = Region::ApNortheast1;
        if region_in_aws_format(&region) != "ap-northeast-1" {
            panic!("Couldn't map ap-northeast-1 enum right.");
        }
        region = Region::ApSoutheast2;
        if region_in_aws_format(&region) != "ap-southeast-2" {
            panic!("Couldn't map ap-southeast-2 enum right.");
        }
        region = Region::SaEast1;
        if region_in_aws_format(&region) != "sa-east-1" {
            panic!("Couldn't map sa-east-1 enum right.");
        }
    }
}
<commit_msg>Unifies region_in_aws_format returns in matcher.<commit_after>#[derive(Debug)]
pub enum Region {
    UsEast1,
    UsWest1,
    UsWest2,
    EuWest1,
    EuCentral1,
    ApSoutheast1,
    ApNortheast1,
    ApSoutheast2,
    SaEast1,
}

pub fn region_in_aws_format(region: &Region) -> String {
    match region {
        &Region::UsEast1 => "us-east-1".to_string(),
        &Region::UsWest1 => "us-west-1".to_string(),
        &Region::UsWest2 => "us-west-2".to_string(),
        &Region::EuWest1 => "eu-west-1".to_string(),
        &Region::EuCentral1 => "eu-central-1".to_string(),
        &Region::ApSoutheast1 => "ap-southeast-1".to_string(),
        &Region::ApNortheast1 => "ap-northeast-1".to_string(),
        &Region::ApSoutheast2 => "ap-southeast-2".to_string(),
        &Region::SaEast1 => "sa-east-1".to_string(),
    }
}

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

	#[test]
	fn regions_correctly_map_to_aws_strings() {
        let mut region = Region::UsEast1;
        if region_in_aws_format(&region) != "us-east-1" {
            panic!("Couldn't map us-east-1 enum right.");
        }
        region = Region::UsWest1;
        if region_in_aws_format(&region) != "us-west-1" {
            panic!("Couldn't map us-west-1 enum right.");
        }
        region = Region::UsWest2;
        if region_in_aws_format(&region) != "us-west-2" {
            panic!("Couldn't map us-west-2 enum right.");
        }
        region = Region::EuWest1;
        if region_in_aws_format(&region) != "eu-west-1" {
            panic!("Couldn't map eu-west-1 enum right.");
        }
        region = Region::EuCentral1;
        if region_in_aws_format(&region) != "eu-central-1" {
            panic!("Couldn't map eu-central-1 enum right.");
        }
        region = Region::ApSoutheast1;
        if region_in_aws_format(&region) != "ap-southeast-1" {
            panic!("Couldn't map ap-southeast-1 enum right.");
        }
        region = Region::ApNortheast1;
        if region_in_aws_format(&region) != "ap-northeast-1" {
            panic!("Couldn't map ap-northeast-1 enum right.");
        }
        region = Region::ApSoutheast2;
        if region_in_aws_format(&region) != "ap-southeast-2" {
            panic!("Couldn't map ap-southeast-2 enum right.");
        }
        region = Region::SaEast1;
        if region_in_aws_format(&region) != "sa-east-1" {
            panic!("Couldn't map sa-east-1 enum right.");
        }
    }
}
<|endoftext|>


<commit_before>//! AWS API requests.
//!
//! Wraps the Hyper library to send PUT, POST, DELETE and GET requests.

use hyper::Client;
use hyper::client::Response;
use hyper::client::RedirectPolicy;
use hyper::header::Headers;
use hyper::method::Method;
use signature::SignedRequest;
use log::LogLevel::Debug;

/// Takes a fully formed and signed request and executes it.
pub fn send_request(signed_request: &SignedRequest) -> Response {
    let hyper_method = match signed_request.method().as_ref() {
        "POST" => Method::Post,
        "PUT" => Method::Put,
        "DELETE" => Method::Delete,
        "GET" => Method::Get,
        _ => Method::Get, // make this unreachable! ?
    };

    // translate the headers map to a format Hyper likes
    let mut hyper_headers = Headers::new();
    for h in signed_request.headers().iter() {
        hyper_headers.set_raw(h.0.to_owned(), h.1.to_owned());
    }

    let mut final_uri = format!("https://{}{}", signed_request.hostname(), signed_request.canonical_uri());
    if signed_request.canonical_query_string().len() > 0 {
        final_uri = final_uri + &format!("?{}", signed_request.canonical_query_string());
    }

    if log_enabled!(Debug) {
        debug!("Full request: \n method: {}\n final_uri: {}\n payload: {:?}\nHeaders:\n",
            hyper_method, final_uri, signed_request.payload());
        for h in hyper_headers.iter() {
            debug!("{}:{}", h.name(), h.value_string());
        }
    }

    let mut client = Client::new();
    client.set_redirect_policy(RedirectPolicy::FollowNone);

    match signed_request.payload() {
        None => client.request(hyper_method, &final_uri).headers(hyper_headers).body("").send().unwrap(),
        Some(payload_contents) => client.request(hyper_method, &final_uri).headers(hyper_headers).body(payload_contents).send().unwrap(),
    }
}
<commit_msg>Convert HTTP payload into a string before debug logging.<commit_after>//! AWS API requests.
//!
//! Wraps the Hyper library to send PUT, POST, DELETE and GET requests.

use std::io::Read;

use hyper::Client;
use hyper::client::Response;
use hyper::client::RedirectPolicy;
use hyper::header::Headers;
use hyper::method::Method;
use signature::SignedRequest;
use log::LogLevel::Debug;

/// Takes a fully formed and signed request and executes it.
pub fn send_request(signed_request: &SignedRequest) -> Response {
    let hyper_method = match signed_request.method().as_ref() {
        "POST" => Method::Post,
        "PUT" => Method::Put,
        "DELETE" => Method::Delete,
        "GET" => Method::Get,
        _ => Method::Get, // make this unreachable! ?
    };

    // translate the headers map to a format Hyper likes
    let mut hyper_headers = Headers::new();
    for h in signed_request.headers().iter() {
        hyper_headers.set_raw(h.0.to_owned(), h.1.to_owned());
    }

    let mut final_uri = format!("https://{}{}", signed_request.hostname(), signed_request.canonical_uri());
    if signed_request.canonical_query_string().len() > 0 {
        final_uri = final_uri + &format!("?{}", signed_request.canonical_query_string());
    }

    if log_enabled!(Debug) {
        let payload = signed_request.payload().map(|mut payload_bytes| {
            let mut payload_string = String::new();

            payload_bytes.read_to_string(&mut payload_string).expect(
                "Failed to read payload to string"
            );

            payload_string
        });

        debug!("Full request: \n method: {}\n final_uri: {}\n payload: {:?}\nHeaders:\n",
            hyper_method, final_uri, payload);
        for h in hyper_headers.iter() {
            debug!("{}:{}", h.name(), h.value_string());
        }
    }

    let mut client = Client::new();
    client.set_redirect_policy(RedirectPolicy::FollowNone);

    match signed_request.payload() {
        None => client.request(hyper_method, &final_uri).headers(hyper_headers).body("").send().unwrap(),
        Some(payload_contents) => client.request(hyper_method, &final_uri).headers(hyper_headers).body(payload_contents).send().unwrap(),
    }
}
<|endoftext|>


<commit_before>#![feature(macro_rules)]
#![allow(unused_variable)]
use std::io::{File};

macro_rules! unwrap(
    ($inp: expr) => (
        match $inp {
            Ok(r) => r,
            Err(e) => fail!("{}",e)
        }
    );
)

fn main() {
    let path = Path::new("/home/alex/.bitcoin/blocks/blk00000.dat");
    let mut file = unwrap!(File::open(&path));

    verify_block(&mut file);
    parse_block(&mut file);
}

fn string_of_hex(hex: & Vec<u8>) -> Vec<String>{
    hex.iter().map(|h| {
        let base16 = ['0', '1', '2', '3',
                      '4', '5', '6', '7',
                      '8', '9', 'A', 'B',
                      'C', 'D', 'E', 'F'];
        let mut s = String::new();
        s.push(base16[(h/16) as uint]);
        s.push(base16[(h%16) as uint]);
        s
    }).collect()
}

fn parse_block(file: &mut File) {
    let header = unwrap!(file.read_le_u32());
    //println!("header={}",header);

    let version = unwrap!(file.read_le_u32());
    println!("version={}",version);

    let sha = unwrap!(file.read_exact(32));
    //println!("sha={}",sha);

    let merkle = unwrap!(file.read_exact(32));
    println!("merkle={}",string_of_hex(&merkle));

    let timestamp = unwrap!(file.read_le_u32());
    //println!("timestamp={}",timestamp);

    let difficulty = unwrap!(file.read_le_u32());
    //println!("difficulty={}",difficulty);

    let nonce = unwrap!(file.read_le_u32());
    println!("nonce={}",nonce);

    let transaction_count = read_vli(file);
    println!("transaction_count={}",transaction_count);

    for _ in range(0, transaction_count) {
        let transaction_version = unwrap!(file.read_le_u32());

        let input_count = read_vli(file);
        println!("{} inputs", input_count);
        for _ in range(0, input_count) {
            let transaction_hash = unwrap!(file.read_exact(32));
            println!("tx hash={}",string_of_hex(&transaction_hash));
            let transaction_index = unwrap!(file.read_le_u32());
            let script_length = read_vli(file) as uint; // is this okay?
            let script = unwrap!(file.read_exact(script_length));
            let sequence_number = unwrap!(file.read_le_u32());
            assert!(sequence_number == 0xFFFFFFFFu32);
        }

        let output_count = read_vli(file);
        println!("{} outputs", output_count);
        for _ in range(0, output_count) {
            let value = unwrap!(file.read_le_u64());
            println!("value={}", value);
            let script_length = read_vli(file) as uint;
            let script = unwrap!(file.read_exact(script_length));
        }

        let lock_time = unwrap!(file.read_le_u32());
        assert!(lock_time == 0u32);
    }

    // Now, we should be done with the block.
    assert!(file.eof());
}

fn read_vli(file: &mut File) -> u64 {
    let flag = unwrap!(file.read_u8());
    if flag < 0xfd {
        flag as u64
    } else if flag == 0xfd {
        (unwrap!(file.read_le_u16())) as u64
    } else if flag == 0xfe {
        (unwrap!(file.read_le_u32())) as u64
    } else {
        unwrap!(file.read_le_u64())
    }
}

fn verify_block(file: &mut File) {
    print!("verifying block...");

    let magic_uint : u32 = 0xD9B4BEF9;
    let file_uint = unwrap!(file.read_le_u32());
    assert!(magic_uint == file_uint);

    println!("verify passed...");
}
<commit_msg>more on parsing<commit_after>#![feature(macro_rules)]
#![allow(unused_variable)]
use std::io::{File};

macro_rules! unwrap(
    ($inp: expr) => (
        match $inp {
            Ok(r) => r,
            Err(e) => fail!("{}",e)
        }
    );
)

macro_rules! vprintln(
    ($flag: ident, $msg: expr, $($args:expr)*) => (
        if $flag { println!($msg, $($args)*); }
    );
)

fn main() {
    let path = Path::new("/home/alex/.bitcoin/blocks/blk00000.dat");
    let mut file = unwrap!(File::open(&path));

    verify_block(&mut file);
    parse_block(&mut file, false);
}

fn string_of_hex(hex: & Vec<u8>) -> Vec<String>{
    hex.iter().map(|h| {
        let base16 = ['0', '1', '2', '3',
                      '4', '5', '6', '7',
                      '8', '9', 'A', 'B',
                      'C', 'D', 'E', 'F'];
        let mut s = String::new();
        s.push(base16[(h/16) as uint]);
        s.push(base16[(h%16) as uint]);
        s
    }).collect()
}

fn parse_block(file: &mut File, verbose: bool) {
    let header = unwrap!(file.read_le_u32());
    vprintln!(verbose, "header={}",header);

    let version = unwrap!(file.read_le_u32());
    vprintln!(verbose, "version={}",version);

    let sha = unwrap!(file.read_exact(32));
    vprintln!(verbose, "sha={}",sha);

    let merkle = unwrap!(file.read_exact(32));
    vprintln!(verbose, "merkle={}",string_of_hex(&merkle));

    let timestamp = unwrap!(file.read_le_u32());
    vprintln!(verbose, "timestamp={}",timestamp);

    let difficulty = unwrap!(file.read_le_u32());
    vprintln!(verbose, "difficulty={}",difficulty);

    let nonce = unwrap!(file.read_le_u32());
    vprintln!(verbose, "nonce={}",nonce);

    let transaction_count = read_vli(file);
    vprintln!(verbose, "transaction_count={}",transaction_count);

    for _ in range(0, transaction_count) {
        let transaction_version = unwrap!(file.read_le_u32());

        let input_count = read_vli(file);
        println!("{} inputs", input_count);
        for _ in range(0, input_count) {
            let transaction_hash = unwrap!(file.read_exact(32));
            println!("tx hash={}",string_of_hex(&transaction_hash));
            let transaction_index = unwrap!(file.read_le_u32());
            let script_length = read_vli(file) as uint; // is this okay?
            let script = unwrap!(file.read_exact(script_length));
            let sequence_number = unwrap!(file.read_le_u32());
            assert!(sequence_number == 0xFFFFFFFFu32);
        }

        let output_count = read_vli(file);
        println!("{} outputs", output_count);
        for _ in range(0, output_count) {
            let value = unwrap!(file.read_le_u64());
            println!("value={}", value);
            let script_length = read_vli(file) as uint;
            let script = unwrap!(file.read_exact(script_length));
        }

        let lock_time = unwrap!(file.read_le_u32());
        assert!(lock_time == 0u32);
    }

    // Now, we should be done with the block.
    //assert!(file.eof()); // apparently there's some extra stuff at the end?
}

fn read_vli(file: &mut File) -> u64 {
    let flag = unwrap!(file.read_u8());
    if flag < 0xfd {
        flag as u64
    } else if flag == 0xfd {
        (unwrap!(file.read_le_u16())) as u64
    } else if flag == 0xfe {
        (unwrap!(file.read_le_u32())) as u64
    } else {
        unwrap!(file.read_le_u64())
    }
}

fn verify_block(file: &mut File) {
    print!("verifying block...");

    let magic_uint : u32 = 0xD9B4BEF9;
    let file_uint = unwrap!(file.read_le_u32());
    assert!(magic_uint == file_uint);

    println!("verify passed...");
}
<|endoftext|>


<commit_before>use crate::Lang;

// TODO: rename
// * FilterList
// * FilterRule
// * GuardList
// * AccessList
// * AllowList
#[derive(Debug)]
pub enum AllowList {
    All,
    Only(Vec<Lang>),
    Except(Vec<Lang>),
}

impl AllowList {
    pub fn all() -> Self {
        Self::All
    }

    pub fn only(whitelist: Vec<Lang>) -> Self {
        Self::Only(whitelist)
    }

    pub fn except(blacklist: Vec<Lang>) -> Self {
        Self::Except(blacklist)
    }

    pub fn is_allowed(&self, lang: Lang) -> bool {
        match self {
            Self::All=> true,
            Self::Only(ref whitelist) => whitelist.contains(&lang),
            Self::Except(ref blacklist) => !blacklist.contains(&lang),
        }
    }
}

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

    #[test]
    fn test_all() {
        let list = AllowList::all();
        assert!(list.is_allowed(Lang::Epo));
    }

    #[test]
    fn test_only() {
        let list = AllowList::only(vec![Lang::Rus, Lang::Ukr]);

        assert!(!list.is_allowed(Lang::Epo));
        assert!(!list.is_allowed(Lang::Eng));

        assert!(list.is_allowed(Lang::Rus));
        assert!(list.is_allowed(Lang::Ukr));
    }

    #[test]
    fn test_except() {
        let list = AllowList::except(vec![Lang::Rus, Lang::Ukr]);

        assert!(list.is_allowed(Lang::Epo));
        assert!(list.is_allowed(Lang::Eng));

        assert!(!list.is_allowed(Lang::Rus));
        assert!(!list.is_allowed(Lang::Ukr));
    }
}
<commit_msg>impl Default for AllowList<commit_after>use crate::Lang;

// TODO: rename
// * FilterList
// * FilterRule
// * GuardList
// * AccessList
// * AllowList
#[derive(Debug)]
pub enum AllowList {
    All,
    Only(Vec<Lang>),
    Except(Vec<Lang>),
}

impl AllowList {
    pub fn all() -> Self {
        Self::All
    }

    pub fn only(whitelist: Vec<Lang>) -> Self {
        Self::Only(whitelist)
    }

    pub fn except(blacklist: Vec<Lang>) -> Self {
        Self::Except(blacklist)
    }

    pub fn is_allowed(&self, lang: Lang) -> bool {
        match self {
            Self::All=> true,
            Self::Only(ref whitelist) => whitelist.contains(&lang),
            Self::Except(ref blacklist) => !blacklist.contains(&lang),
        }
    }
}

impl Default for AllowList {
    fn default() -> Self {
        AllowList::All
    }
}

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

    #[test]
    fn test_all() {
        let list = AllowList::all();
        assert!(list.is_allowed(Lang::Epo));
    }

    #[test]
    fn test_only() {
        let list = AllowList::only(vec![Lang::Rus, Lang::Ukr]);

        assert!(!list.is_allowed(Lang::Epo));
        assert!(!list.is_allowed(Lang::Eng));

        assert!(list.is_allowed(Lang::Rus));
        assert!(list.is_allowed(Lang::Ukr));
    }

    #[test]
    fn test_except() {
        let list = AllowList::except(vec![Lang::Rus, Lang::Ukr]);

        assert!(list.is_allowed(Lang::Epo));
        assert!(list.is_allowed(Lang::Eng));

        assert!(!list.is_allowed(Lang::Rus));
        assert!(!list.is_allowed(Lang::Ukr));
    }
}
<|endoftext|>


<commit_before>#![crate_type = "bin"]
#![feature(collections)]

extern crate gtk;
extern crate glib;
extern crate sysinfo;

use gtk::{WindowTrait, ContainerTrait, WidgetTrait};
use glib::{Type, timeout};
use sysinfo::*;
use gtk::signal::Inhibit;
use gtk::signal::WidgetSignals;
use std::collections::VecMap;
use std::str::FromStr;

fn append_column(title: &str, v: &mut Vec<gtk::TreeViewColumn>) {
    let l = v.len();
    let renderer = gtk::CellRendererText::new().unwrap();

    v.push(gtk::TreeViewColumn::new().unwrap());
    let tmp = v.get_mut(l).unwrap();

    tmp.set_title(title);
    tmp.pack_start(&renderer, true);
    tmp.add_attribute(&renderer, "text", l as i32);
}

fn create_and_fill_model(list_store: &mut gtk::ListStore, pid: i64, name: &str, cpu: f32, memory: u64) {
    if name.len() < 1 {
        return;
    }
    let mut top_level = gtk::TreeIter::new();

    list_store.append(&mut top_level);
    list_store.set_string(&top_level, 0, &format!("{}", pid));
    list_store.set_string(&top_level, 1, name);
    list_store.set_string(&top_level, 2, &format!("{}", cpu));
    list_store.set_string(&top_level, 3, &format!("{}", memory));
}

fn update_window(w: &mut (&mut gtk::ListStore, &mut sysinfo::System)) -> i32 {
    let mut model = w.0.get_model().unwrap();
    let mut iter = gtk::TreeIter::new();

    w.1.refresh();
    let mut entries : VecMap<Processus> = (*w.1.get_processus_list()).clone();
    let mut nb = model.iter_n_children(None);
    let mut i = 0;

    while i < nb {
        if model.iter_nth_child(&mut iter, None, i) {
            let pid : i64 = i64::from_str(&model.get_value(&iter, 0).get_string().unwrap()).unwrap();
            let mut to_delete = false;

            match entries.get(&(pid as usize)) {
                Some(p) => {
                    //w.0.set_string(&iter, 1, &p.name);
                    w.0.set_string(&iter, 2, &format!("{}", p.cpu_usage));
                    w.0.set_string(&iter, 3, &format!("{}", p.memory));
                    to_delete = true;
                }
                None => {
                    w.0.remove(&iter);
                }
            }
            if to_delete {
                entries.remove(&(pid as usize));
                nb = model.iter_n_children(None);
                i += 1;
            }
        } else {
            i += 1;
        }
    }
    for (_, pro) in entries {
        create_and_fill_model(&mut w.0, pro.pid, &pro.name, pro.cpu_usage, pro.memory);
    }
    1
}

fn main() {
    gtk::init();

    let mut window = gtk::Window::new(gtk::WindowType::TopLevel).unwrap();
    let mut sys = sysinfo::System::new();

    window.set_title("TreeView Sample");
    window.set_window_position(gtk::WindowPosition::Center);

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(true)
    });

    let mut left_tree = gtk::TreeView::new().unwrap();
    let mut scroll = gtk::ScrolledWindow::new(None, None).unwrap();

    scroll.set_min_content_height(800);
    scroll.set_min_content_width(600);

    let mut columns : Vec<gtk::TreeViewColumn> = Vec::new();

    append_column("pid", &mut columns);
    append_column("process name", &mut columns);
    append_column("cpu usage", &mut columns);
    append_column("memory usage", &mut columns);

    for i in columns {
        left_tree.append_column(&i);
    }

    let mut list_store = gtk::ListStore::new(&[Type::String, Type::String, Type::String, Type::String]).unwrap();
    sys.refresh();
    for (_, pro) in sys.get_processus_list() {
        create_and_fill_model(&mut list_store, pro.pid, &pro.name, pro.cpu_usage, pro.memory);
    }

    left_tree.set_model(&list_store.get_model().unwrap());
    left_tree.set_headers_visible(true);
    scroll.add(&left_tree);

    /*for _ in 0..10 {
        let mut iter = gtk::TreeIter::new().unwrap();
        left_store.append(&mut iter);
        left_store.set_string(&iter, 0, "I'm in a list");
    }*/

    // display the panes

    //let mut split_pane = gtk::Box::new(gtk::Orientation::Horizontal, 10).unwrap();

    //split_pane.set_size_request(-1, -1);
    //split_pane.add(&left_tree);

    timeout::add(1500, update_window, &mut (&mut list_store, &mut sys));

    window.add(&scroll);
    window.show_all();
    gtk::main();
}
<commit_msg>Add button<commit_after>#![crate_type = "bin"]
#![feature(collections)]

extern crate gtk;
extern crate glib;
extern crate sysinfo;

use gtk::{WindowTrait, ContainerTrait, WidgetTrait};
use glib::{Type, timeout};
use sysinfo::*;
use gtk::signal::Inhibit;
use gtk::signal::WidgetSignals;
use std::collections::VecMap;
use std::str::FromStr;

fn append_column(title: &str, v: &mut Vec<gtk::TreeViewColumn>) {
    let l = v.len();
    let renderer = gtk::CellRendererText::new().unwrap();

    v.push(gtk::TreeViewColumn::new().unwrap());
    let tmp = v.get_mut(l).unwrap();

    tmp.set_title(title);
    tmp.pack_start(&renderer, true);
    tmp.add_attribute(&renderer, "text", l as i32);
}

fn create_and_fill_model(list_store: &mut gtk::ListStore, pid: i64, name: &str, cpu: f32, memory: u64) {
    if name.len() < 1 {
        return;
    }
    let mut top_level = gtk::TreeIter::new();

    list_store.append(&mut top_level);
    list_store.set_string(&top_level, 0, &format!("{}", pid));
    list_store.set_string(&top_level, 1, name);
    list_store.set_string(&top_level, 2, &format!("{}", cpu));
    list_store.set_string(&top_level, 3, &format!("{}", memory));
}

fn update_window(w: &mut (&mut gtk::ListStore, &mut sysinfo::System)) -> i32 {
    let mut model = w.0.get_model().unwrap();
    let mut iter = gtk::TreeIter::new();

    w.1.refresh();
    let mut entries : VecMap<Processus> = (*w.1.get_processus_list()).clone();
    let mut nb = model.iter_n_children(None);
    let mut i = 0;

    while i < nb {
        if model.iter_nth_child(&mut iter, None, i) {
            let pid : i64 = i64::from_str(&model.get_value(&iter, 0).get_string().unwrap()).unwrap();
            let mut to_delete = false;

            match entries.get(&(pid as usize)) {
                Some(p) => {
                    //w.0.set_string(&iter, 1, &p.name);
                    w.0.set_string(&iter, 2, &format!("{}", p.cpu_usage));
                    w.0.set_string(&iter, 3, &format!("{}", p.memory));
                    to_delete = true;
                }
                None => {
                    w.0.remove(&iter);
                }
            }
            if to_delete {
                entries.remove(&(pid as usize));
                nb = model.iter_n_children(None);
                i += 1;
            }
        } else {
            i += 1;
        }
    }
    for (_, pro) in entries {
        create_and_fill_model(&mut w.0, pro.pid, &pro.name, pro.cpu_usage, pro.memory);
    }
    1
}

fn main() {
    gtk::init();

    let mut window = gtk::Window::new(gtk::WindowType::TopLevel).unwrap();
    let mut sys = sysinfo::System::new();

    window.set_title("Processus viewer");
    window.set_window_position(gtk::WindowPosition::Center);

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(true)
    });

    let mut left_tree = gtk::TreeView::new().unwrap();
    let mut scroll = gtk::ScrolledWindow::new(None, None).unwrap();

    scroll.set_min_content_height(800);
    scroll.set_min_content_width(600);

    let mut columns : Vec<gtk::TreeViewColumn> = Vec::new();

    append_column("pid", &mut columns);
    append_column("process name", &mut columns);
    append_column("cpu usage", &mut columns);
    append_column("memory usage", &mut columns);

    for i in columns {
        left_tree.append_column(&i);
    }

    let mut list_store = gtk::ListStore::new(&[Type::String, Type::String, Type::String, Type::String]).unwrap();
    sys.refresh();
    for (_, pro) in sys.get_processus_list() {
        create_and_fill_model(&mut list_store, pro.pid, &pro.name, pro.cpu_usage, pro.memory);
    }

    left_tree.set_model(&list_store.get_model().unwrap());
    left_tree.set_headers_visible(true);
    scroll.add(&left_tree);
    let mut vertical_layout = gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap();
    let mut kill_button = gtk::Button::new_with_label("End task").unwrap();

    kill_button.set_sensitive(false);
    timeout::add(1500, update_window, &mut (&mut list_store, &mut sys));

    vertical_layout.add(&scroll);
    vertical_layout.add(&kill_button);
    window.add(&vertical_layout);
    window.show_all();
    gtk::main();
}
<|endoftext|>


<commit_before>#![allow(non_snake_case)]

use std::str::from_utf8;
use std::collections::HashMap;

use rustc_serialize::json;
use curl::http;

pub const SESSION_TTL: &'static str = "10s";

#[derive(RustcDecodable, RustcEncodable, Debug)]
pub struct SessionCreate {
    Name: String,
    TTL: String
}

#[derive(RustcDecodable, RustcEncodable, Debug)]
pub struct SessionID {
    ID: String
}

pub struct Session {
    endpoint: String
}

impl Session {
    pub fn new(address: &str) ->  Session {
        Session {
            endpoint: format!("http://{}/v1/session", address)
        }
    }

    pub fn create(&self, name: String) -> String{
        let url = format!("{}/create", self.endpoint);
        let session = SessionCreate {
            Name: name,
            TTL: self::SESSION_TTL.to_owned()
        };
        let json_str = json::encode(&session).unwrap();

        let resp = http::handle()
            .put(url, &json_str)
            .content_type("application/json")
            .exec().unwrap();
        if resp.get_code() != 200 {
            panic!("Consul: Error creating a session!");
        }
        let result = from_utf8(resp.get_body()).unwrap();
        let json_data = match json::Json::from_str(result) {
            Ok(value) => value,
            Err(err) => panic!("consul: Could not convert to json: {:?}", result)
        };
        super::get_string(&json_data, &["ID"])
    }

    pub fn renew(&self, session_id: &String) {
        let url = format!("{}/renew/{}", self.endpoint, session_id);
        let resp = http::handle()
            .put(url, "")
            .content_type("application/json")
            .exec().unwrap();
        if resp.get_code() != 200 {
            panic!("Cound not renew session: {}", session_id);
        }

    }

    pub fn end(&self, session_id: &String) {
        let url = format!("{}/destroy/{}", self.endpoint, session_id);
        let resp = http::handle()
            .put(url, "")
            .content_type("application/json")
            .exec().unwrap();
        if resp.get_code() != 200 {
            panic!("Cound not destroy session: {}", session_id);
        }

    }

}
<commit_msg>Adding resilience to session::renew<commit_after>#![allow(non_snake_case)]

use std::str::from_utf8;
use std::collections::HashMap;
use std::thread;

use rustc_serialize::json;
use curl::http;

pub const SESSION_TTL: &'static str = "10s";

#[derive(RustcDecodable, RustcEncodable, Debug)]
pub struct SessionCreate {
    Name: String,
    TTL: String
}

#[derive(RustcDecodable, RustcEncodable, Debug)]
pub struct SessionID {
    ID: String
}

pub struct Session {
    endpoint: String
}

impl Session {
    pub fn new(address: &str) ->  Session {
        Session {
            endpoint: format!("http://{}/v1/session", address)
        }
    }

    pub fn create(&self, name: String) -> String{
        let url = format!("{}/create", self.endpoint);
        let session = SessionCreate {
            Name: name,
            TTL: self::SESSION_TTL.to_owned()
        };
        let json_str = json::encode(&session).unwrap();

        let resp = http::handle()
            .put(url, &json_str)
            .content_type("application/json")
            .exec().unwrap();
        if resp.get_code() != 200 {
            panic!("Consul: Error creating a session!");
        }
        let result = from_utf8(resp.get_body()).unwrap();
        let json_data = match json::Json::from_str(result) {
            Ok(value) => value,
            Err(err) => panic!("consul: Could not convert to json: {:?}", result)
        };
        super::get_string(&json_data, &["ID"])
    }

    pub fn renew(&self, session_id: &String) {
        let url = format!("{}/renew/{}", self.endpoint, session_id);

        for _ in 0..10 {
            let resp = http::handle()
                .put(url.clone(), "")
                .content_type("application/json")
                .exec().unwrap();
            if resp.get_code() != 200 {
                println!("Cound not renew session: {}. Sleeping for 1 sec", session_id);
                thread::sleep_ms(1000);
            }
        }
        panic!("Cound not renew session: {} after 10 tries. Panicing.", session_id);

    }

    pub fn end(&self, session_id: &String) {
        let url = format!("{}/destroy/{}", self.endpoint, session_id);
        let resp = http::handle()
            .put(url, "")
            .content_type("application/json")
            .exec().unwrap();
        if resp.get_code() != 200 {
            panic!("Cound not destroy session: {}", session_id);
        }

    }

}
<|endoftext|>


<commit_before>use tf;
use libc::{c_char, c_int};
use std::ffi::CString;
use std::marker;
use std::path::Path;
use std::ptr;
use std::result::Result as StdResult;
use super::Code;
use super::DataType;
use super::Graph;
use super::GraphTrait;
use super::Operation;
use super::OperationTrait;
use super::Result;
use super::SessionOptions;
use super::Status;
use super::Tensor;
use super::TensorType;

/// Manages a single graph and execution.
#[derive(Debug)]
pub struct Session {
    inner: *mut tf::TF_Session,
}

impl Session {
    /// Creates a session.
    pub fn new(options: &SessionOptions, graph: &Graph) -> Result<Self> {
        let mut status = Status::new();
        let inner = unsafe { tf::TF_NewSession(graph.inner(), options.inner, status.inner()) };
        if inner.is_null() {
            Err(status)
        } else {
            Ok(Session { inner: inner })
        }
    }

    /// Loads a session from an exported model.
    pub fn from_saved_model<P: AsRef<Path>, Tag: AsRef<str>, Tags: IntoIterator<Item = Tag>>
        (options: &SessionOptions,
         tags: Tags,
         graph: &mut Graph,
         export_dir: P)
         -> Result<Self> {
        let mut status = Status::new();

        let export_dir_cstr = try!(export_dir.as_ref()
                                       .to_str()
                                       .and_then(|s| CString::new(s.as_bytes()).ok())
                                       .ok_or_else(|| {
            Status::new_set(Code::InvalidArgument, "Invalid export directory path").unwrap()
        }));

        let tags_cstr: Vec<_> = try!(tags.into_iter()
                                         .map(|t| CString::new(t.as_ref()))
                                         .collect::<StdResult<_, _>>()
                                         .map_err(|_| {
            Status::new_set(Code::InvalidArgument, "Invalid tag name").unwrap()
        }));
        // keeping tags_cstr to retain strings in memory
        let tags_ptr: Vec<*const c_char> = tags_cstr.iter().map(|t| t.as_ptr()).collect();

        let inner = unsafe {
            tf::TF_LoadSessionFromSavedModel(options.inner,
                                             ptr::null(),
                                             export_dir_cstr.to_bytes_with_nul().as_ptr() as
                                             *const c_char,
                                             tags_ptr.as_ptr(),
                                             tags_ptr.len() as c_int,
                                             graph.inner(),
                                             ptr::null_mut(),
                                             status.inner())
        };
        if inner.is_null() {
            Err(status)
        } else {
            Ok(Session { inner: inner })
        }
    }

    /// Closes the session.
    pub fn close(&mut self) -> Result<()> {
        let mut status = Status::new();
        unsafe {
            tf::TF_CloseSession(self.inner, status.inner());
        }
        status.into_result()
    }

    /// Runs the graph, feeding the inputs and then fetching the outputs requested in the step.
    pub fn run(&mut self, step: &mut StepWithGraph) -> Result<()> {
        // Copy the input tensors because TF_Run consumes them.
        let mut input_tensors = Vec::with_capacity(step.input_tensors.len());
        for &input_tensor in &step.input_tensors {
            unsafe {
                let mut dims = Vec::with_capacity(tf::TF_NumDims(input_tensor) as usize);
                for i in 0..dims.capacity() {
                    dims.push(tf::TF_Dim(input_tensor, i as c_int));
                }
                input_tensors.push(tf::TF_NewTensor(tf::TF_TensorType(input_tensor),
                                                    dims.as_ptr(),
                                                    dims.len() as c_int,
                                                    tf::TF_TensorData(input_tensor),
                                                    tf::TF_TensorByteSize(input_tensor),
                                                    Some(super::noop_deallocator),
                                                    ptr::null_mut()));
            }
        }

        // In case we're running it a second time and not all outputs were taken out.
        step.drop_output_tensors();

        let mut status = Status::new();
        unsafe {
            tf::TF_SessionRun(self.inner,
                              ptr::null(),
                              step.input_ports.as_ptr(),
                              input_tensors.as_mut_ptr(),
                              input_tensors.len() as c_int,
                              step.output_ports.as_ptr(),
                              step.output_tensors.as_mut_ptr(),
                              step.output_tensors.len() as c_int,
                              step.target_operations.as_mut_ptr(),
                              step.target_operations.len() as c_int,
                              ptr::null_mut(),
                              status.inner());
        };
        status.into_result()
    }
}

impl Drop for Session {
    fn drop(&mut self) {
        let mut status = Status::new();
        unsafe {
            tf::TF_DeleteSession(self.inner, status.inner());
        }
        // TODO: What do we do with the status?
    }
}

////////////////////////

/// An opaque token for retrieving an output from a computation.
#[derive(Copy,Clone,Debug)]
pub struct OutputToken {
    index: usize,
}

/// Manages the inputs and outputs for a single execution of a graph.
///
/// Typical usage involves creating an instance of this struct,
/// adding some inputs to it, requesting some outputs, passing it to `Session::run`
/// and then taking the outputs out of it.
///
/// This will be renamed to Step once the old API goes away.
#[derive(Debug)]
pub struct StepWithGraph<'l> {
    input_ports: Vec<tf::TF_Output>,
    input_tensors: Vec<*mut tf::TF_Tensor>,

    output_ports: Vec<tf::TF_Output>,
    output_tensors: Vec<*mut tf::TF_Tensor>,

    target_operations: Vec<*const tf::TF_Operation>,

    phantom: marker::PhantomData<&'l ()>,
}

impl<'l> StepWithGraph<'l> {
    /// Creates a StepWithGraph.
    pub fn new() -> Self {
        StepWithGraph {
            input_ports: vec![],
            input_tensors: vec![],

            output_ports: vec![],
            output_tensors: vec![],

            target_operations: vec![],

            phantom: marker::PhantomData,
        }
    }

    /// Adds an input to be fed to the graph.
    pub fn add_input<T: TensorType>(&mut self,
                                    operation: &Operation,
                                    index: c_int,
                                    tensor: &'l Tensor<T>) {
        self.input_ports.push(tf::TF_Output {
                                  operation: operation.inner(),
                                  index: index,
                              });
        self.input_tensors.push(tensor.inner);
    }

    /// Requests that an output is fetched from the graph after running this step.
    /// Returns an index that you can then use to fetch this output from the step after running it.
    pub fn request_output(&mut self, operation: &Operation, index: c_int) -> OutputToken {
        self.output_ports.push(tf::TF_Output {
                                   operation: operation.inner(),
                                   index: index,
                               });
        self.output_tensors.push(ptr::null_mut());
        OutputToken { index: self.output_tensors.len() - 1 }
    }

    /// Extracts a tensor output given an index. A given index can only be extracted
    /// once per `Session::run`.
    /// Returns an error if output_idx is out of range, output is unavailable or the
    /// requested type does not match the type of the actual tensor.
    pub fn take_output<T: TensorType>(&mut self, token: OutputToken) -> Result<Tensor<T>> {
        let output_idx = token.index;
        if output_idx >= self.output_tensors.len() {
            return Err(Status::new_set(Code::OutOfRange,
                                       &format!("Requested output index is out of range: {} vs \
                                                 {}",
                                                output_idx,
                                                self.output_tensors.len()))
                               .unwrap());
        }
        if self.output_tensors[output_idx].is_null() {
            return Err(Status::new_set(Code::Unavailable,
                                       "Output not available. Either it was already taken, or \
                                        this step has not been sucessfully run yet.")
                               .unwrap());
        }
        let actual_data_type = self.output_data_type(output_idx).unwrap();
        if actual_data_type != T::data_type() {
            return Err(invalid_arg!("Requested tensor type does not match actual tensor type: \
                                     {} vs {}",
                                    actual_data_type,
                                    T::data_type()));
        }
        let tensor = unsafe { Tensor::from_tf_tensor(self.output_tensors[output_idx]).unwrap() };
        self.output_tensors[output_idx] = ptr::null_mut();
        Ok(tensor)
    }

    /// Adds a target operation to be executed when running the graph.
    pub fn add_target(&mut self, operation: &Operation) {
        self.target_operations.push(operation.inner());
    }

    /// Retuns the type of the tensor given an index.
    /// Returns `None` if the index is out of range or the output is not yet available.
    pub fn output_data_type(&self, output_idx: usize) -> Option<DataType> {
        if output_idx >= self.output_tensors.len() {
            return None;
        }
        if self.output_tensors[output_idx].is_null() {
            return None;
        }
        unsafe { Some(DataType::from_c(tf::TF_TensorType(self.output_tensors[output_idx]))) }
    }

    fn drop_output_tensors(&mut self) {
        for mut tensor in &mut self.output_tensors {
            // TODO: Is TF_DeleteTensor NULL safe?
            if !tensor.is_null() {
                unsafe {
                    tf::TF_DeleteTensor(*tensor);
                }
            }
            *tensor = ptr::null_mut();
        }
    }
}

impl<'l> Drop for StepWithGraph<'l> {
    fn drop(&mut self) {
        self.drop_output_tensors();
    }
}

////////////////////////

#[cfg(test)]
mod tests {
    use super::*;
    use super::super::DataType;
    use super::super::Graph;
    use super::super::Operation;
    use super::super::Output;
    use super::super::SessionOptions;
    use super::super::Shape;
    use super::super::Tensor;

    fn create_session() -> (Session, Operation, Operation) {
        let mut g = Graph::new();
        let two = {
            let mut nd = g.new_operation("Const", "two").unwrap();
            nd.set_attr_type("dtype", DataType::Float).unwrap();
            let mut value = Tensor::new(&[1]);
            value[0] = 2.0f32;
            nd.set_attr_tensor("value", value).unwrap();
            nd.finish().unwrap()
        };
        let x = {
            let mut nd = g.new_operation("Placeholder", "x").unwrap();
            nd.set_attr_type("dtype", DataType::Float).unwrap();
            nd.set_attr_shape("shape", &Shape(Some(vec![]))).unwrap();
            nd.finish().unwrap()
        };
        let y = {
            let mut nd = g.new_operation("Mul", "y").unwrap();
            nd.add_input(Output {
                             operation: &two,
                             index: 0,
                         });
            nd.add_input(Output {
                             operation: &x,
                             index: 0,
                         });
            nd.finish().unwrap()
        };
        let options = SessionOptions::new();
        match Session::new(&options, &g) {
            Ok(session) => (session, x, y),
            Err(status) => panic!("Creating session failed with status: {}", status),
        }
    }

    #[test]
    fn smoke() {
        create_session();
    }

    #[test]
    fn test_close() {
        let (mut session, _, _) = create_session();
        let status = session.close();
        assert!(status.is_ok());
    }

    #[test]
    fn test_run() {
        let (mut session, x_operation, y_operation) = create_session();
        let mut x = <Tensor<f32>>::new(&[2]);
        x[0] = 2.0;
        x[1] = 3.0;
        let mut step = StepWithGraph::new();
        step.add_input(&x_operation, 0, &x);
        let output_token = step.request_output(&y_operation, 0);
        session.run(&mut step).unwrap();
        let output_tensor = step.take_output::<f32>(output_token).unwrap();
        let data = output_tensor.data();
        assert_eq!(data.len(), 2);
        assert_eq!(data[0], 4.0);
        assert_eq!(data[1], 6.0);
    }
}
<commit_msg>Refactor code<commit_after>use tf;
use libc::{c_char, c_int};
use std::ffi::CString;
use std::marker;
use std::path::Path;
use std::ptr;
use super::Code;
use super::DataType;
use super::Graph;
use super::GraphTrait;
use super::Operation;
use super::OperationTrait;
use super::Result;
use super::SessionOptions;
use super::Status;
use super::Tensor;
use super::TensorType;

/// Manages a single graph and execution.
#[derive(Debug)]
pub struct Session {
    inner: *mut tf::TF_Session,
}

impl Session {
    /// Creates a session.
    pub fn new(options: &SessionOptions, graph: &Graph) -> Result<Self> {
        let mut status = Status::new();
        let inner = unsafe { tf::TF_NewSession(graph.inner(), options.inner, status.inner()) };
        if inner.is_null() {
            Err(status)
        } else {
            Ok(Session { inner: inner })
        }
    }

    /// Loads a session from an exported model.
    pub fn from_saved_model<P: AsRef<Path>, Tag: AsRef<str>, Tags: IntoIterator<Item = Tag>>
        (options: &SessionOptions,
         tags: Tags,
         graph: &mut Graph,
         export_dir: P)
         -> Result<Self> {
        let mut status = Status::new();

        let export_dir_cstr =
            try!(export_dir.as_ref()
                     .to_str()
                     .and_then(|s| CString::new(s.as_bytes()).ok())
                     .ok_or_else(|| invalid_arg!("Invalid export directory path")));

        let tags_cstr: Vec<_> = try!(tags.into_iter()
                                         .map(|t| CString::new(t.as_ref()))
                                         .collect::<::std::result::Result<_, _>>()
                                         .map_err(|_| invalid_arg!("Invalid tag name")));
        // keeping tags_cstr to retain strings in memory
        let tags_ptr: Vec<*const c_char> = tags_cstr.iter().map(|t| t.as_ptr()).collect();

        let inner = unsafe {
            tf::TF_LoadSessionFromSavedModel(options.inner,
                                             ptr::null(),
                                             export_dir_cstr.as_ptr(),
                                             tags_ptr.as_ptr(),
                                             tags_ptr.len() as c_int,
                                             graph.inner(),
                                             ptr::null_mut(),
                                             status.inner())
        };
        if inner.is_null() {
            Err(status)
        } else {
            Ok(Session { inner: inner })
        }
    }

    /// Closes the session.
    pub fn close(&mut self) -> Result<()> {
        let mut status = Status::new();
        unsafe {
            tf::TF_CloseSession(self.inner, status.inner());
        }
        status.into_result()
    }

    /// Runs the graph, feeding the inputs and then fetching the outputs requested in the step.
    pub fn run(&mut self, step: &mut StepWithGraph) -> Result<()> {
        // Copy the input tensors because TF_Run consumes them.
        let mut input_tensors = Vec::with_capacity(step.input_tensors.len());
        for &input_tensor in &step.input_tensors {
            unsafe {
                let mut dims = Vec::with_capacity(tf::TF_NumDims(input_tensor) as usize);
                for i in 0..dims.capacity() {
                    dims.push(tf::TF_Dim(input_tensor, i as c_int));
                }
                input_tensors.push(tf::TF_NewTensor(tf::TF_TensorType(input_tensor),
                                                    dims.as_ptr(),
                                                    dims.len() as c_int,
                                                    tf::TF_TensorData(input_tensor),
                                                    tf::TF_TensorByteSize(input_tensor),
                                                    Some(super::noop_deallocator),
                                                    ptr::null_mut()));
            }
        }

        // In case we're running it a second time and not all outputs were taken out.
        step.drop_output_tensors();

        let mut status = Status::new();
        unsafe {
            tf::TF_SessionRun(self.inner,
                              ptr::null(),
                              step.input_ports.as_ptr(),
                              input_tensors.as_mut_ptr(),
                              input_tensors.len() as c_int,
                              step.output_ports.as_ptr(),
                              step.output_tensors.as_mut_ptr(),
                              step.output_tensors.len() as c_int,
                              step.target_operations.as_mut_ptr(),
                              step.target_operations.len() as c_int,
                              ptr::null_mut(),
                              status.inner());
        };
        status.into_result()
    }
}

impl Drop for Session {
    fn drop(&mut self) {
        let mut status = Status::new();
        unsafe {
            tf::TF_DeleteSession(self.inner, status.inner());
        }
        // TODO: What do we do with the status?
    }
}

////////////////////////

/// An opaque token for retrieving an output from a computation.
#[derive(Copy,Clone,Debug)]
pub struct OutputToken {
    index: usize,
}

/// Manages the inputs and outputs for a single execution of a graph.
///
/// Typical usage involves creating an instance of this struct,
/// adding some inputs to it, requesting some outputs, passing it to `Session::run`
/// and then taking the outputs out of it.
///
/// This will be renamed to Step once the old API goes away.
#[derive(Debug)]
pub struct StepWithGraph<'l> {
    input_ports: Vec<tf::TF_Output>,
    input_tensors: Vec<*mut tf::TF_Tensor>,

    output_ports: Vec<tf::TF_Output>,
    output_tensors: Vec<*mut tf::TF_Tensor>,

    target_operations: Vec<*const tf::TF_Operation>,

    phantom: marker::PhantomData<&'l ()>,
}

impl<'l> StepWithGraph<'l> {
    /// Creates a StepWithGraph.
    pub fn new() -> Self {
        StepWithGraph {
            input_ports: vec![],
            input_tensors: vec![],

            output_ports: vec![],
            output_tensors: vec![],

            target_operations: vec![],

            phantom: marker::PhantomData,
        }
    }

    /// Adds an input to be fed to the graph.
    pub fn add_input<T: TensorType>(&mut self,
                                    operation: &Operation,
                                    index: c_int,
                                    tensor: &'l Tensor<T>) {
        self.input_ports.push(tf::TF_Output {
                                  operation: operation.inner(),
                                  index: index,
                              });
        self.input_tensors.push(tensor.inner);
    }

    /// Requests that an output is fetched from the graph after running this step.
    /// Returns an index that you can then use to fetch this output from the step after running it.
    pub fn request_output(&mut self, operation: &Operation, index: c_int) -> OutputToken {
        self.output_ports.push(tf::TF_Output {
                                   operation: operation.inner(),
                                   index: index,
                               });
        self.output_tensors.push(ptr::null_mut());
        OutputToken { index: self.output_tensors.len() - 1 }
    }

    /// Extracts a tensor output given an index. A given index can only be extracted
    /// once per `Session::run`.
    /// Returns an error if output_idx is out of range, output is unavailable or the
    /// requested type does not match the type of the actual tensor.
    pub fn take_output<T: TensorType>(&mut self, token: OutputToken) -> Result<Tensor<T>> {
        let output_idx = token.index;
        if output_idx >= self.output_tensors.len() {
            return Err(Status::new_set(Code::OutOfRange,
                                       &format!("Requested output index is out of range: {} vs \
                                                 {}",
                                                output_idx,
                                                self.output_tensors.len()))
                               .unwrap());
        }
        if self.output_tensors[output_idx].is_null() {
            return Err(Status::new_set(Code::Unavailable,
                                       "Output not available. Either it was already taken, or \
                                        this step has not been sucessfully run yet.")
                               .unwrap());
        }
        let actual_data_type = self.output_data_type(output_idx).unwrap();
        if actual_data_type != T::data_type() {
            return Err(invalid_arg!("Requested tensor type does not match actual tensor type: \
                                     {} vs {}",
                                    actual_data_type,
                                    T::data_type()));
        }
        let tensor = unsafe { Tensor::from_tf_tensor(self.output_tensors[output_idx]).unwrap() };
        self.output_tensors[output_idx] = ptr::null_mut();
        Ok(tensor)
    }

    /// Adds a target operation to be executed when running the graph.
    pub fn add_target(&mut self, operation: &Operation) {
        self.target_operations.push(operation.inner());
    }

    /// Retuns the type of the tensor given an index.
    /// Returns `None` if the index is out of range or the output is not yet available.
    pub fn output_data_type(&self, output_idx: usize) -> Option<DataType> {
        if output_idx >= self.output_tensors.len() {
            return None;
        }
        if self.output_tensors[output_idx].is_null() {
            return None;
        }
        unsafe { Some(DataType::from_c(tf::TF_TensorType(self.output_tensors[output_idx]))) }
    }

    fn drop_output_tensors(&mut self) {
        for mut tensor in &mut self.output_tensors {
            // TODO: Is TF_DeleteTensor NULL safe?
            if !tensor.is_null() {
                unsafe {
                    tf::TF_DeleteTensor(*tensor);
                }
            }
            *tensor = ptr::null_mut();
        }
    }
}

impl<'l> Drop for StepWithGraph<'l> {
    fn drop(&mut self) {
        self.drop_output_tensors();
    }
}

////////////////////////

#[cfg(test)]
mod tests {
    use super::*;
    use super::super::DataType;
    use super::super::Graph;
    use super::super::Operation;
    use super::super::Output;
    use super::super::SessionOptions;
    use super::super::Shape;
    use super::super::Tensor;

    fn create_session() -> (Session, Operation, Operation) {
        let mut g = Graph::new();
        let two = {
            let mut nd = g.new_operation("Const", "two").unwrap();
            nd.set_attr_type("dtype", DataType::Float).unwrap();
            let mut value = Tensor::new(&[1]);
            value[0] = 2.0f32;
            nd.set_attr_tensor("value", value).unwrap();
            nd.finish().unwrap()
        };
        let x = {
            let mut nd = g.new_operation("Placeholder", "x").unwrap();
            nd.set_attr_type("dtype", DataType::Float).unwrap();
            nd.set_attr_shape("shape", &Shape(Some(vec![]))).unwrap();
            nd.finish().unwrap()
        };
        let y = {
            let mut nd = g.new_operation("Mul", "y").unwrap();
            nd.add_input(Output {
                             operation: &two,
                             index: 0,
                         });
            nd.add_input(Output {
                             operation: &x,
                             index: 0,
                         });
            nd.finish().unwrap()
        };
        let options = SessionOptions::new();
        match Session::new(&options, &g) {
            Ok(session) => (session, x, y),
            Err(status) => panic!("Creating session failed with status: {}", status),
        }
    }

    #[test]
    fn smoke() {
        create_session();
    }

    #[test]
    fn test_close() {
        let (mut session, _, _) = create_session();
        let status = session.close();
        assert!(status.is_ok());
    }

    #[test]
    fn test_run() {
        let (mut session, x_operation, y_operation) = create_session();
        let mut x = <Tensor<f32>>::new(&[2]);
        x[0] = 2.0;
        x[1] = 3.0;
        let mut step = StepWithGraph::new();
        step.add_input(&x_operation, 0, &x);
        let output_token = step.request_output(&y_operation, 0);
        session.run(&mut step).unwrap();
        let output_tensor = step.take_output::<f32>(output_token).unwrap();
        let data = output_tensor.data();
        assert_eq!(data.len(), 2);
        assert_eq!(data[0], 4.0);
        assert_eq!(data[1], 6.0);
    }
}

<|endoftext|>