<commit_before>use std::prelude::v1::*;
use std::env::args;
use std::io;
use std::io::Write;
//use std::rand::FloatMath::*;

#[derive(Debug)]
pub enum TokenType {
    Plus,
    Minus,
    Divide,
    Multiply,
    Exponent,
    OpenParen,
    CloseParen,
    Number,
    Error
}

impl TokenType {
    pub fn to_string(&self) -> &'static str {
        match self {
            &TokenType::Plus       => "Plus",
            &TokenType::Minus      => "Minus",
            &TokenType::Divide     => "Divide",
            &TokenType::Multiply   => "Multiply",
            &TokenType::Exponent   => "Exponent",
            &TokenType::OpenParen  => "OpenParen",
            &TokenType::CloseParen => "CloseParen",
            &TokenType::Number     => "Number",
            &TokenType::Error      => "Error",
        }
    }
}

#[derive(Debug)]
pub struct Token {
    token_type: TokenType,
    contents: String
}

impl Token {
    pub fn new<S: Into<String>>(t: TokenType, s: S) -> Self {
        Token {
            token_type: t,
            contents: s.into()
        }
    }

    pub fn new_number<S: Into<String>>(number: S) -> Self {
        Token {
            token_type: TokenType::Number,
            contents: number.into()
        }
    }

    pub fn new_operator(operator: char) -> Self {
        let mut op = String::with_capacity(1);
        let op_type = match operator {
            '+' => TokenType::Plus,
            '-' => TokenType::Minus,
            '/' => TokenType::Divide,
            '*' => TokenType::Multiply,
            '^' => TokenType::Exponent,
            '(' => TokenType::OpenParen,
            ')' => TokenType::CloseParen,
            _   => unreachable!(), // TODO: should indicate error here
        };
        op.push(operator);
        Token {
            token_type: op_type,
            contents: op
        }
    }

    pub fn to_string(&self) -> String {
        [ self.token_type.to_string(), "(", self.contents.as_str(), ")" ].join("")
    }
}

#[derive(Debug)]
pub enum ParseError {
    InvalidNumber(String),
    UnrecognizedToken(String),
    UnexpectedToken(String, &'static str),
    UnexpectedEndOfInput,
    OtherError(String),
}

#[derive(Clone,Debug)]
pub struct IntermediateResult {
    value: f64,
    tokens_read: usize,
}

impl IntermediateResult {
    fn new(value: f64, tokens_read: usize) -> Self {
        IntermediateResult {
            value: value,
            tokens_read: tokens_read,
        }
    }
}

pub trait IsOperator {
	fn is_operator(self) -> bool;
}

impl IsOperator for char {
    fn is_operator(self) -> bool {
        self == '+' ||
        self == '-' ||
        self == '*' ||
        self == '/' ||
        self == '^' ||
        self == '(' ||
        self == ')'
    }
}

// Vec<Token> -> String
// take a vector of tokens and produce a string representation of the form: TokenType(token contents) ...
// tokens_to_string([Number(3), Plus(+), Number(4)]) => "Number(3) Plus(+) Number(4)"
// tokens_to_string([Number(3), Multiple(+), Number(4), Plus(+), Number(5)]) => "Number(3) Multiple(+) Number(4) Plus(+) Number(5)"
pub fn tokens_to_string(tokens: &[Token]) -> String {
    let v: Vec<String> = tokens.iter()
          .map(|t| t.to_string())
          .collect();
    v.join(" ")
}

// String -> Vec<Token>
// purpose: take an input string and return a vector of tokens
// tokenize("3+4") => [Number(3), Plus(+), Number(4)]
// tokenize("3 * 4 + 5") => [Number(3), Multiple(+), Number(4), Plus(+), Number(5)]
// tokenize("3 + 4 / 5") => [Number(3), Plus(+), Number(4), Divide(+), Number(5)]
pub fn tokenize(input: &str) -> Result<Vec<Token>, ParseError> {
    // CONSIDER: any smarter way to guess an initial capacity?
    let mut tokens: Vec<Token> = Vec::with_capacity(25);

    // TODO: Not this. Modify to use iterator
    let chars: Vec<char> = input.chars().collect();

    let input_length = chars.len();
    let mut current_pos = 0;
    while current_pos < input_length {
        let c : char = chars[current_pos];
        if c.is_digit(10) {
            let token_string = consume_number(&chars[current_pos..]);
            current_pos += token_string.len();
            tokens.push(Token::new_number(token_string));
        } else if c.is_operator() {
            tokens.push(Token::new_operator(chars[current_pos]));
            current_pos += 1;
        } else if c.is_whitespace() {
            current_pos += 1;
        } else {
            let token_string = consume_until_new_token(&chars[current_pos..]);
            return Err(ParseError::UnrecognizedToken(token_string));
        }
    }
    Ok(tokens)
}

fn consume_number(input: &[char]) -> String {
    // CONSIDER: input.len seems a bit generous
    let mut number = String::with_capacity(input.len());
    let mut has_decimal_point = false;
    for &c in input {
        if c == '.' {
            if has_decimal_point {
                break;
            } else {
                number.push(c);
                has_decimal_point = true;
            }
        } else if c.is_digit(10) {
            number.push(c);
        } else {
            break;
        }
    }
    number
}

fn consume_until_new_token(input: &[char]) -> String {
    input.iter()
         .take_while(|c| !(c.is_whitespace() || c.is_operator() || c.is_digit(10)))
         .map(|&c| c)
         .collect()
}

// Addition and subtraction
pub fn e_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    let mut t1 = try!(t_expr(token_list));
    let mut index = t1.tokens_read;

    while index < token_list.len() {
        match token_list[index].token_type {
            TokenType::Plus => {
                let t2 = try!(t_expr(&token_list[index+1..]));
                t1.value += t2.value;
                t1.tokens_read += t2.tokens_read + 1;
            }
            TokenType::Minus => {
                let t2 = try!(t_expr(&token_list[index+1..]));
                t1.value -= t2.value;
                t1.tokens_read += t2.tokens_read + 1;
            }
            TokenType::Number => return Err(ParseError::UnexpectedToken(token_list[index].contents.clone(),"operator")),
            _ => return break,
        };
        index = t1.tokens_read;
    }
    Ok(t1)
}

// Multiplication and division
pub fn t_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    let mut f1 = try!(f_expr(token_list));
    let mut index = f1.tokens_read;

    while index < token_list.len() {
        match token_list[index].token_type {
            TokenType::Multiply => {
                let f2 = try!(f_expr(&token_list[index+1..]));
                f1.value *= f2.value;
                f1.tokens_read += f2.tokens_read + 1;
            }
            TokenType::Divide => {
                let f2 = try!(f_expr(&token_list[index+1..]));
                if f2.value == 0.0 {
                    return Err(ParseError::OtherError("Divide by zero error".to_owned()));
                } else {
                    f1.value /= f2.value;
                    f1.tokens_read += f2.tokens_read + 1;
                }
            }
            TokenType::Number => return Err(ParseError::UnexpectedToken(token_list[index].contents.clone(),"operator")),
            _ => break,
        }
        index = f1.tokens_read;
    }
    Ok(f1)
}

// Exponentiation
pub fn f_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    let mut g1 = try!(g_expr(token_list));
    // TODO: uncomment all of this once I can figure out why powf won't work
    /*
    let mut index = g1.tokens_read;
    let token_len = token_list.len();
    while index < token_len {
        match token_list[index].token_type {
            TokenType::Exponent => {
                let f = try!(f_expr(&token_list[index+1..]));
                g1.value = g1.value.powf(f.value);
                g1.tokens_read += f.tokens_read + 1;
            }
            TokenType::Number => return Err(ParseError::UnexpectedToken(token_list[index].contents.clone(),"operator")),
            _ => break,
        }
        index = g1.tokens_read;
    }
    */
    Ok(g1)
}

// Numbers and parenthesized expressions
pub fn g_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    if !token_list.is_empty() {
        match token_list[0].token_type {
            TokenType::Number => {
                token_list[0].contents.parse::<f64>()
                    .map_err(|_| ParseError::InvalidNumber(token_list[0].contents.clone()))
                    .and_then(|num| Ok(IntermediateResult::new(num, 1)))
            }
            TokenType::Minus => {
                if token_list.len() > 1 {
                    token_list[1].contents.parse::<f64>()
                        .map_err(|_| ParseError::InvalidNumber(token_list[1].contents.clone()))
                        .and_then(|num| Ok(IntermediateResult::new(-1.0 * num, 2)))
                } else {
                    Err(ParseError::UnexpectedToken(token_list[1].contents.clone(), "number"))
                }
            }
            TokenType::OpenParen => {
                let expr = e_expr(&token_list[1..]);
                match expr {
                    Ok(ir) => {
                        let close_paren = ir.tokens_read + 1;
                        if close_paren < token_list.len() {
                            match token_list[close_paren].token_type {
                                TokenType::CloseParen => Ok(IntermediateResult::new(ir.value, close_paren+1)),
                                _ => Err(ParseError::UnexpectedToken(token_list[close_paren].contents.clone(), ")")),
                            }
                        } else {
                            Err(ParseError::OtherError("no matching close parenthesis found.".to_owned()))
                        }
                    }
                    Err(e) => Err(e),
                }
            }
            _ => Err(ParseError::UnexpectedToken(token_list[0].contents.clone(), "number"))
        }
    } else {
        Err(ParseError::UnexpectedEndOfInput)
    }
}

pub fn parse(tokens: Vec<Token>) -> Result<String, ParseError> {
    e_expr(&tokens[..]).map(|answer| answer.value.to_string())
}

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

    #[test]
    fn simple_addition() {
        assert_eq!(tokenize("12+3").and_then(parse).unwrap(), "15");
    }

    #[test]
    fn addition() {
        assert_eq!(tokenize("12+3+5").and_then(parse).unwrap(), "20");
    }

    #[test]
    fn simple_subtraction() {
        assert_eq!(tokenize("12-3").and_then(parse).unwrap(), "9");
    }

    #[test]
    fn subtraction() {
        assert_eq!(tokenize("12-3-4").and_then(parse).unwrap(), "5");
    }

    #[test]
    fn mixed_addition_and_subtraction() {
        assert_eq!(tokenize("12+3-4+8-2-3").and_then(parse).unwrap(), "14");
    }

    #[test]
    fn simple_parentheses() {
        assert_eq!(tokenize("((3))").and_then(parse).unwrap(), "3");
        assert_eq!(tokenize("(12+(2+3))").and_then(parse).unwrap(), "17");
        assert_eq!(tokenize("12+(2+3)").and_then(parse).unwrap(), "17");
    }

    #[test]
    fn parentheses() {
        assert_eq!(tokenize("12+(2+(3+5))+4+(((6)))").and_then(parse).unwrap(), "32");
    }

    #[test]
    fn multiplication() {
        assert_eq!(tokenize("3*3").and_then(parse).unwrap(), "9");
        assert_eq!(tokenize("3*5").and_then(parse).unwrap(), "15");
        assert_eq!(tokenize("0*5").and_then(parse).unwrap(), "0");
        assert_eq!(tokenize("5*4*3*2*1").and_then(parse).unwrap(), "120");
        assert_eq!(tokenize("(5*4)*3*(2*1)").and_then(parse).unwrap(), "120");
    }

    #[test]
    fn division() {
        assert_eq!(tokenize("12/4").and_then(parse).unwrap(), "3");
        assert_eq!(tokenize("12/3").and_then(parse).unwrap(), "4");
        assert_eq!(tokenize("5/2").and_then(parse).unwrap(), "2.5");
        assert_eq!(tokenize("120/5/4/3/2").and_then(parse).unwrap(), "1");
        assert_eq!(tokenize("(120/5)/4/(3/2)").and_then(parse).unwrap(), "4");
    }

    #[test]
    fn exponentiation() {
        assert_eq!(tokenize("3^2").and_then(parse).unwrap(), "9");
        assert_eq!(tokenize("2^3^2").and_then(parse).unwrap(), "512");
        assert_eq!(tokenize("2^(2+1)^2").and_then(parse).unwrap(), "512");
    }
}

fn eval(input: &str) -> String {
    match tokenize(input).and_then(parse) {
        Ok(s) => s,
        Err(e) => match e {
            ParseError::InvalidNumber(s) => ["Invalid number: ", s.as_str() ].join(""),
            ParseError::UnrecognizedToken(s) => ["Unrecognized token: ", s.as_str()].join(""),
            ParseError::UnexpectedToken(found, expected) => ["Unexpected token: expected [", expected, "] but found '", found.as_str(), "'"].join(""),
            ParseError::UnexpectedEndOfInput => "Error: Unexpected end of input.".to_owned(),
            ParseError::OtherError(s) => s,
        }
    }
}

fn main() {
    let args = args();
    if args.len() > 1 {
        let input: Vec<String> = args.skip(1).collect();
        println!("{}", eval(&input.join("")));
    } else {
        let mut stdout = io::stdout();
        let mut stdin = io::stdin();
        loop {
            print!("[]> ");
            stdout.flush();
            let mut input = String::new();
            stdin.read_line(&mut input)
                 .expect("Error reading input");
            match input.trim() {
                "exit" => break,
                s => println!("{}", eval(s)),
            }
        }
    }
}
<commit_msg>Comment out exponentiation tests for now<commit_after>use std::prelude::v1::*;
use std::env::args;
use std::io;
use std::io::Write;
//use std::rand::FloatMath::*;

#[derive(Debug)]
pub enum TokenType {
    Plus,
    Minus,
    Divide,
    Multiply,
    Exponent,
    OpenParen,
    CloseParen,
    Number,
    Error
}

impl TokenType {
    pub fn to_string(&self) -> &'static str {
        match self {
            &TokenType::Plus       => "Plus",
            &TokenType::Minus      => "Minus",
            &TokenType::Divide     => "Divide",
            &TokenType::Multiply   => "Multiply",
            &TokenType::Exponent   => "Exponent",
            &TokenType::OpenParen  => "OpenParen",
            &TokenType::CloseParen => "CloseParen",
            &TokenType::Number     => "Number",
            &TokenType::Error      => "Error",
        }
    }
}

#[derive(Debug)]
pub struct Token {
    token_type: TokenType,
    contents: String
}

impl Token {
    pub fn new<S: Into<String>>(t: TokenType, s: S) -> Self {
        Token {
            token_type: t,
            contents: s.into()
        }
    }

    pub fn new_number<S: Into<String>>(number: S) -> Self {
        Token {
            token_type: TokenType::Number,
            contents: number.into()
        }
    }

    pub fn new_operator(operator: char) -> Self {
        let mut op = String::with_capacity(1);
        let op_type = match operator {
            '+' => TokenType::Plus,
            '-' => TokenType::Minus,
            '/' => TokenType::Divide,
            '*' => TokenType::Multiply,
            '^' => TokenType::Exponent,
            '(' => TokenType::OpenParen,
            ')' => TokenType::CloseParen,
            _   => unreachable!(), // TODO: should indicate error here
        };
        op.push(operator);
        Token {
            token_type: op_type,
            contents: op
        }
    }

    pub fn to_string(&self) -> String {
        [ self.token_type.to_string(), "(", self.contents.as_str(), ")" ].join("")
    }
}

#[derive(Debug)]
pub enum ParseError {
    InvalidNumber(String),
    UnrecognizedToken(String),
    UnexpectedToken(String, &'static str),
    UnexpectedEndOfInput,
    OtherError(String),
}

#[derive(Clone,Debug)]
pub struct IntermediateResult {
    value: f64,
    tokens_read: usize,
}

impl IntermediateResult {
    fn new(value: f64, tokens_read: usize) -> Self {
        IntermediateResult {
            value: value,
            tokens_read: tokens_read,
        }
    }
}

pub trait IsOperator {
	fn is_operator(self) -> bool;
}

impl IsOperator for char {
    fn is_operator(self) -> bool {
        self == '+' ||
        self == '-' ||
        self == '*' ||
        self == '/' ||
        self == '^' ||
        self == '(' ||
        self == ')'
    }
}

// Vec<Token> -> String
// take a vector of tokens and produce a string representation of the form: TokenType(token contents) ...
// tokens_to_string([Number(3), Plus(+), Number(4)]) => "Number(3) Plus(+) Number(4)"
// tokens_to_string([Number(3), Multiple(+), Number(4), Plus(+), Number(5)]) => "Number(3) Multiple(+) Number(4) Plus(+) Number(5)"
pub fn tokens_to_string(tokens: &[Token]) -> String {
    let v: Vec<String> = tokens.iter()
          .map(|t| t.to_string())
          .collect();
    v.join(" ")
}

// String -> Vec<Token>
// purpose: take an input string and return a vector of tokens
// tokenize("3+4") => [Number(3), Plus(+), Number(4)]
// tokenize("3 * 4 + 5") => [Number(3), Multiple(+), Number(4), Plus(+), Number(5)]
// tokenize("3 + 4 / 5") => [Number(3), Plus(+), Number(4), Divide(+), Number(5)]
pub fn tokenize(input: &str) -> Result<Vec<Token>, ParseError> {
    // CONSIDER: any smarter way to guess an initial capacity?
    let mut tokens: Vec<Token> = Vec::with_capacity(25);

    // TODO: Not this. Modify to use iterator
    let chars: Vec<char> = input.chars().collect();

    let input_length = chars.len();
    let mut current_pos = 0;
    while current_pos < input_length {
        let c : char = chars[current_pos];
        if c.is_digit(10) {
            let token_string = consume_number(&chars[current_pos..]);
            current_pos += token_string.len();
            tokens.push(Token::new_number(token_string));
        } else if c.is_operator() {
            tokens.push(Token::new_operator(chars[current_pos]));
            current_pos += 1;
        } else if c.is_whitespace() {
            current_pos += 1;
        } else {
            let token_string = consume_until_new_token(&chars[current_pos..]);
            return Err(ParseError::UnrecognizedToken(token_string));
        }
    }
    Ok(tokens)
}

fn consume_number(input: &[char]) -> String {
    // CONSIDER: input.len seems a bit generous
    let mut number = String::with_capacity(input.len());
    let mut has_decimal_point = false;
    for &c in input {
        if c == '.' {
            if has_decimal_point {
                break;
            } else {
                number.push(c);
                has_decimal_point = true;
            }
        } else if c.is_digit(10) {
            number.push(c);
        } else {
            break;
        }
    }
    number
}

fn consume_until_new_token(input: &[char]) -> String {
    input.iter()
         .take_while(|c| !(c.is_whitespace() || c.is_operator() || c.is_digit(10)))
         .map(|&c| c)
         .collect()
}

// Addition and subtraction
pub fn e_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    let mut t1 = try!(t_expr(token_list));
    let mut index = t1.tokens_read;

    while index < token_list.len() {
        match token_list[index].token_type {
            TokenType::Plus => {
                let t2 = try!(t_expr(&token_list[index+1..]));
                t1.value += t2.value;
                t1.tokens_read += t2.tokens_read + 1;
            }
            TokenType::Minus => {
                let t2 = try!(t_expr(&token_list[index+1..]));
                t1.value -= t2.value;
                t1.tokens_read += t2.tokens_read + 1;
            }
            TokenType::Number => return Err(ParseError::UnexpectedToken(token_list[index].contents.clone(),"operator")),
            _ => return break,
        };
        index = t1.tokens_read;
    }
    Ok(t1)
}

// Multiplication and division
pub fn t_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    let mut f1 = try!(f_expr(token_list));
    let mut index = f1.tokens_read;

    while index < token_list.len() {
        match token_list[index].token_type {
            TokenType::Multiply => {
                let f2 = try!(f_expr(&token_list[index+1..]));
                f1.value *= f2.value;
                f1.tokens_read += f2.tokens_read + 1;
            }
            TokenType::Divide => {
                let f2 = try!(f_expr(&token_list[index+1..]));
                if f2.value == 0.0 {
                    return Err(ParseError::OtherError("Divide by zero error".to_owned()));
                } else {
                    f1.value /= f2.value;
                    f1.tokens_read += f2.tokens_read + 1;
                }
            }
            TokenType::Number => return Err(ParseError::UnexpectedToken(token_list[index].contents.clone(),"operator")),
            _ => break,
        }
        index = f1.tokens_read;
    }
    Ok(f1)
}

// Exponentiation
pub fn f_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    let mut g1 = try!(g_expr(token_list));
    // TODO: uncomment all of this once I can figure out why powf won't work
    /*
    let mut index = g1.tokens_read;
    let token_len = token_list.len();
    while index < token_len {
        match token_list[index].token_type {
            TokenType::Exponent => {
                let f = try!(f_expr(&token_list[index+1..]));
                g1.value = g1.value.powf(f.value);
                g1.tokens_read += f.tokens_read + 1;
            }
            TokenType::Number => return Err(ParseError::UnexpectedToken(token_list[index].contents.clone(),"operator")),
            _ => break,
        }
        index = g1.tokens_read;
    }
    */
    Ok(g1)
}

// Numbers and parenthesized expressions
pub fn g_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    if !token_list.is_empty() {
        match token_list[0].token_type {
            TokenType::Number => {
                token_list[0].contents.parse::<f64>()
                    .map_err(|_| ParseError::InvalidNumber(token_list[0].contents.clone()))
                    .and_then(|num| Ok(IntermediateResult::new(num, 1)))
            }
            TokenType::Minus => {
                if token_list.len() > 1 {
                    token_list[1].contents.parse::<f64>()
                        .map_err(|_| ParseError::InvalidNumber(token_list[1].contents.clone()))
                        .and_then(|num| Ok(IntermediateResult::new(-1.0 * num, 2)))
                } else {
                    Err(ParseError::UnexpectedToken(token_list[1].contents.clone(), "number"))
                }
            }
            TokenType::OpenParen => {
                let expr = e_expr(&token_list[1..]);
                match expr {
                    Ok(ir) => {
                        let close_paren = ir.tokens_read + 1;
                        if close_paren < token_list.len() {
                            match token_list[close_paren].token_type {
                                TokenType::CloseParen => Ok(IntermediateResult::new(ir.value, close_paren+1)),
                                _ => Err(ParseError::UnexpectedToken(token_list[close_paren].contents.clone(), ")")),
                            }
                        } else {
                            Err(ParseError::OtherError("no matching close parenthesis found.".to_owned()))
                        }
                    }
                    Err(e) => Err(e),
                }
            }
            _ => Err(ParseError::UnexpectedToken(token_list[0].contents.clone(), "number"))
        }
    } else {
        Err(ParseError::UnexpectedEndOfInput)
    }
}

pub fn parse(tokens: Vec<Token>) -> Result<String, ParseError> {
    e_expr(&tokens[..]).map(|answer| answer.value.to_string())
}

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

    #[test]
    fn simple_addition() {
        assert_eq!(tokenize("12+3").and_then(parse).unwrap(), "15");
    }

    #[test]
    fn addition() {
        assert_eq!(tokenize("12+3+5").and_then(parse).unwrap(), "20");
    }

    #[test]
    fn simple_subtraction() {
        assert_eq!(tokenize("12-3").and_then(parse).unwrap(), "9");
    }

    #[test]
    fn subtraction() {
        assert_eq!(tokenize("12-3-4").and_then(parse).unwrap(), "5");
    }

    #[test]
    fn mixed_addition_and_subtraction() {
        assert_eq!(tokenize("12+3-4+8-2-3").and_then(parse).unwrap(), "14");
    }

    #[test]
    fn simple_parentheses() {
        assert_eq!(tokenize("((3))").and_then(parse).unwrap(), "3");
        assert_eq!(tokenize("(12+(2+3))").and_then(parse).unwrap(), "17");
        assert_eq!(tokenize("12+(2+3)").and_then(parse).unwrap(), "17");
    }

    #[test]
    fn parentheses() {
        assert_eq!(tokenize("12+(2+(3+5))+4+(((6)))").and_then(parse).unwrap(), "32");
    }

    #[test]
    fn multiplication() {
        assert_eq!(tokenize("3*3").and_then(parse).unwrap(), "9");
        assert_eq!(tokenize("3*5").and_then(parse).unwrap(), "15");
        assert_eq!(tokenize("0*5").and_then(parse).unwrap(), "0");
        assert_eq!(tokenize("5*4*3*2*1").and_then(parse).unwrap(), "120");
        assert_eq!(tokenize("(5*4)*3*(2*1)").and_then(parse).unwrap(), "120");
    }

    #[test]
    fn division() {
        assert_eq!(tokenize("12/4").and_then(parse).unwrap(), "3");
        assert_eq!(tokenize("12/3").and_then(parse).unwrap(), "4");
        assert_eq!(tokenize("5/2").and_then(parse).unwrap(), "2.5");
        assert_eq!(tokenize("120/5/4/3/2").and_then(parse).unwrap(), "1");
        assert_eq!(tokenize("(120/5)/4/(3/2)").and_then(parse).unwrap(), "4");
    }

    /*
    #[test]
    fn exponentiation() {
        assert_eq!(tokenize("3^2").and_then(parse).unwrap(), "9");
        assert_eq!(tokenize("2^3^2").and_then(parse).unwrap(), "512");
        assert_eq!(tokenize("2^(2+1)^2").and_then(parse).unwrap(), "512");
    }
    */
}

fn eval(input: &str) -> String {
    match tokenize(input).and_then(parse) {
        Ok(s) => s,
        Err(e) => match e {
            ParseError::InvalidNumber(s) => ["Invalid number: ", s.as_str() ].join(""),
            ParseError::UnrecognizedToken(s) => ["Unrecognized token: ", s.as_str()].join(""),
            ParseError::UnexpectedToken(found, expected) => ["Unexpected token: expected [", expected, "] but found '", found.as_str(), "'"].join(""),
            ParseError::UnexpectedEndOfInput => "Error: Unexpected end of input.".to_owned(),
            ParseError::OtherError(s) => s,
        }
    }
}

fn main() {
    let args = args();
    if args.len() > 1 {
        let input: Vec<String> = args.skip(1).collect();
        println!("{}", eval(&input.join("")));
    } else {
        let mut stdout = io::stdout();
        let mut stdin = io::stdin();
        loop {
            print!("[]> ");
            stdout.flush();
            let mut input = String::new();
            stdin.read_line(&mut input)
                 .expect("Error reading input");
            match input.trim() {
                "exit" => break,
                s => println!("{}", eval(s)),
            }
        }
    }
}
<|endoftext|>


<commit_before>//! The `leac` compiler command line utility.

#![feature(plugin)]
#![plugin(docopt_macros)]

extern crate docopt;
extern crate rustc_serialize;
extern crate bincode;
extern crate term;
extern crate lea_compiler as compiler;
extern crate lea_parser as parser;
extern crate lea;

use parser::span::DummyTerm;
use compiler::{CompileConfig, FnData};

use rustc_serialize::json;
use bincode::SizeLimit;
use bincode::rustc_serialize::EncodingError;

use std::io::{self, stdin, stderr, stdout, Read, Write};
use std::fs::File;
use std::path::Path;

#[derive(Debug, RustcDecodable)]
#[allow(non_camel_case_types)]
enum Encoding {
    json,
    bin,
    debug,
}

impl Encoding {
    pub fn encode<W: Write>(&self, fndata: &FnData, wr: &mut W)
    -> io::Result<()> {
        match *self {
            Encoding::json => {
                match json::encode(fndata) {
                    Ok(s) => Ok(try!(write!(wr, "{}", &s))),
                    Err(_) => Err(io::Error::new(io::ErrorKind::Other, "json encoding error")),
                }
            }
            Encoding::bin => {
                match bincode::rustc_serialize::encode_into(fndata, wr, SizeLimit::Infinite) {
                    Ok(_) => Ok(()),
                    Err(EncodingError::IoError(e)) => Err(e),
                    Err(EncodingError::SizeLimit) => Err(io::Error::new(io::ErrorKind::Other, "size limit reached")),
                }
            }
            Encoding::debug => {
                write!(wr, "{:#?}\n", fndata)
            }
        }
    }
}

docopt!(Args derive Debug, "
The Lea compiler

Usage:
    leac ( --help | --version )
    leac [-o <out>] [-e <enc>] [--] <file>
    leac ( -p | --pretty ) [--] <file>

Options:
    -h, --help                  Show this help.
    -v, --version               Show the version of the Lea package.
    -p, --pretty                Pretty print the source code instead of compiling it.
    -o <out>, --out <out>       Write output to <out> (`-` to write to stdout).
    -e <enc>, --encoding <enc>  The encoding to use for writing the compiled code.

By default, leac will write the compiled code to stdout. If stdout is a terminal, leac will print \
it using the `debug` encoding. Otherwise, leac will encode the compilation result in a binary \
form (`bin` encoding).
", flag_encoding: Option<Encoding>, flag_out: Option<String>);

/// Opens a terminal that writes to stderr. If stderr couldn't be opened as a terminal, creates a
/// `DummyTerm` that writes to stderr instead.
fn stderr_term() -> Box<term::StderrTerminal> {
    term::stderr().unwrap_or_else(|| Box::new(DummyTerm(io::stderr())))
}

/// Compiles a piece of code. Prints all errors / warnings to stderr, using color if stderr is a
/// terminal.
fn compile(code: &str, filename: &str) -> io::Result<Option<FnData>> {
    let mut fmt_target = stderr_term();
    let fmt_target = &mut *fmt_target;

    match compiler::compile_str(code, filename, &CompileConfig::default()) {
        Err(e) => {
            try!(e.format(code, filename, fmt_target));
            Ok(None)
        },
        Ok(output) => {
            let warns = output.warns;
            if warns.len() > 0 {
                for w in warns {
                    try!(w.format(code, filename, fmt_target));
                }
            }

            Ok(Some(output.mainproto))
        }
    }
}

fn read_file(filename: &str) -> io::Result<String> {
    let mut s = String::new();
    let mut file = try!(File::open(&Path::new(filename)));
    try!(file.read_to_string(&mut s));

    Ok(s)
}

#[allow(dead_code)]     // TODO write tests
fn main() {
    match Args::docopt().decode::<Args>() {
        Err(e) => {
            println!("{}", e);
        }
        Ok(args) => {
            match args {
                Args { flag_version: true, .. } => {
                    println!("Lea {}", lea::version_str());
                }
                Args { arg_file, flag_out, .. } => {
                    // Read input
                    let mut code = String::new();
                    let source_name;
                    if arg_file == "-" {
                        stdin().read_to_string(&mut code).unwrap();
                        source_name = "<stdin>".to_owned();
                    } else {
                        source_name = arg_file;
                        code = match read_file(&source_name) {
                            Ok(content) => content,
                            Err(e) => {
                                writeln!(stderr(), "{}", e).unwrap();
                                return;
                            }
                        }
                    }

                    // Open output
                    let mut out: Box<Write>;
                    match flag_out.as_ref().map(|s| s.as_ref()) {
                        None | Some("-") => {
                            out = Box::new(stdout()) as Box<Write>;
                        }
                        Some(s) => {
                            let f = match File::create(&Path::new(s)) {
                                Ok(f) => f,
                                Err(e) => {
                                    writeln!(stderr(), "{}", e).unwrap();
                                    return;
                                }
                            };

                            out = Box::new(f) as Box<Write>;
                        }
                    }

                    let enc = args.flag_encoding.unwrap_or(Encoding::bin);

                    match compile(&code, &source_name).unwrap() {
                        Some(fndata) => {
                            // serialize to `out`, except if `out` is a terminal and we defaulted to `-` (TODO)
                            match enc.encode(&fndata, &mut out) {
                                Err(e) => {
                                    writeln!(stderr(), "{}", e).unwrap();
                                    return;
                                }
                                _ => {}
                            }
                        }
                        None => {}
                    }
                }
            }
        }
    }
}
<commit_msg>Remove unused --pretty flag from leac<commit_after>//! The `leac` compiler command line utility.

#![feature(plugin)]
#![plugin(docopt_macros)]

extern crate docopt;
extern crate rustc_serialize;
extern crate bincode;
extern crate term;
extern crate lea_compiler as compiler;
extern crate lea_parser as parser;
extern crate lea;

use parser::span::DummyTerm;
use compiler::{CompileConfig, FnData};

use rustc_serialize::json;
use bincode::SizeLimit;
use bincode::rustc_serialize::EncodingError;

use std::io::{self, stdin, stderr, stdout, Read, Write};
use std::fs::File;
use std::path::Path;

#[derive(Debug, RustcDecodable)]
#[allow(non_camel_case_types)]
enum Encoding {
    json,
    bin,
    debug,
}

impl Encoding {
    pub fn encode<W: Write>(&self, fndata: &FnData, wr: &mut W)
    -> io::Result<()> {
        match *self {
            Encoding::json => {
                match json::encode(fndata) {
                    Ok(s) => Ok(try!(write!(wr, "{}", &s))),
                    Err(_) => Err(io::Error::new(io::ErrorKind::Other, "json encoding error")),
                }
            }
            Encoding::bin => {
                match bincode::rustc_serialize::encode_into(fndata, wr, SizeLimit::Infinite) {
                    Ok(_) => Ok(()),
                    Err(EncodingError::IoError(e)) => Err(e),
                    Err(EncodingError::SizeLimit) => Err(io::Error::new(io::ErrorKind::Other, "size limit reached")),
                }
            }
            Encoding::debug => {
                write!(wr, "{:#?}\n", fndata)
            }
        }
    }
}

docopt!(Args derive Debug, "
The Lea compiler

Usage:
    leac ( --help | --version )
    leac [-o <out>] [-e <enc>] [--] <file>

Options:
    -h, --help                  Show this help.
    -v, --version               Show the version of the Lea package.
    -o <out>, --out <out>       Write output to <out> (`-` to write to stdout).
    -e <enc>, --encoding <enc>  The encoding to use for writing the compiled code.

By default, leac will write the compiled code to stdout. If stdout is a terminal, leac will print \
it using the `debug` encoding. Otherwise, leac will encode the compilation result in a binary \
form (`bin` encoding).
", flag_encoding: Option<Encoding>, flag_out: Option<String>);

/// Opens a terminal that writes to stderr. If stderr couldn't be opened as a terminal, creates a
/// `DummyTerm` that writes to stderr instead.
fn stderr_term() -> Box<term::StderrTerminal> {
    term::stderr().unwrap_or_else(|| Box::new(DummyTerm(io::stderr())))
}

/// Compiles a piece of code. Prints all errors / warnings to stderr, using color if stderr is a
/// terminal.
fn compile(code: &str, filename: &str) -> io::Result<Option<FnData>> {
    let mut fmt_target = stderr_term();
    let fmt_target = &mut *fmt_target;

    match compiler::compile_str(code, filename, &CompileConfig::default()) {
        Err(e) => {
            try!(e.format(code, filename, fmt_target));
            Ok(None)
        },
        Ok(output) => {
            let warns = output.warns;
            if warns.len() > 0 {
                for w in warns {
                    try!(w.format(code, filename, fmt_target));
                }
            }

            Ok(Some(output.mainproto))
        }
    }
}

fn read_file(filename: &str) -> io::Result<String> {
    let mut s = String::new();
    let mut file = try!(File::open(&Path::new(filename)));
    try!(file.read_to_string(&mut s));

    Ok(s)
}

#[allow(dead_code)]     // TODO write tests
fn main() {
    match Args::docopt().decode::<Args>() {
        Err(e) => {
            println!("{}", e);
        }
        Ok(args) => {
            match args {
                Args { flag_version: true, .. } => {
                    println!("Lea {}", lea::version_str());
                }
                Args { arg_file, flag_out, .. } => {
                    // Read input
                    let mut code = String::new();
                    let source_name;
                    if arg_file == "-" {
                        stdin().read_to_string(&mut code).unwrap();
                        source_name = "<stdin>".to_owned();
                    } else {
                        source_name = arg_file;
                        code = match read_file(&source_name) {
                            Ok(content) => content,
                            Err(e) => {
                                writeln!(stderr(), "{}", e).unwrap();
                                return;
                            }
                        }
                    }

                    // Open output
                    let mut out: Box<Write>;
                    match flag_out.as_ref().map(|s| s.as_ref()) {
                        None | Some("-") => {
                            out = Box::new(stdout()) as Box<Write>;
                        }
                        Some(s) => {
                            let f = match File::create(&Path::new(s)) {
                                Ok(f) => f,
                                Err(e) => {
                                    writeln!(stderr(), "{}", e).unwrap();
                                    return;
                                }
                            };

                            out = Box::new(f) as Box<Write>;
                        }
                    }

                    let enc = args.flag_encoding.unwrap_or(Encoding::bin);

                    match compile(&code, &source_name).unwrap() {
                        Some(fndata) => {
                            // serialize to `out`, except if `out` is a terminal and we defaulted to `-` (TODO)
                            match enc.encode(&fndata, &mut out) {
                                Err(e) => {
                                    writeln!(stderr(), "{}", e).unwrap();
                                    return;
                                }
                                _ => {}
                            }
                        }
                        None => {}
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate coreutils;
extern crate extra;

use std::collections::VecDeque;
use std::env;
use std::fs;
use std::io::{self, BufRead, Read, Stderr, Write};
use coreutils::ArgParser;
use extra::option::OptionalExt;
use extra::io::{WriteExt, fail};

static MAN_PAGE: &'static str = /* @MANSTART{tail} */ r#"
NAME
    tail - output the last part of a file

SYNOPSIS
    tail [[-h | --help] | [[-n | --lines] [+]LINES] | [[-c | --bytes] [+]BYTES]] [FILE ...]

DESCRIPTION
    Print the last 10 lines of each FILE to standard output. If there are no files, read the
    standard input. If there are multiple files, prefix each one with a header containing it's
    name.

OPTIONS
    -h
    --help
        Print this manual page.

    -n LINES
    --lines LINES
        Print the last LINES lines.

    -n +LINES
    --lines +LINES
        Print all but the first LINES lines.

    -c BYTES
    --bytes BYTES
        Print the last BYTES bytes.

    -c +BYTES
    --bytes +BYTES
        Print all but the first BYTES bytes.

AUTHOR
    Written by Žad Deljkić.
"#; /* @MANEND */

fn tail<R: Read, W: Write>(input: R, output: W, stderr: &mut Stderr, parser: &ArgParser) -> io::Result<()> {
    let mut writer = io::BufWriter::new(output);
    let (skip, num): (bool, usize) =
        if let Some(num) = parser.get_opt(&'n') {
            (num.starts_with("+"), num.trim_left_matches('+').parse().try(stderr))
        }
        else if let Some(num) = parser.get_opt("lines") {
            (num.starts_with("+"), num.trim_left_matches('+').parse().try(stderr))
        }
        else if let Some(num) = parser.get_opt(&'c') {
            (num.starts_with("+"), num.trim_left_matches('+').parse().try(stderr))
        }
        else if let Some(num) = parser.get_opt("bytes") {
            (num.starts_with("+"), num.trim_left_matches('+').parse().try(stderr))
        }
        else {
            fail("missing argument (number of lines/bytes)", stderr);
        };

    if parser.found(&'n') || parser.found("lines") {
        if skip {
            let lines = io::BufReader::new(input).lines().skip(num);

            for line_res in lines {
                match line_res {
                    Ok(mut line) => {
                        line.push('\n');
                        try!(writer.write_all(line.as_bytes()));
                    }
                    Err(err) => return Err(err),
                };
            }
        } else {
            let lines = io::BufReader::new(input).lines();
            let mut deque = VecDeque::new();

            for line_res in lines {
                match line_res {
                    Ok(line) => {
                        deque.push_back(line);

                        if deque.len() > num {
                            deque.pop_front();
                        }
                    }
                    Err(err) => return Err(err),
                };
            }

            for mut line in deque {
                line.push('\n');
                try!(writer.write_all(line.as_bytes()));
            }
        }
    }
    else if parser.found(&'c') || parser.found("bytes") {
        if skip {
            let bytes = input.bytes().skip(num);

            for byte_res in bytes {
                match byte_res {
                    Ok(byte) => try!(writer.write_all(&[byte])),
                    Err(err) => return Err(err),
                };
            }
        }
        else {
            let bytes = input.bytes();
            let mut deque = VecDeque::new();

            for byte_res in bytes {
                match byte_res {
                    Ok(byte) => {
                        deque.push_back(byte);

                        if deque.len() > num {
                            deque.pop_front();
                        }
                    }
                    Err(err) => return Err(err),
                };
            }

            for byte in deque {
                try!(writer.write_all(&[byte]));
            }
        }
    }

    Ok(())
}

fn main() {
    let stdout = io::stdout();
    let mut stdout = stdout.lock();
    let mut stderr = io::stderr();
    let mut parser = ArgParser::new(3)
        .add_opt_default("n", "lines", "10")
        .add_opt("c", "bytes")
        .add_flag("h", "help");
    parser.parse(env::args());

    if parser.found(&'h') || parser.found("help") {
        stdout.write_all(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        return;
    }
    if parser.found(&'c') || parser.found("bytes") {
        *parser.opt(&'n') = "".to_owned();
        *parser.opt("lines") = "".to_owned();
    }
    if let Err(err) = parser.found_invalid() {
        stderr.write_all(err.as_bytes()).try(&mut stderr);
        stderr.flush().try(&mut stderr);
        return;
    }

    // run the main part
    if parser.args.is_empty() {
        let stdin = io::stdin();
        let stdin = stdin.lock();
        tail(stdin, stdout, &mut stderr, &parser).try(&mut stderr);
    } else if parser.args.len() == 1 {
        let file = fs::File::open(&parser.args[0]).try(&mut stderr);
        tail(file, stdout, &mut stderr, &parser).try(&mut stderr);
    } else {
        for path in &parser.args {
            let file = fs::File::open(&path).try(&mut stderr);
            stdout.write(b"==> ").try(&mut stderr);
            stdout.write(path.as_bytes()).try(&mut stderr);
            stdout.writeln(b" <==").try(&mut stderr);
            tail(file, &mut stdout, &mut stderr, &parser).try(&mut stderr);
        }
    }
}
<commit_msg>Clear the existing the string, not overwriting it with a new one<commit_after>#![deny(warnings)]

extern crate coreutils;
extern crate extra;

use std::collections::VecDeque;
use std::env;
use std::fs;
use std::io::{self, BufRead, Read, Stderr, Write};
use coreutils::ArgParser;
use extra::option::OptionalExt;
use extra::io::{WriteExt, fail};

static MAN_PAGE: &'static str = /* @MANSTART{tail} */ r#"
NAME
    tail - output the last part of a file

SYNOPSIS
    tail [[-h | --help] | [[-n | --lines] [+]LINES] | [[-c | --bytes] [+]BYTES]] [FILE ...]

DESCRIPTION
    Print the last 10 lines of each FILE to standard output. If there are no files, read the
    standard input. If there are multiple files, prefix each one with a header containing it's
    name.

OPTIONS
    -h
    --help
        Print this manual page.

    -n LINES
    --lines LINES
        Print the last LINES lines.

    -n +LINES
    --lines +LINES
        Print all but the first LINES lines.

    -c BYTES
    --bytes BYTES
        Print the last BYTES bytes.

    -c +BYTES
    --bytes +BYTES
        Print all but the first BYTES bytes.

AUTHOR
    Written by Žad Deljkić.
"#; /* @MANEND */

fn tail<R: Read, W: Write>(input: R, output: W, stderr: &mut Stderr, parser: &ArgParser) -> io::Result<()> {
    let mut writer = io::BufWriter::new(output);
    let (skip, num): (bool, usize) =
        if let Some(num) = parser.get_opt(&'n') {
            (num.starts_with("+"), num.trim_left_matches('+').parse().try(stderr))
        }
        else if let Some(num) = parser.get_opt("lines") {
            (num.starts_with("+"), num.trim_left_matches('+').parse().try(stderr))
        }
        else if let Some(num) = parser.get_opt(&'c') {
            (num.starts_with("+"), num.trim_left_matches('+').parse().try(stderr))
        }
        else if let Some(num) = parser.get_opt("bytes") {
            (num.starts_with("+"), num.trim_left_matches('+').parse().try(stderr))
        }
        else {
            fail("missing argument (number of lines/bytes)", stderr);
        };

    if parser.found(&'n') || parser.found("lines") {
        if skip {
            let lines = io::BufReader::new(input).lines().skip(num);

            for line_res in lines {
                match line_res {
                    Ok(mut line) => {
                        line.push('\n');
                        try!(writer.write_all(line.as_bytes()));
                    }
                    Err(err) => return Err(err),
                };
            }
        } else {
            let lines = io::BufReader::new(input).lines();
            let mut deque = VecDeque::new();

            for line_res in lines {
                match line_res {
                    Ok(line) => {
                        deque.push_back(line);

                        if deque.len() > num {
                            deque.pop_front();
                        }
                    }
                    Err(err) => return Err(err),
                };
            }

            for mut line in deque {
                line.push('\n');
                try!(writer.write_all(line.as_bytes()));
            }
        }
    }
    else if parser.found(&'c') || parser.found("bytes") {
        if skip {
            let bytes = input.bytes().skip(num);

            for byte_res in bytes {
                match byte_res {
                    Ok(byte) => try!(writer.write_all(&[byte])),
                    Err(err) => return Err(err),
                };
            }
        }
        else {
            let bytes = input.bytes();
            let mut deque = VecDeque::new();

            for byte_res in bytes {
                match byte_res {
                    Ok(byte) => {
                        deque.push_back(byte);

                        if deque.len() > num {
                            deque.pop_front();
                        }
                    }
                    Err(err) => return Err(err),
                };
            }

            for byte in deque {
                try!(writer.write_all(&[byte]));
            }
        }
    }

    Ok(())
}

fn main() {
    let stdout = io::stdout();
    let mut stdout = stdout.lock();
    let mut stderr = io::stderr();
    let mut parser = ArgParser::new(3)
        .add_opt_default("n", "lines", "10")
        .add_opt("c", "bytes")
        .add_flag("h", "help");
    parser.parse(env::args());

    if parser.found(&'h') || parser.found("help") {
        stdout.write_all(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        return;
    }
    if parser.found(&'c') || parser.found("bytes") {
        parser.opt(&'n').clear();
        parser.opt("lines").clear();
    }
    if let Err(err) = parser.found_invalid() {
        stderr.write_all(err.as_bytes()).try(&mut stderr);
        stderr.flush().try(&mut stderr);
        return;
    }

    // run the main part
    if parser.args.is_empty() {
        let stdin = io::stdin();
        let stdin = stdin.lock();
        tail(stdin, stdout, &mut stderr, &parser).try(&mut stderr);
    } else if parser.args.len() == 1 {
        let file = fs::File::open(&parser.args[0]).try(&mut stderr);
        tail(file, stdout, &mut stderr, &parser).try(&mut stderr);
    } else {
        for path in &parser.args {
            let file = fs::File::open(&path).try(&mut stderr);
            stdout.write(b"==> ").try(&mut stderr);
            stdout.write(path.as_bytes()).try(&mut stderr);
            stdout.writeln(b" <==").try(&mut stderr);
            tail(file, &mut stdout, &mut stderr, &parser).try(&mut stderr);
        }
    }
}
<|endoftext|>


<commit_before>use std::ops::{Add, Mul, Neg, Sub};
use dsl::LpExpression::*;
use dsl::{Constraint, LpBinary, LpConstraint, LpContinuous, LpExpression, LpInteger};

/// Operations trait for any type implementing Into<LpExpressions> trait
pub trait LpOperations<T> where T: Into<LpExpression> {
    /// Less or equal binary syntax for LpExpression
    fn le(&self, lhs_expr: T) -> LpConstraint;
    /// Greater or equal binary syntax for LpExpression
    fn ge(&self, lhs_expr: T) -> LpConstraint;
    /// Equality binary syntax for LpExpression
    fn equal(&self, lhs_expr: T) -> LpConstraint;
}

/// Macro implementing Into<LpExpression> for types
macro_rules! to_into_expr {
    ($type_to:ty) => {
        impl Into<LpExpression> for $type_to {
            fn into(self) -> LpExpression {
                LitVal(self as f32)
            }
        }
    };
    ($type_to:ty, $wrapper: ident) => {
        impl Into<LpExpression> for $type_to {
            fn into(self) -> LpExpression {
                $wrapper(self)
            }
        }
        impl<'a> Into<LpExpression> for &'a $type_to {
            fn into(self) -> LpExpression {
                $wrapper(self.clone())
            }
        }
    };
}
to_into_expr!(f32);
to_into_expr!(i32);
to_into_expr!(LpBinary, ConsBin);
to_into_expr!(LpInteger, ConsInt);
to_into_expr!(LpContinuous, ConsCont);

/// Macro implementing binary operations for Into<LpExpression> or &Into<LpExpression>
macro_rules! operations_for_expr {
    ($trait_name: ident, $f_name: ident, $expr_type: ident) => {
        impl<T> $trait_name<T> for LpExpression
        where
            T: Into<LpExpression> + Clone,
        {
            type Output = LpExpression;
            fn $f_name(self, _rhs: T) -> LpExpression {
                $expr_type(Box::new(self.clone()), Box::new(_rhs.into()))
            }
        }
        impl<'a, T> $trait_name<T> for &'a LpExpression
        where
            T: Into<LpExpression> + Clone,
        {
            type Output = LpExpression;
            fn $f_name(self, _rhs: T) -> LpExpression {
                $expr_type(Box::new(self.clone()), Box::new(_rhs.into()))
            }
        }
    };
}

operations_for_expr!(Add, add, AddExpr);
operations_for_expr!(Sub, sub, SubExpr);
operations_for_expr!(Mul, mul, MulExpr);

/// Macro implementing a binary operation with a LpVars and a Into<Expression>
macro_rules! lpvars_operation_for_intoexpr {
    ($trait_name: ident, $f_name: ident, $lp_type: ident, $expr_type: ident, $cons_type: ident) => {
        impl<T> $trait_name<T> for $lp_type
        where
            T: Into<LpExpression> + Clone,
        {
            type Output = LpExpression;
            fn $f_name(self, _rhs: T) -> LpExpression {
                $expr_type(Box::new($cons_type(self.clone())), Box::new(_rhs.into())).normalize()
            }
        }
        impl<'a, T> $trait_name<T> for &'a $lp_type
        where
            T: Into<LpExpression> + Clone,
        {
            type Output = LpExpression;
            fn $f_name(self, _rhs: T) -> LpExpression {
                $expr_type(Box::new($cons_type(self.clone())), Box::new(_rhs.into())).normalize()
            }
        }
    };
}
lpvars_operation_for_intoexpr!(Mul, mul, LpInteger, MulExpr, ConsInt);
lpvars_operation_for_intoexpr!(Add, add, LpInteger, AddExpr, ConsInt);
lpvars_operation_for_intoexpr!(Sub, sub, LpInteger, SubExpr, ConsInt);

/// Macro implementing binary operations for a numeric type
macro_rules! numeric_operation_for_expr {
    ($num_type: ty, $trait_name: ident, $f_name: ident, $type_expr: ident) => {
        impl $trait_name<LpExpression> for $num_type {
            type Output = LpExpression;
            fn $f_name(self, _rhs: LpExpression) -> LpExpression {
                $type_expr(Box::new(LitVal(self as f32)), Box::new(_rhs))
            }
        }
        impl<'a> $trait_name<&'a LpExpression> for $num_type {
            type Output = LpExpression;
            fn $f_name(self, _rhs: &'a LpExpression) -> LpExpression {
                $type_expr(Box::new(LitVal(self as f32)), Box::new(_rhs.clone()))
            }
        }
    };
}
/// Macro implementing add, mul and sub for a specific numeric type
macro_rules! numeric_all_ops_for_expr {
    ($num_type: ty) => {
        numeric_operation_for_expr!($num_type, Add, add, AddExpr);
        numeric_operation_for_expr!($num_type, Mul, mul, MulExpr);
        numeric_operation_for_expr!($num_type, Sub, sub, SubExpr);
    };
}
numeric_all_ops_for_expr!(f32);
numeric_all_ops_for_expr!(i32);

/// &LpExpression to LpExpression
impl<'a> Into<LpExpression> for &'a LpExpression {
    fn into(self) -> LpExpression {
        self.clone()
    }
}

/// Implementing LpOperations trait for any Into<LpExpression>
impl<T: Into<LpExpression> + Clone, U> LpOperations<T> for U where U: Into<LpExpression> + Clone {
    fn le(&self, lhs_expr: T) -> LpConstraint {
        LpConstraint(
            self.clone().into(),
            Constraint::LessOrEqual,
            lhs_expr.clone().into(),
        )
        .generalize()
    }
    fn ge(&self, lhs_expr: T) -> LpConstraint {
        LpConstraint(
            self.clone().into(),
            Constraint::GreaterOrEqual,
            lhs_expr.clone().into(),
        )
        .generalize()
    }
    fn equal(&self, lhs_expr: T) -> LpConstraint {
        LpConstraint(
            self.clone().into(),
            Constraint::Equal,
            lhs_expr.clone().into(),
        )
        .generalize()
    }
}

impl<'a> Neg for &'a LpExpression {
    type Output = LpExpression;
    fn neg(self) -> LpExpression {
        MulExpr(Box::new(LitVal(-1.0)), Box::new(self.clone()))
    }
}
macro_rules! neg_operation_for_lpvars {
    ($lp_var_type: ty, $constr_expr: ident) => {
        impl<'a> Neg for &'a $lp_var_type {
            type Output = LpExpression;
            fn neg(self) -> LpExpression {
                MulExpr(Box::new(LitVal(-1.0)), Box::new($constr_expr(self.clone())))
            }
        }
    };
}
neg_operation_for_lpvars!(LpInteger, ConsInt);
neg_operation_for_lpvars!(LpContinuous, ConsCont);
neg_operation_for_lpvars!(LpBinary, ConsBin);

/// Macro implementing binary operations for a numeric type
macro_rules! numeric_operation_for_lpvars {
    ($num_type: ty, $trait_name: ident, $f_name: ident, $type_expr: ident, $lp_type: ty, $cons_expr: ident) => {
        impl $trait_name<$lp_type> for $num_type {
            type Output = LpExpression;
            fn $f_name(self, _rhs: $lp_type) -> LpExpression {
                $type_expr(Box::new(LitVal(self as f32)), Box::new($cons_expr(_rhs)))
            }
        }
        impl<'a> $trait_name<&'a $lp_type> for $num_type {
            type Output = LpExpression;
            fn $f_name(self, _rhs: &'a $lp_type) -> LpExpression {
                $type_expr(
                    Box::new(LitVal(self as f32)),
                    Box::new($cons_expr(_rhs.clone())),
                )
            }
        }
    };
}

/// Macro implementing add, mul and sub for a specific numeric type
macro_rules! numeric_all_ops_for_lpvars {
    ($num_type: ty) => {
        numeric_operation_for_lpvars!($num_type, Add, add, AddExpr, LpInteger, ConsInt);
        numeric_operation_for_lpvars!($num_type, Add, add, AddExpr, LpBinary, ConsBin);
        numeric_operation_for_lpvars!($num_type, Add, add, AddExpr, LpContinuous, ConsCont);
        numeric_operation_for_lpvars!($num_type, Mul, mul, MulExpr, LpInteger, ConsInt);
        numeric_operation_for_lpvars!($num_type, Mul, mul, MulExpr, LpBinary, ConsBin);
        numeric_operation_for_lpvars!($num_type, Mul, mul, MulExpr, LpContinuous, ConsCont);
        numeric_operation_for_lpvars!($num_type, Sub, sub, SubExpr, LpInteger, ConsInt);
        numeric_operation_for_lpvars!($num_type, Sub, sub, SubExpr, LpBinary, ConsBin);
        numeric_operation_for_lpvars!($num_type, Sub, sub, SubExpr, LpContinuous, ConsCont);
    };
}
numeric_all_ops_for_lpvars!(i32);
numeric_all_ops_for_lpvars!(f32);
<commit_msg>adding add, mult, sub operations for binary and continuous<commit_after>use std::ops::{Add, Mul, Neg, Sub};
use dsl::LpExpression::*;
use dsl::{Constraint, LpBinary, LpConstraint, LpContinuous, LpExpression, LpInteger};

/// Operations trait for any type implementing Into<LpExpressions> trait
pub trait LpOperations<T> where T: Into<LpExpression> {
    /// Less or equal binary syntax for LpExpression
    fn le(&self, lhs_expr: T) -> LpConstraint;
    /// Greater or equal binary syntax for LpExpression
    fn ge(&self, lhs_expr: T) -> LpConstraint;
    /// Equality binary syntax for LpExpression
    fn equal(&self, lhs_expr: T) -> LpConstraint;
}

/// Macro implementing Into<LpExpression> for types
macro_rules! to_into_expr {
    ($type_to:ty) => {
        impl Into<LpExpression> for $type_to {
            fn into(self) -> LpExpression {
                LitVal(self as f32)
            }
        }
    };
    ($type_to:ty, $wrapper: ident) => {
        impl Into<LpExpression> for $type_to {
            fn into(self) -> LpExpression {
                $wrapper(self)
            }
        }
        impl<'a> Into<LpExpression> for &'a $type_to {
            fn into(self) -> LpExpression {
                $wrapper(self.clone())
            }
        }
    };
}
to_into_expr!(f32);
to_into_expr!(i32);
to_into_expr!(LpBinary, ConsBin);
to_into_expr!(LpInteger, ConsInt);
to_into_expr!(LpContinuous, ConsCont);

/// Macro implementing binary operations for Into<LpExpression> or &Into<LpExpression>
macro_rules! operations_for_expr {
    ($trait_name: ident, $f_name: ident, $expr_type: ident) => {
        impl<T> $trait_name<T> for LpExpression
        where
            T: Into<LpExpression> + Clone,
        {
            type Output = LpExpression;
            fn $f_name(self, _rhs: T) -> LpExpression {
                $expr_type(Box::new(self.clone()), Box::new(_rhs.into()))
            }
        }
        impl<'a, T> $trait_name<T> for &'a LpExpression
        where
            T: Into<LpExpression> + Clone,
        {
            type Output = LpExpression;
            fn $f_name(self, _rhs: T) -> LpExpression {
                $expr_type(Box::new(self.clone()), Box::new(_rhs.into()))
            }
        }
    };
}

operations_for_expr!(Add, add, AddExpr);
operations_for_expr!(Sub, sub, SubExpr);
operations_for_expr!(Mul, mul, MulExpr);

/// Macro implementing a binary operation with a LpVars and a Into<Expression>
macro_rules! lpvars_operation_for_intoexpr {
    ($trait_name: ident, $f_name: ident, $lp_type: ident, $expr_type: ident, $cons_type: ident) => {
        impl<T> $trait_name<T> for $lp_type
        where
            T: Into<LpExpression> + Clone,
        {
            type Output = LpExpression;
            fn $f_name(self, _rhs: T) -> LpExpression {
                $expr_type(Box::new($cons_type(self.clone())), Box::new(_rhs.into())).normalize()
            }
        }
        impl<'a, T> $trait_name<T> for &'a $lp_type
        where
            T: Into<LpExpression> + Clone,
        {
            type Output = LpExpression;
            fn $f_name(self, _rhs: T) -> LpExpression {
                $expr_type(Box::new($cons_type(self.clone())), Box::new(_rhs.into())).normalize()
            }
        }
    };
}

lpvars_operation_for_intoexpr!(Mul, mul, LpBinary, MulExpr, ConsBin);
lpvars_operation_for_intoexpr!(Add, add, LpBinary, AddExpr, ConsBin);
lpvars_operation_for_intoexpr!(Sub, sub, LpBinary, SubExpr, ConsBin);
lpvars_operation_for_intoexpr!(Mul, mul, LpInteger, MulExpr, ConsInt);
lpvars_operation_for_intoexpr!(Add, add, LpInteger, AddExpr, ConsInt);
lpvars_operation_for_intoexpr!(Sub, sub, LpInteger, SubExpr, ConsInt);
lpvars_operation_for_intoexpr!(Mul, mul, LpContinuous, MulExpr, ConsCont);
lpvars_operation_for_intoexpr!(Add, add, LpContinuous, AddExpr, ConsCont);
lpvars_operation_for_intoexpr!(Sub, sub, LpContinuous, SubExpr, ConsCont);

/// Macro implementing binary operations for a numeric type
macro_rules! numeric_operation_for_expr {
    ($num_type: ty, $trait_name: ident, $f_name: ident, $type_expr: ident) => {
        impl $trait_name<LpExpression> for $num_type {
            type Output = LpExpression;
            fn $f_name(self, _rhs: LpExpression) -> LpExpression {
                $type_expr(Box::new(LitVal(self as f32)), Box::new(_rhs))
            }
        }
        impl<'a> $trait_name<&'a LpExpression> for $num_type {
            type Output = LpExpression;
            fn $f_name(self, _rhs: &'a LpExpression) -> LpExpression {
                $type_expr(Box::new(LitVal(self as f32)), Box::new(_rhs.clone()))
            }
        }
    };
}
/// Macro implementing add, mul and sub for a specific numeric type
macro_rules! numeric_all_ops_for_expr {
    ($num_type: ty) => {
        numeric_operation_for_expr!($num_type, Add, add, AddExpr);
        numeric_operation_for_expr!($num_type, Mul, mul, MulExpr);
        numeric_operation_for_expr!($num_type, Sub, sub, SubExpr);
    };
}
numeric_all_ops_for_expr!(f32);
numeric_all_ops_for_expr!(i32);

/// &LpExpression to LpExpression
impl<'a> Into<LpExpression> for &'a LpExpression {
    fn into(self) -> LpExpression {
        self.clone()
    }
}

/// Implementing LpOperations trait for any Into<LpExpression>
impl<T: Into<LpExpression> + Clone, U> LpOperations<T> for U where U: Into<LpExpression> + Clone {
    fn le(&self, lhs_expr: T) -> LpConstraint {
        LpConstraint(
            self.clone().into(),
            Constraint::LessOrEqual,
            lhs_expr.clone().into(),
        )
        .generalize()
    }
    fn ge(&self, lhs_expr: T) -> LpConstraint {
        LpConstraint(
            self.clone().into(),
            Constraint::GreaterOrEqual,
            lhs_expr.clone().into(),
        )
        .generalize()
    }
    fn equal(&self, lhs_expr: T) -> LpConstraint {
        LpConstraint(
            self.clone().into(),
            Constraint::Equal,
            lhs_expr.clone().into(),
        )
        .generalize()
    }
}

impl<'a> Neg for &'a LpExpression {
    type Output = LpExpression;
    fn neg(self) -> LpExpression {
        MulExpr(Box::new(LitVal(-1.0)), Box::new(self.clone()))
    }
}
macro_rules! neg_operation_for_lpvars {
    ($lp_var_type: ty, $constr_expr: ident) => {
        impl<'a> Neg for &'a $lp_var_type {
            type Output = LpExpression;
            fn neg(self) -> LpExpression {
                MulExpr(Box::new(LitVal(-1.0)), Box::new($constr_expr(self.clone())))
            }
        }
    };
}
neg_operation_for_lpvars!(LpInteger, ConsInt);
neg_operation_for_lpvars!(LpContinuous, ConsCont);
neg_operation_for_lpvars!(LpBinary, ConsBin);

/// Macro implementing binary operations for a numeric type
macro_rules! numeric_operation_for_lpvars {
    ($num_type: ty, $trait_name: ident, $f_name: ident, $type_expr: ident, $lp_type: ty, $cons_expr: ident) => {
        impl $trait_name<$lp_type> for $num_type {
            type Output = LpExpression;
            fn $f_name(self, _rhs: $lp_type) -> LpExpression {
                $type_expr(Box::new(LitVal(self as f32)), Box::new($cons_expr(_rhs)))
            }
        }
        impl<'a> $trait_name<&'a $lp_type> for $num_type {
            type Output = LpExpression;
            fn $f_name(self, _rhs: &'a $lp_type) -> LpExpression {
                $type_expr(
                    Box::new(LitVal(self as f32)),
                    Box::new($cons_expr(_rhs.clone())),
                )
            }
        }
    };
}

/// Macro implementing add, mul and sub for a specific numeric type
macro_rules! numeric_all_ops_for_lpvars {
    ($num_type: ty) => {
        numeric_operation_for_lpvars!($num_type, Add, add, AddExpr, LpInteger, ConsInt);
        numeric_operation_for_lpvars!($num_type, Add, add, AddExpr, LpBinary, ConsBin);
        numeric_operation_for_lpvars!($num_type, Add, add, AddExpr, LpContinuous, ConsCont);
        numeric_operation_for_lpvars!($num_type, Mul, mul, MulExpr, LpInteger, ConsInt);
        numeric_operation_for_lpvars!($num_type, Mul, mul, MulExpr, LpBinary, ConsBin);
        numeric_operation_for_lpvars!($num_type, Mul, mul, MulExpr, LpContinuous, ConsCont);
        numeric_operation_for_lpvars!($num_type, Sub, sub, SubExpr, LpInteger, ConsInt);
        numeric_operation_for_lpvars!($num_type, Sub, sub, SubExpr, LpBinary, ConsBin);
        numeric_operation_for_lpvars!($num_type, Sub, sub, SubExpr, LpContinuous, ConsCont);
    };
}
numeric_all_ops_for_lpvars!(i32);
numeric_all_ops_for_lpvars!(f32);
<|endoftext|>


<commit_before>use super::ease::Easing;
/// This struct captures quadratic easing functions
pub struct Quad;

impl Easing for Quad {
    fn ease_in(t: f32, b: f32, c: f32, d: f32) -> f32 {
        let inner_t = t / d;
        c * inner_t.powi(2) + b
    }

    fn ease_out(t: f32, b: f32, c: f32, d: f32) -> f32 {
        let inner_t = t / d;
        -c * inner_t * (inner_t - 2.0) + b
    }

    fn ease_in_out(t: f32, b: f32, c: f32, d: f32) -> f32 {
        let inner_t = t / (d / 2.0);
        if inner_t < 1.0 {
            return (c / 2.0 * (inner_t.powi(2))) + b;
        }
        let temp = inner_t - 1.0;
        return -c / 2.0 * (((inner_t - 2.0) * (temp)) - 1.0) + b;
    }
}

#[cfg(test)]
mod test {
    #[allow(unused_imports)]
    use functions::ease::Easing;
    #[test]
    fn ease_in() {
        assert_relative_eq!(super::Quad::ease_in(1.0, 2.0, 3.0, 4.0), 2.187500);
    }

    #[test]
    fn ease_out() {
        assert_relative_eq!(super::Quad::ease_out(1.0, 2.0, 3.0, 4.0), 3.312500);
    }

    #[test]
    fn ease_in_out() {
        assert_relative_eq!(super::Quad::ease_in_out(1.0, 2.0, 3.0, 4.0), 2.37500);
        assert_relative_eq!(super::Quad::ease_in_out(51.0, 1.0, 100.0, 100.0), 51.979999);
    }

}
<commit_msg>Fix the quad_ease_in_out function<commit_after>use super::ease::Easing;

/// This struct captures quadratic easing functions
pub struct Quad;

impl Easing for Quad {
    fn ease_in(t: f32, b: f32, c: f32, d: f32) -> f32 {
        let inner_t = t / d;
        c * inner_t.powi(2) + b
    }

    fn ease_out(t: f32, b: f32, c: f32, d: f32) -> f32 {
        let inner_t = t / d;
        -c * inner_t * (inner_t - 2.0) + b
    }

    fn ease_in_out(t: f32, b: f32, c: f32, d: f32) -> f32 {
        let mut t = t / (d / 2.0);
        if t < 1.0 {
            c / 2.0 * t * t + b
        }
        else {
            t -= 1.0;
            -c / 2.0 * (t * (t - 2.0) - 1.0) + b
        }
    }
}

#[cfg(test)]
mod test {
    #[allow(unused_imports)]
    use functions::ease::Easing;
    #[test]
    fn ease_in() {
        assert_relative_eq!(super::Quad::ease_in(1.0, 2.0, 3.0, 4.0), 2.187500);
    }

    #[test]
    fn ease_out() {
        assert_relative_eq!(super::Quad::ease_out(1.0, 2.0, 3.0, 4.0), 3.312500);
    }

    #[test]
    fn ease_in_out() {
        assert_relative_eq!(super::Quad::ease_in_out(1.0, 2.0, 3.0, 4.0), 2.37500);
        assert_relative_eq!(super::Quad::ease_in_out(51.0, 1.0, 100.0, 100.0), 52.98);
    }

}
<|endoftext|>


<commit_before>//! Handle http requests
//!
//! This implementation is stolen from <https://github.com/getsentry/sentry-cli> and adapted for
//! gerrit server. Thanks Armin!
//!
//! **NOTICE**: The complete call request could be handled with hyper or something like that. This
//! could beused instead the curl-approach.

use curl;
use error::GGRResult;
use std::cell::RefCell;
use std::cell::RefMut;
use std::fmt;
use std::io::Read;
use std::io::Write;
use url;

/// helper function for Request without body content and with content
fn send_req<W: Write>(handle: &mut curl::easy::Easy,
                     out: &mut W,
                     body: Option<Vec<u8>>)
    -> GGRResult<(u32, Vec<String>)> {
        match body {
            Some(body) => {
                let mut body = &body[..];
                try!(handle.upload(true));
                try!(handle.in_filesize(body.len() as u64));
                handle_req(handle, out, &mut |buf| body.read(buf).unwrap_or(0))
            },
            None => {
                handle_req(handle, out, &mut |_| 0)
            }
        }
}

/// Does the real send
fn handle_req<W: Write>(handle: &mut curl::easy::Easy,
                       out: &mut W,
                       read: &mut FnMut(&mut [u8]) -> usize)
    -> GGRResult<(u32, Vec<String>)> {
        let mut headers = Vec::new();

        {
            let mut handle = handle.transfer();

            try!(handle.read_function(|buf| Ok(read(buf))));
            try!{handle.write_function(|data| {
                Ok(match out.write_all(data) {
                    Ok(_) => data.len(),
                    Err(_) => 0,
                })
            })};

            try!{handle.header_function(|data| {
                headers.push(String::from_utf8_lossy(data).into_owned());
                true
            })};

            try!(handle.perform());
        }

        Ok((try!{handle.response_code()}, headers))
}

/// HTTP methods
pub enum CallMethod {
    /// Identify a GET call
    Get,
}

/// Transform CallMethod type to String
impl fmt::Display for CallMethod {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CallMethod::Get => write!(f, "GET"),
        }
    }
}

/// Represents a HTTP request
///
/// For usage we fill the CallRequest with an header and a body. Later we call via `handler` the
/// gerrit server.
pub struct CallRequest<'a> {
    handle: RefMut<'a, curl::easy::Easy>,
    headers: curl::easy::List,
    body: Option<Vec<u8>>,
}

impl<'a> CallRequest<'a> {
    /// creates new instance of [`CallRequest`] with a curl-handler, the HTTP method and the url
    /// endpoint
    pub fn new(mut handle: RefMut<'a, curl::easy::Easy>,
               method: CallMethod,
               url: String)
        -> GGRResult<CallRequest<'a>> {
            let mut headers = curl::easy::List::new();

            // we only want compact json data
            let _ = headers.append("Accept: application/json");

            match method {
                CallMethod::Get => try!{handle.get(true)},
            };

            try!(handle.url(&url));

            Ok(CallRequest {
                handle: handle,
                headers: headers,
                body: None,
            })
    }

    /// helper function to handle a request, write the returned content to a `Write` capabel object
    /// and returns a `CallResponse`.
    fn send_into<W:Write>(mut self, out: &mut W) -> GGRResult<CallResponse> {
        try!(self.handle.http_headers(self.headers));

        let (status, headers) = try!(send_req(&mut self.handle, out, self.body));

        Ok(CallResponse {
            status: status,
            headers: headers,
            body: None,
        })
    }

    /// Does the send function.
    ///
    /// **NOTICE**: The first 4 characters are cutted from the returned content. We want only json
    /// data which has a prevention against XSSI attacks. More here:
    /// <https://gerrit-documentation.storage.googleapis.com/Documentation/2.12.3/rest-api.html#output>
    pub fn send(self) -> GGRResult<CallResponse> {
        let mut out = Vec::new();
        let mut rv = try!(self.send_into(&mut out));

        /* cut first 4 bytes from output stream */
        if out.starts_with(b")]}'") {
            out = out[4..].into();
        }

        rv.body = Some(out);
        Ok(rv)
    }
}

/// Representation of a Response
#[derive(Debug)]
pub struct CallResponse {
    /// http return status
    pub status: u32,
    /// header of http response
    pub headers: Vec<String>,
    /// the content
    pub body: Option<Vec<u8>>,
}

/// Abstraction of a HTTP call
pub struct Call {
    url: url::Url,
    handle: RefCell<curl::easy::Easy>,
}

impl Call {
    /// Creates a new http call with the base address of a gerrit server
    pub fn new(url: String) -> Call {
        Call {
            url: url::Url::parse(&url).unwrap(),
            handle: RefCell::new(curl::easy::Easy::new()),
        }
    }

    /// Creates a `CallRequest` object with a specific HTTP method and the complete url
    fn request(&self, method:CallMethod, url:String) -> GGRResult<CallRequest> {
        let handle = self.handle.borrow_mut();

        CallRequest::new(handle, method, url)
    }

    /// Does a `GET` Request an returns a CallResponse. Only path and querystring is needed. The
    /// base url is setup via [`Call::new()`] function.
    ///
    /// [`Call::new()`]: ./struct.Call.html#method.new
    pub fn get(&self, path: &str, querystring: String) -> GGRResult<CallResponse> {
        let mut sendurl = self.url.clone();
        sendurl.set_path(path);
        sendurl.set_query(Some(&querystring));

        let e = try!(self.request(CallMethod::Get, sendurl.into_string()));

        e.send()
    }
}
<commit_msg>call: small: improve documentation with distinguished struct names<commit_after>//! Handle http requests
//!
//! This implementation is stolen from <https://github.com/getsentry/sentry-cli> and adapted for
//! gerrit server. Thanks Armin!
//!
//! **NOTICE**: The complete call request could be handled with hyper or something like that. This
//! could beused instead the curl-approach.

use curl;
use error::GGRResult;
use std::cell::RefCell;
use std::cell::RefMut;
use std::fmt;
use std::io::Read;
use std::io::Write;
use url;

/// helper function for Request without body content and with content
fn send_req<W: Write>(handle: &mut curl::easy::Easy,
                     out: &mut W,
                     body: Option<Vec<u8>>)
    -> GGRResult<(u32, Vec<String>)> {
        match body {
            Some(body) => {
                let mut body = &body[..];
                try!(handle.upload(true));
                try!(handle.in_filesize(body.len() as u64));
                handle_req(handle, out, &mut |buf| body.read(buf).unwrap_or(0))
            },
            None => {
                handle_req(handle, out, &mut |_| 0)
            }
        }
}

/// Does the real send
fn handle_req<W: Write>(handle: &mut curl::easy::Easy,
                       out: &mut W,
                       read: &mut FnMut(&mut [u8]) -> usize)
    -> GGRResult<(u32, Vec<String>)> {
        let mut headers = Vec::new();

        {
            let mut handle = handle.transfer();

            try!(handle.read_function(|buf| Ok(read(buf))));
            try!{handle.write_function(|data| {
                Ok(match out.write_all(data) {
                    Ok(_) => data.len(),
                    Err(_) => 0,
                })
            })};

            try!{handle.header_function(|data| {
                headers.push(String::from_utf8_lossy(data).into_owned());
                true
            })};

            try!(handle.perform());
        }

        Ok((try!{handle.response_code()}, headers))
}

/// HTTP methods
pub enum CallMethod {
    /// Identify a GET call
    Get,
}

/// Transform `CallMethod` type to String
impl fmt::Display for CallMethod {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CallMethod::Get => write!(f, "GET"),
        }
    }
}

/// Represents a HTTP request
///
/// For usage we fill the `CallRequest` with an header and a body. Later we call via `handler` the
/// gerrit server.
pub struct CallRequest<'a> {
    handle: RefMut<'a, curl::easy::Easy>,
    headers: curl::easy::List,
    body: Option<Vec<u8>>,
}

impl<'a> CallRequest<'a> {
    /// creates new instance of [`CallRequest`] with a curl-handler, the HTTP method and the url
    /// endpoint
    pub fn new(mut handle: RefMut<'a, curl::easy::Easy>,
               method: CallMethod,
               url: String)
        -> GGRResult<CallRequest<'a>> {
            let mut headers = curl::easy::List::new();

            // we only want compact json data
            let _ = headers.append("Accept: application/json");

            match method {
                CallMethod::Get => try!{handle.get(true)},
            };

            try!(handle.url(&url));

            Ok(CallRequest {
                handle: handle,
                headers: headers,
                body: None,
            })
    }

    /// helper function to handle a request, write the returned content to a `Write` capabel object
    /// and returns a `CallResponse`.
    fn send_into<W:Write>(mut self, out: &mut W) -> GGRResult<CallResponse> {
        try!(self.handle.http_headers(self.headers));

        let (status, headers) = try!(send_req(&mut self.handle, out, self.body));

        Ok(CallResponse {
            status: status,
            headers: headers,
            body: None,
        })
    }

    /// Does the send function.
    ///
    /// **NOTICE**: The first 4 characters are cutted from the returned content. We want only json
    /// data which has a prevention against XSSI attacks. More here:
    /// <https://gerrit-documentation.storage.googleapis.com/Documentation/2.12.3/rest-api.html#output>
    pub fn send(self) -> GGRResult<CallResponse> {
        let mut out = Vec::new();
        let mut rv = try!(self.send_into(&mut out));

        /* cut first 4 bytes from output stream */
        if out.starts_with(b")]}'") {
            out = out[4..].into();
        }

        rv.body = Some(out);
        Ok(rv)
    }
}

/// Representation of a Response
#[derive(Debug)]
pub struct CallResponse {
    /// http return status
    pub status: u32,
    /// header of http response
    pub headers: Vec<String>,
    /// the content
    pub body: Option<Vec<u8>>,
}

/// Abstraction of a HTTP call
pub struct Call {
    url: url::Url,
    handle: RefCell<curl::easy::Easy>,
}

impl Call {
    /// Creates a new http call with the base address of a gerrit server
    pub fn new(url: String) -> Call {
        Call {
            url: url::Url::parse(&url).unwrap(),
            handle: RefCell::new(curl::easy::Easy::new()),
        }
    }

    /// Creates a `CallRequest` object with a specific HTTP method and the complete url
    fn request(&self, method:CallMethod, url:String) -> GGRResult<CallRequest> {
        let handle = self.handle.borrow_mut();

        CallRequest::new(handle, method, url)
    }

    /// Does a `GET` Request an returns a CallResponse. Only path and querystring is needed. The
    /// base url is setup via [`Call::new()`] function.
    ///
    /// [`Call::new()`]: ./struct.Call.html#method.new
    pub fn get(&self, path: &str, querystring: String) -> GGRResult<CallResponse> {
        let mut sendurl = self.url.clone();
        sendurl.set_path(path);
        sendurl.set_query(Some(&querystring));

        let e = try!(self.request(CallMethod::Get, sendurl.into_string()));

        e.send()
    }
}
<|endoftext|>


<commit_before>// NB: transitionary, de-mode-ing.
#[forbid(deprecated_mode)];
#[forbid(deprecated_pattern)];

/*!
 * A type representing values that may be computed concurrently and
 * operations for working with them.
 *
 * # Example
 *
 * ~~~
 * let delayed_fib = future::spawn {|| fib(5000) };
 * make_a_sandwich();
 * io::println(fmt!("fib(5000) = %?", delayed_fib.get()))
 * ~~~
 */

use either::Either;
use pipes::recv;
use unsafe::copy_lifetime;

export Future;
export extensions;
export from_value;
export from_port;
export from_fn;
export get;
export with;
export spawn;

// for task.rs
export future_pipe;

#[doc = "The future type"]
struct Future<A> {
    /*priv*/ mut state: FutureState<A>,

    // FIXME(#2829) -- futures should not be copyable, because they close
    // over fn~'s that have pipes and so forth within!
    drop {}
}

priv enum FutureState<A> {
    Pending(fn~() -> A),
    Evaluating,
    Forced(~A)
}

/// Methods on the `future` type
impl<A:Copy> Future<A> {
    fn get() -> A {
        //! Get the value of the future

        get(&self)
    }
}

impl<A> Future<A> {
    fn get_ref(&self) -> &self/A {
        get_ref(self)
    }

    fn with<B>(blk: fn((&A)) -> B) -> B {
        //! Work with the value without copying it

        with(&self, blk)
    }
}

fn from_value<A>(+val: A) -> Future<A> {
    /*!
     * Create a future from a value
     *
     * The value is immediately available and calling `get` later will
     * not block.
     */

    Future {state: Forced(~(move val))}
}

fn from_port<A:Send>(+port: future_pipe::client::waiting<A>) -> Future<A> {
    /*!
     * Create a future from a port
     *
     * The first time that the value is requested the task will block
     * waiting for the result to be received on the port.
     */

    let port = ~mut Some(move port);
    do from_fn |move port| {
        let mut port_ = None;
        port_ <-> *port;
        let port = option::unwrap(port_);
        match recv(move port) {
            future_pipe::completed(move data) => move data
        }
    }
}

fn from_fn<A>(+f: ~fn() -> A) -> Future<A> {
    /*!
     * Create a future from a function.
     *
     * The first time that the value is requested it will be retreived by
     * calling the function.  Note that this function is a local
     * function. It is not spawned into another task.
     */

    Future {state: Pending(move f)}
}

fn spawn<A:Send>(+blk: fn~() -> A) -> Future<A> {
    /*!
     * Create a future from a unique closure.
     *
     * The closure will be run in a new task and its result used as the
     * value of the future.
     */

    from_port(pipes::spawn_service_recv(future_pipe::init, |move blk, ch| {
        future_pipe::server::completed(move ch, blk());
    }))
}

fn get_ref<A>(future: &r/Future<A>) -> &r/A {
    /*!
     * Executes the future's closure and then returns a borrowed
     * pointer to the result.  The borrowed pointer lasts as long as
     * the future.
     */

    // The unsafety here is to hide the aliases from borrowck, which
    // would otherwise be concerned that someone might reassign
    // `future.state` and cause the value of the future to be freed.
    // But *we* know that once `future.state` is `Forced()` it will
    // never become "unforced"---so we can safely return a pointer
    // into the interior of the Forced() variant which will last as
    // long as the future itself.

    match future.state {
      Forced(ref v) => { // v here has type &A, but with a shorter lifetime.
        return unsafe{ copy_lifetime(future, &**v) }; // ...extend it.
      }
      Evaluating => {
        fail ~"Recursive forcing of future!";
      }
      Pending(_) => {}
    }

    let mut state = Evaluating;
    state <-> future.state;
    match move state {
      Forced(_) | Evaluating => {
        fail ~"Logic error.";
      }
      Pending(move f) => {
        future.state = Forced(~f());
        return get_ref(future);
      }
    }
}

fn get<A:Copy>(future: &Future<A>) -> A {
    //! Get the value of the future

    *get_ref(future)
}

fn with<A,B>(future: &Future<A>, blk: fn((&A)) -> B) -> B {
    //! Work with the value without copying it

    blk(get_ref(future))
}

proto! future_pipe (
    waiting:recv<T:Send> {
        completed(T) -> !
    }
)

#[allow(non_implicitly_copyable_typarams)]
mod test {
    #[test]
    fn test_from_value() {
        let f = from_value(~"snail");
        assert get(&f) == ~"snail";
    }

    #[test]
    fn test_from_port() {
        let (po, ch) = future_pipe::init();
        future_pipe::server::completed(ch, ~"whale");
        let f = from_port(po);
        assert get(&f) == ~"whale";
    }

    #[test]
    fn test_from_fn() {
        let f = from_fn(|| ~"brail");
        assert get(&f) == ~"brail";
    }

    #[test]
    fn test_interface_get() {
        let f = from_value(~"fail");
        assert f.get() == ~"fail";
    }

    #[test]
    fn test_with() {
        let f = from_value(~"nail");
        assert with(&f, |v| copy *v) == ~"nail";
    }

    #[test]
    fn test_get_ref_method() {
        let f = from_value(22);
        assert *f.get_ref() == 22;
    }

    #[test]
    fn test_get_ref_fn() {
        let f = from_value(22);
        assert *get_ref(&f) == 22;
    }

    #[test]
    fn test_interface_with() {
        let f = from_value(~"kale");
        assert f.with(|v| copy *v) == ~"kale";
    }

    #[test]
    fn test_spawn() {
        let f = spawn(|| ~"bale");
        assert get(&f) == ~"bale";
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(target_os = "win32"))]
    fn test_futurefail() {
        let f = spawn(|| fail);
        let _x: ~str = get(&f);
    }

    #[test]
    fn test_sendable_future() {
        let expected = ~"schlorf";
        let f = do spawn |copy expected| { expected };
        do task::spawn {
            let actual = get(&f);
            assert actual == expected;
        }
    }
}
<commit_msg>fix a implicitly copyable warning<commit_after>// NB: transitionary, de-mode-ing.
#[forbid(deprecated_mode)];
#[forbid(deprecated_pattern)];

/*!
 * A type representing values that may be computed concurrently and
 * operations for working with them.
 *
 * # Example
 *
 * ~~~
 * let delayed_fib = future::spawn {|| fib(5000) };
 * make_a_sandwich();
 * io::println(fmt!("fib(5000) = %?", delayed_fib.get()))
 * ~~~
 */

use either::Either;
use pipes::recv;
use unsafe::copy_lifetime;

export Future;
export extensions;
export from_value;
export from_port;
export from_fn;
export get;
export with;
export spawn;

// for task.rs
export future_pipe;

#[doc = "The future type"]
struct Future<A> {
    /*priv*/ mut state: FutureState<A>,

    // FIXME(#2829) -- futures should not be copyable, because they close
    // over fn~'s that have pipes and so forth within!
    drop {}
}

priv enum FutureState<A> {
    Pending(fn~() -> A),
    Evaluating,
    Forced(~A)
}

/// Methods on the `future` type
impl<A:Copy> Future<A> {
    fn get() -> A {
        //! Get the value of the future

        get(&self)
    }
}

impl<A> Future<A> {
    fn get_ref(&self) -> &self/A {
        get_ref(self)
    }

    fn with<B>(blk: fn((&A)) -> B) -> B {
        //! Work with the value without copying it

        with(&self, blk)
    }
}

fn from_value<A>(+val: A) -> Future<A> {
    /*!
     * Create a future from a value
     *
     * The value is immediately available and calling `get` later will
     * not block.
     */

    Future {state: Forced(~(move val))}
}

fn from_port<A:Send>(+port: future_pipe::client::waiting<A>) -> Future<A> {
    /*!
     * Create a future from a port
     *
     * The first time that the value is requested the task will block
     * waiting for the result to be received on the port.
     */

    let port = ~mut Some(move port);
    do from_fn |move port| {
        let mut port_ = None;
        port_ <-> *port;
        let port = option::unwrap(port_);
        match recv(move port) {
            future_pipe::completed(move data) => move data
        }
    }
}

fn from_fn<A>(+f: ~fn() -> A) -> Future<A> {
    /*!
     * Create a future from a function.
     *
     * The first time that the value is requested it will be retreived by
     * calling the function.  Note that this function is a local
     * function. It is not spawned into another task.
     */

    Future {state: Pending(move f)}
}

fn spawn<A:Send>(+blk: fn~() -> A) -> Future<A> {
    /*!
     * Create a future from a unique closure.
     *
     * The closure will be run in a new task and its result used as the
     * value of the future.
     */

    from_port(pipes::spawn_service_recv(future_pipe::init, |move blk, ch| {
        future_pipe::server::completed(move ch, blk());
    }))
}

fn get_ref<A>(future: &r/Future<A>) -> &r/A {
    /*!
     * Executes the future's closure and then returns a borrowed
     * pointer to the result.  The borrowed pointer lasts as long as
     * the future.
     */

    // The unsafety here is to hide the aliases from borrowck, which
    // would otherwise be concerned that someone might reassign
    // `future.state` and cause the value of the future to be freed.
    // But *we* know that once `future.state` is `Forced()` it will
    // never become "unforced"---so we can safely return a pointer
    // into the interior of the Forced() variant which will last as
    // long as the future itself.

    match future.state {
      Forced(ref v) => { // v here has type &A, but with a shorter lifetime.
        return unsafe{ copy_lifetime(future, &**v) }; // ...extend it.
      }
      Evaluating => {
        fail ~"Recursive forcing of future!";
      }
      Pending(_) => {}
    }

    let mut state = Evaluating;
    state <-> future.state;
    match move state {
      Forced(_) | Evaluating => {
        fail ~"Logic error.";
      }
      Pending(move f) => {
        future.state = Forced(~f());
        return get_ref(future);
      }
    }
}

fn get<A:Copy>(future: &Future<A>) -> A {
    //! Get the value of the future

    *get_ref(future)
}

fn with<A,B>(future: &Future<A>, blk: fn((&A)) -> B) -> B {
    //! Work with the value without copying it

    blk(get_ref(future))
}

proto! future_pipe (
    waiting:recv<T:Send> {
        completed(T) -> !
    }
)

#[allow(non_implicitly_copyable_typarams)]
mod test {
    #[test]
    fn test_from_value() {
        let f = from_value(~"snail");
        assert get(&f) == ~"snail";
    }

    #[test]
    fn test_from_port() {
        let (po, ch) = future_pipe::init();
        future_pipe::server::completed(ch, ~"whale");
        let f = from_port(po);
        assert get(&f) == ~"whale";
    }

    #[test]
    fn test_from_fn() {
        let f = from_fn(|| ~"brail");
        assert get(&f) == ~"brail";
    }

    #[test]
    fn test_interface_get() {
        let f = from_value(~"fail");
        assert f.get() == ~"fail";
    }

    #[test]
    fn test_with() {
        let f = from_value(~"nail");
        assert with(&f, |v| copy *v) == ~"nail";
    }

    #[test]
    fn test_get_ref_method() {
        let f = from_value(22);
        assert *f.get_ref() == 22;
    }

    #[test]
    fn test_get_ref_fn() {
        let f = from_value(22);
        assert *get_ref(&f) == 22;
    }

    #[test]
    fn test_interface_with() {
        let f = from_value(~"kale");
        assert f.with(|v| copy *v) == ~"kale";
    }

    #[test]
    fn test_spawn() {
        let f = spawn(|| ~"bale");
        assert get(&f) == ~"bale";
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(target_os = "win32"))]
    fn test_futurefail() {
        let f = spawn(|| fail);
        let _x: ~str = get(&f);
    }

    #[test]
    fn test_sendable_future() {
        let expected = ~"schlorf";
        let f = do spawn |copy expected| { copy expected };
        do task::spawn {
            let actual = get(&f);
            assert actual == expected;
        }
    }
}
<|endoftext|>