<commit_before>extern crate extra;
use extra::option::OptionalExt;
use extra::io::{fail, WriteExt};

use std::env::args;
use std::io::{self, Write};

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

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

    pub fn to_string(&self) -> String {
        self.to_str().to_owned()
    }
}

#[derive(Debug,  Clone)]
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,
            tokens_read,
        }
    }
}

pub trait OperatorFunctions {
    fn is_operator(self) -> bool;
    fn operator_type(self) -> Token;
}

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

    fn operator_type(self) -> Token {
        match self {
            '+' => Token::Plus,
            '-' => Token::Minus,
            '/' => Token::Divide,
            '*' => Token::Multiply,
            '^' => Token::Exponent,
            '(' => Token::OpenParen,
            ')' => Token::CloseParen,
            _   => fail("Invalid operator", &mut io::stderr())
        }
    }
}

pub fn tokenize(input: &str) -> Result<Vec<Token>, ParseError> {
    let mut tokens = Vec::with_capacity(input.len());

    // 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 = chars[current_pos];
        if c.is_digit(10) || c == '.' {
            let token_string = consume_number(&chars[current_pos..]);
            current_pos += token_string.len();
            tokens.push(Token::Number(token_string));
        } else if c.is_operator() {
            tokens.push(c.operator_type());
            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 {
    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 = t_expr(token_list)?;
    let mut index = t1.tokens_read;

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

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

    while index < token_list.len() {
        match token_list[index] {
            Token::Multiply => {
                let f2 = f_expr(&token_list[index+1..])?;
                f1.value *= f2.value;
                f1.tokens_read += f2.tokens_read + 1;
            }
            Token::Divide => {
                let f2 = 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;
                }
            }
            Token::Number(ref n) => return Err(ParseError::UnexpectedToken(n.clone(),"operator")),
            _ => break,
        }
        index = f1.tokens_read;
    }
    Ok(f1)
}

// Exponentiation
pub fn f_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    let mut g1 = g_expr(token_list)?;
    let mut index = g1.tokens_read;
    let token_len = token_list.len();
    while index < token_len {
        match token_list[index] {
            Token::Exponent => {
                let f = f_expr(&token_list[index+1..])?;
                g1.value = g1.value.powf(f.value);
                g1.tokens_read += f.tokens_read + 1;
            }
            Token::Number(ref n) => return Err(ParseError::UnexpectedToken(n.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::Number(ref n) => {
                n.parse::<f64>()
                 .map_err(|_| ParseError::InvalidNumber(n.clone()))
                 .and_then(|num| Ok(IntermediateResult::new(num, 1)))
            }
            Token::Minus => {
                if token_list.len() > 1 {
                    if let Token::Number(ref n) = token_list[1] {
                        n.parse::<f64>()
                         .map_err(|_| ParseError::InvalidNumber(n.clone()))
                         .and_then(|num| Ok(IntermediateResult::new(-1.0 * num, 2)))
                    } else {
                        Err(ParseError::UnexpectedToken(token_list[1].to_string(), "number"))
                    }
                } else {
                    Err(ParseError::UnexpectedEndOfInput)
                }
            }
            Token::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::CloseParen => Ok(IntermediateResult::new(ir.value, close_paren+1)),
                                _ => Err(ParseError::UnexpectedToken(token_list[close_paren].to_string(), ")")),
                            }
                        } else {
                            Err(ParseError::OtherError("no matching close parenthesis found.".to_owned()))
                        }
                    }
                    Err(e) => Err(e),
                }
            }
            _ => Err(ParseError::UnexpectedToken(token_list[0].to_string(), "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) => ["Error: Invalid number: ", s.as_str() ].concat(),
            ParseError::UnrecognizedToken(s) => ["Error: Unrecognized token: ", s.as_str()].concat(),
            ParseError::UnexpectedToken(found, expected) => ["Error: Unexpected token: expected [", expected, "] but found '", found.as_str(), "'"].concat(),
            ParseError::UnexpectedEndOfInput => "Error: Unexpected end of input.".to_owned(),
            ParseError::OtherError(s) => s,
        }
    }
}

fn main() {
    let args = args();
    let stdout = io::stdout();
    let mut stdout = stdout.lock();
    let mut stderr = io::stderr();
    if args.len() > 1 {
        let input: Vec<String> = args.skip(1).collect();
        stdout.writeln(eval(&input.join("")).as_bytes()).try(&mut stderr);
    } else {
        loop {
            print!("[]> ");
            stdout.flush().try(&mut stderr);
            let mut input = String::new();
            io::stdin().read_line(&mut input)
                       .try(&mut stderr);
            if input.is_empty() {
                break;
            } else {
                match input.trim() {
                    "" => (),
                    "exit" => break,
                    s => {
                        stdout.writeln(eval(s).as_bytes()).try(&mut stderr);
                        stdout.flush().try(&mut stderr);
                    },
                }
            }
        }
    }
}
<commit_msg>Clippy: implement Display instead of to_string()<commit_after>extern crate extra;
use extra::option::OptionalExt;
use extra::io::{fail, WriteExt};

use std::env::args;
use std::io::{self, Write};
use std::fmt;

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

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

impl fmt::Display for Token {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.to_str())
    }
}

#[derive(Debug,  Clone)]
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,
            tokens_read,
        }
    }
}

pub trait OperatorFunctions {
    fn is_operator(self) -> bool;
    fn operator_type(self) -> Token;
}

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

    fn operator_type(self) -> Token {
        match self {
            '+' => Token::Plus,
            '-' => Token::Minus,
            '/' => Token::Divide,
            '*' => Token::Multiply,
            '^' => Token::Exponent,
            '(' => Token::OpenParen,
            ')' => Token::CloseParen,
            _   => fail("Invalid operator", &mut io::stderr())
        }
    }
}

pub fn tokenize(input: &str) -> Result<Vec<Token>, ParseError> {
    let mut tokens = Vec::with_capacity(input.len());

    // 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 = chars[current_pos];
        if c.is_digit(10) || c == '.' {
            let token_string = consume_number(&chars[current_pos..]);
            current_pos += token_string.len();
            tokens.push(Token::Number(token_string));
        } else if c.is_operator() {
            tokens.push(c.operator_type());
            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 {
    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 = t_expr(token_list)?;
    let mut index = t1.tokens_read;

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

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

    while index < token_list.len() {
        match token_list[index] {
            Token::Multiply => {
                let f2 = f_expr(&token_list[index+1..])?;
                f1.value *= f2.value;
                f1.tokens_read += f2.tokens_read + 1;
            }
            Token::Divide => {
                let f2 = 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;
                }
            }
            Token::Number(ref n) => return Err(ParseError::UnexpectedToken(n.clone(),"operator")),
            _ => break,
        }
        index = f1.tokens_read;
    }
    Ok(f1)
}

// Exponentiation
pub fn f_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    let mut g1 = g_expr(token_list)?;
    let mut index = g1.tokens_read;
    let token_len = token_list.len();
    while index < token_len {
        match token_list[index] {
            Token::Exponent => {
                let f = f_expr(&token_list[index+1..])?;
                g1.value = g1.value.powf(f.value);
                g1.tokens_read += f.tokens_read + 1;
            }
            Token::Number(ref n) => return Err(ParseError::UnexpectedToken(n.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::Number(ref n) => {
                n.parse::<f64>()
                 .map_err(|_| ParseError::InvalidNumber(n.clone()))
                 .and_then(|num| Ok(IntermediateResult::new(num, 1)))
            }
            Token::Minus => {
                if token_list.len() > 1 {
                    if let Token::Number(ref n) = token_list[1] {
                        n.parse::<f64>()
                         .map_err(|_| ParseError::InvalidNumber(n.clone()))
                         .and_then(|num| Ok(IntermediateResult::new(-1.0 * num, 2)))
                    } else {
                        Err(ParseError::UnexpectedToken(token_list[1].to_string(), "number"))
                    }
                } else {
                    Err(ParseError::UnexpectedEndOfInput)
                }
            }
            Token::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::CloseParen => Ok(IntermediateResult::new(ir.value, close_paren+1)),
                                _ => Err(ParseError::UnexpectedToken(token_list[close_paren].to_string(), ")")),
                            }
                        } else {
                            Err(ParseError::OtherError("no matching close parenthesis found.".to_owned()))
                        }
                    }
                    Err(e) => Err(e),
                }
            }
            _ => Err(ParseError::UnexpectedToken(token_list[0].to_string(), "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) => ["Error: Invalid number: ", s.as_str() ].concat(),
            ParseError::UnrecognizedToken(s) => ["Error: Unrecognized token: ", s.as_str()].concat(),
            ParseError::UnexpectedToken(found, expected) => ["Error: Unexpected token: expected [", expected, "] but found '", found.as_str(), "'"].concat(),
            ParseError::UnexpectedEndOfInput => "Error: Unexpected end of input.".to_owned(),
            ParseError::OtherError(s) => s,
        }
    }
}

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


<commit_before>#![feature(plugin, custom_derive)]
#![plugin(rocket_codegen)]
#![cfg_attr(test, plugin(stainless))]
#![cfg_attr(feature = "dev", allow(unstable_features))]
#![cfg_attr(feature = "dev", plugin(clippy))]

extern crate rocket;
#[macro_use] extern crate rocket_contrib;
extern crate rand;
#[macro_use] extern crate lazy_static;
extern crate diesel;
extern crate r2d2;
extern crate r2d2_diesel;
extern crate plib;

pub mod paste_id;
pub mod paste_data;

use diesel::pg::PgConnection;
use diesel::prelude::*;
use plib::*;
use plib::models::Paste;
use r2d2::{Pool, PooledConnection, GetTimeout};
use r2d2_diesel::ConnectionManager;
use rocket::Outcome::{Success, Failure};
use rocket::Request;
use rocket::http::Status;
use rocket::request::{FromRequest, Outcome};
use std::fs::remove_file;
use std::io::*;
use std::io::Error;
use std::path::Path;
use std::thread;
use std::time::Duration;

fn main() {
    thread::spawn(|| {
        loop {
            let interval = 60;
            if let Err(err) = remove_old_files() {
                println!("Error: {}", err);
            }
            thread::sleep(Duration::from_secs(interval)) //TODO maybe make this better
        }
    });
    rocket::ignite()
        .catch(errors![routes::not_found, routes::too_large])
        .mount("/",
               routes![routes::get_static,
                       routes::index,
                       routes::upload,
                       routes::retrieve,
                       routes::remove])
        .mount("/json/", routes![routes::retrieve_json,
                                 routes::upload_json])
        .launch()
}

lazy_static! {
    // TODO: are there race conditions? maybe cover with mutex
    pub static ref DB_POOL: Pool<ConnectionManager<PgConnection>> = create_db_pool();
}

pub struct DB(PooledConnection<ConnectionManager<PgConnection>>);

impl DB {
    pub fn conn(&self) -> &PgConnection {
        &*self.0
    }
}

impl<'a, 'r> FromRequest<'a, 'r> for DB {
    type Error = GetTimeout;
    fn from_request(_: &'a Request<'r>) -> Outcome<Self, Self::Error> {
        match DB_POOL.get() {
            Ok(conn) => Success(DB(conn)),
            Err(e) => Failure((Status::InternalServerError, e)),
        }
    }
}

fn remove_old_files() -> Result<usize> {
    use plib::schema::pastes::dsl::*;

    let mut count: usize = 0;

    let pool_conn = DB_POOL.get();
    if let Err(err) = pool_conn {
        return Err(Error::new(ErrorKind::Other, err.to_string()));
    }

    let conn = &(*pool_conn.expect("Could not unwrap pooled connection!"));
    for paste in pastes.load::<Paste>(conn).expect("Error loading pastes") {
        let file_string = "upload/".to_string() + &paste.get_id_cloned();
        let path = Path::new(&file_string);
        if !path.exists() {
            // file does not exist. Remove from db and then continue the loop
            println!("Removed zombie paste");
            del_paste_from_db(paste.get_id_cloned());
            continue;
        }
        let metadata = try!(path.metadata());
        let time = try!(metadata.modified());
        let time_alive = time.elapsed().expect("Could not get elapsed time!");
        if time_alive > Duration::from_secs(paste.get_ttl_u64()) && remove_file(path).is_ok() {
            // also remove from db
            count += del_paste_from_db(paste.get_id_cloned());
            println!("Removed file of paste {}",
                     path.file_name().unwrap().to_str().unwrap());

        }
    }
    Ok(count)
}

fn del_paste_from_db(p_id: String) -> usize {
    use plib::schema::pastes::dsl::*;

    if let Ok(pool_conn) = DB_POOL.get() {
        let conn = &(*pool_conn);
        diesel::delete(pastes.filter(id.like(p_id)))
            .execute(conn)
            .expect("Error deleting paste")
    } else {
        0
    }
}

mod routes {
    use diesel;
    use paste_data::PasteData;
    use paste_id::{self, PasteID};
    use plib::models::Paste;
    use rand::{self, Rng};
    use rocket;
    use rocket::http::Status;
    use rocket::request::{Form, FlashMessage};
    use rocket::response::{status, NamedFile, Redirect, Flash};
    use rocket_contrib::{JSON, Value, Template};
    use std;
    use std::collections::HashMap;
    use std::fs::{File, remove_file};
    use std::io::Read;
    use std::path::{Path, PathBuf};

    static ERR_FILE_404: &'static str = "ERR_FILE_404";
    static MSG_FILE_404: &'static str = "Could not find file";

    #[error(404)]
    pub fn not_found(req: &rocket::Request) -> Template {
        let mut map = HashMap::new();
        map.insert("path", req.uri().as_str());
        Template::render("404", &map)
    }

    #[error(413)]
    pub fn too_large() -> Template {
        let mut map = HashMap::new();
        map.insert("error", "Too large!");
        Template::render("index", &map)
    }

    #[get("/")]
    pub fn index(msg: Option<FlashMessage>) -> Template {
        let mut map: HashMap<&str, &str> = std::collections::HashMap::new();
        if let Some(msg_u) = msg {
            let code = msg_u.msg();
            if code == ERR_FILE_404 {
                map.insert("error", MSG_FILE_404);
            }
        }
        Template::render("index", &map)
    }

    #[post("/", format="text/plain", data = "<paste>")]
    pub fn upload(db: super::DB, paste: PasteData) -> Result<Template, Redirect> {
        // TODO add ttl option to Form and use it here
        // TODO refactor this using the json fn. transform the json in a format the renderr can work with
        use plib::schema::pastes;
        use diesel::LoadDsl;

        let p_id = PasteID::new();
        let mut map = HashMap::new();
        match write_to_file(paste, &p_id) {
            Ok(res) => {
                let paste_id = format!("{}", p_id);
                let paste_key = generate_deletion_key();
                let new_paste = Paste::new(paste_id, paste_key, 60 * 60 * 24 * 7); //TODO
                map.insert("id", new_paste.get_id_cloned());
                map.insert("key", new_paste.get_key_cloned());
                map.insert("ttl", new_paste.get_ttl_u64().to_string());
                map.insert("link", res.1.to_string());
                diesel::insert(&new_paste)
                    .into(pastes::table)
                    .get_result::<Paste>(db.conn())
                    .expect("Error saving new paste");
                return Ok(Template::render("success", &map));
            }
            Err(res) => map.insert("error", res.to_string()),
        };
        Ok(Template::render("index", &map))
    }

    #[post("/", format="text/plain", data = "<paste>")]
    pub fn upload_json(db: super::DB, paste: PasteData) -> JSON<Value> {
        // TODO add ttl option to Form and use it here
        use plib::schema::pastes;
        use diesel::LoadDsl;

        let p_id = PasteID::new();
        match write_to_file(paste, &p_id) {
            Ok(res) => {
                let paste_id = format!("{}", p_id);
                let paste_key = generate_deletion_key();
                let new_paste = Paste::new(paste_id, paste_key, 60 * 60 * 24 * 7); //TODO
                let ret_json = JSON(json!({
                    "id": new_paste.get_id_cloned(),
                    "key": new_paste.get_key_cloned(),
                    "ttl": new_paste.get_ttl_u64().to_string(),
                    "link": res.1.to_string()
                }));
                diesel::insert(&new_paste)
                    .into(pastes::table)
                    .get_result::<Paste>(db.conn())
                    .expect("Error saving new paste");
                ret_json
            }
            Err(res) => return JSON(json!({"error": res.to_string()}))
        }
    }

    // #[put("/<id>", format="text/plain", data = "<paste>")]
    // pub fn update(id: PasteID, paste: PasteData) -> std::io::Result<status::Custom<String>> {
    //     write_to_file(paste, id)
    // }

    fn generate_deletion_key() -> String {
        let mut key = String::with_capacity(16);
        let mut rng = rand::thread_rng();
        for _ in 0..16 {
            key.push(paste_id::BASE62[rng.gen::<usize>() % 62] as char);
        }
        key
    }

    fn write_to_file(paste: PasteData, id: &PasteID) -> std::io::Result<status::Custom<String>> {
        let filename = format!("upload/{id}", id = id);
        let output = format!("/{id}", id = id);

        paste.stream_to_file(Path::new(&filename))?;
        Ok(status::Custom(Status::Created, output))
    }

    #[get("/<id>")]
    pub fn retrieve(id: PasteID) -> Result<Template, Flash<Redirect>> {
        let filename = format!("upload/{id}", id = id);
        if let Ok(data) = get_data(filename) {
            let mut map = HashMap::new();
            map.insert("paste", data);
            return Ok(Template::render("paste", &map));
        }
        Err(Flash::error(Redirect::to("/"), ERR_FILE_404))
    }

    #[get("/<id>")]
    pub fn retrieve_json(id: PasteID) -> JSON<Value> {
        let filename = format!("upload/{id}", id = id);
        if let Ok(data) = get_data(filename) {
            return JSON(json!({"paste": data}));
        } else {
            return JSON(json!({"error": ERR_FILE_404}));
        }
    }

    fn get_data(filename: String) -> Result<String, String> {
        let mut data = String::new();
        if let Ok(mut f) = File::open(filename) {
            f.read_to_string(&mut data).expect("Unable to read string");
            return Ok(data);
        }
        Err(ERR_FILE_404.into())
    }

    #[derive(FromForm)]
    pub struct PasteDel<'r> {
        paste_id: &'r str,
        paste_key: &'r str,
    }

    #[post("/remove", data = "<del_form>")]
    pub fn remove<'a>(del_form: Form<'a, PasteDel<'a>>) -> Template {
        let paste_del = del_form.get();
        let filename = format!("upload/{id}", id = paste_del.paste_id);
        let file = Path::new(&filename);
        let mut map = HashMap::new();
        if file.exists() {
            let key = paste_del.paste_key;
            if key == get_paste_key(paste_del.paste_id.into()) && remove_file(file).is_ok() {
                map.insert("success",
                           format!("Paste {id} removed", id = paste_del.paste_id));
                super::del_paste_from_db(paste_del.paste_id.into());
            } else {
                map.insert("error", "Invalid Paste ID or Key".into());
            }
        } else {
            map.insert("error", "Invalid Paste ID or Key".into());
        }
        Template::render("index", &map)
    }

    fn get_paste_key(paste_id: String) -> String {
        use plib::schema::pastes::dsl::*;
        use diesel::prelude::*;

        if let Ok(pool_conn) = super::DB_POOL.get() {
            let conn = &(*pool_conn);
            let k = pastes.find(paste_id)
                .first::<Paste>(conn)
                .expect("Error loading paste");
            k.get_key_cloned()
        } else {
            // db connection could not be established, return random key
            generate_deletion_key()
        }
    }

    #[get("/static/<file..>")]
    pub fn get_static(file: PathBuf) -> Option<NamedFile> {
        NamedFile::open(Path::new("static/").join(file)).ok()
    }
}

#[cfg(test)]
#[allow(unused_variables, unused_mut)]
mod tests {
    use rocket;
    use rocket::http::{Status, Method, ContentType};
    use rocket::testing::MockRequest;
    use routes;

    fn post_data_req(size: usize, rocket: &rocket::Rocket) -> (Status, String) {
        let mut paste_content = String::new();
        for _ in 0..(size / 2) {
            paste_content += "XX";
        }
        let mut req = MockRequest::new(Method::Post, "/")
            .header(ContentType::new("text", "plain"))
            .body(&format!("paste={paste}", paste = paste_content));
        let mut res = req.dispatch_with(rocket);
        let body_str = res.body()
            .and_then(|b| b.into_string())
            .expect("Result has no body!");
        (res.status(), body_str)
    }

    describe! route_tests{
        before_each {
            let rocket = rocket::ignite()
                .catch(errors![routes::not_found, routes::too_large])
                .mount("/", routes![routes::get_static,
                                    routes::index,
                                    routes::upload,
                                    routes::retrieve,
                                    routes::remove]);
        }

        describe! status {
            before_each {
                let mut req = MockRequest::new(Method::Get, "/");
                let mut res = req.dispatch_with(&rocket);
                let body_str = res.body()
                            .and_then(|b| b.into_string())
                            .expect("Result has no body!");
            }

            it "responds with status OK 200" {
                assert_eq!(res.status(), Status::Ok);
            }

            it "responds with no error" {
                assert!(!body_str.contains("Error"));
            }
        }

        describe! error404 {
            it "invalid url" {
                let mut req = MockRequest::new(Method::Get, "/invalid_url");
                let res = req.dispatch_with(&rocket);
                assert_eq!(res.status(), Status::NotFound);
            }
        }

        describe! post_paste {
            it "basic paste" {
                let (status, body_str) = post_data_req(42, &rocket);
                assert_eq!(status, Status::Ok);
                assert!(body_str.contains("ID:"));
            }
        }
    }
}
<commit_msg>refactored both post to /<commit_after>#![feature(plugin, custom_derive)]
#![plugin(rocket_codegen)]
#![cfg_attr(test, plugin(stainless))]
#![cfg_attr(feature = "dev", allow(unstable_features))]
#![cfg_attr(feature = "dev", plugin(clippy))]

extern crate rocket;
#[macro_use] extern crate rocket_contrib;
extern crate rand;
#[macro_use] extern crate lazy_static;
extern crate diesel;
extern crate r2d2;
extern crate r2d2_diesel;
extern crate plib;

pub mod paste_id;
pub mod paste_data;

use diesel::pg::PgConnection;
use diesel::prelude::*;
use plib::*;
use plib::models::Paste;
use r2d2::{Pool, PooledConnection, GetTimeout};
use r2d2_diesel::ConnectionManager;
use rocket::Outcome::{Success, Failure};
use rocket::Request;
use rocket::http::Status;
use rocket::request::{FromRequest, Outcome};
use std::fs::remove_file;
use std::io::*;
use std::io::Error;
use std::path::Path;
use std::thread;
use std::time::Duration;

fn main() {
    thread::spawn(|| {
        loop {
            let interval = 60;
            if let Err(err) = remove_old_files() {
                println!("Error: {}", err);
            }
            thread::sleep(Duration::from_secs(interval)) //TODO maybe make this better
        }
    });
    rocket::ignite()
        .catch(errors![routes::not_found, routes::too_large])
        .mount("/",
               routes![routes::get_static,
                       routes::index,
                       routes::upload,
                       routes::retrieve,
                       routes::remove])
        .mount("/json/", routes![routes::retrieve_json,
                                 routes::upload_json])
        .launch()
}

lazy_static! {
    // TODO: are there race conditions? maybe cover with mutex
    pub static ref DB_POOL: Pool<ConnectionManager<PgConnection>> = create_db_pool();
}

pub struct DB(PooledConnection<ConnectionManager<PgConnection>>);

impl DB {
    pub fn conn(&self) -> &PgConnection {
        &*self.0
    }
}

impl<'a, 'r> FromRequest<'a, 'r> for DB {
    type Error = GetTimeout;
    fn from_request(_: &'a Request<'r>) -> Outcome<Self, Self::Error> {
        match DB_POOL.get() {
            Ok(conn) => Success(DB(conn)),
            Err(e) => Failure((Status::InternalServerError, e)),
        }
    }
}

fn remove_old_files() -> Result<usize> {
    use plib::schema::pastes::dsl::*;

    let mut count: usize = 0;

    let pool_conn = DB_POOL.get();
    if let Err(err) = pool_conn {
        return Err(Error::new(ErrorKind::Other, err.to_string()));
    }

    let conn = &(*pool_conn.expect("Could not unwrap pooled connection!"));
    for paste in pastes.load::<Paste>(conn).expect("Error loading pastes") {
        let file_string = "upload/".to_string() + &paste.get_id_cloned();
        let path = Path::new(&file_string);
        if !path.exists() {
            // file does not exist. Remove from db and then continue the loop
            println!("Removed zombie paste");
            del_paste_from_db(paste.get_id_cloned());
            continue;
        }
        let metadata = try!(path.metadata());
        let time = try!(metadata.modified());
        let time_alive = time.elapsed().expect("Could not get elapsed time!");
        if time_alive > Duration::from_secs(paste.get_ttl_u64()) && remove_file(path).is_ok() {
            // also remove from db
            count += del_paste_from_db(paste.get_id_cloned());
            println!("Removed file of paste {}",
                     path.file_name().unwrap().to_str().unwrap());

        }
    }
    Ok(count)
}

fn del_paste_from_db(p_id: String) -> usize {
    use plib::schema::pastes::dsl::*;

    if let Ok(pool_conn) = DB_POOL.get() {
        let conn = &(*pool_conn);
        diesel::delete(pastes.filter(id.like(p_id)))
            .execute(conn)
            .expect("Error deleting paste")
    } else {
        0
    }
}

mod routes {
    use diesel;
    use paste_data::PasteData;
    use paste_id::{self, PasteID};
    use plib::models::Paste;
    use rand::{self, Rng};
    use rocket;
    use rocket::http::Status;
    use rocket::request::{Form, FlashMessage};
    use rocket::response::{status, NamedFile, Redirect, Flash};
    use rocket_contrib::{JSON, Value, Template};
    use std;
    use std::collections::HashMap;
    use std::fs::{File, remove_file};
    use std::io::Read;
    use std::path::{Path, PathBuf};

    static ERR_FILE_404: &'static str = "ERR_FILE_404";
    static MSG_FILE_404: &'static str = "Could not find file";

    #[error(404)]
    pub fn not_found(req: &rocket::Request) -> Template {
        let mut map = HashMap::new();
        map.insert("path", req.uri().as_str());
        Template::render("404", &map)
    }

    #[error(413)]
    pub fn too_large() -> Template {
        let mut map = HashMap::new();
        map.insert("error", "Too large!");
        Template::render("index", &map)
    }

    #[get("/")]
    pub fn index(msg: Option<FlashMessage>) -> Template {
        let mut map: HashMap<&str, &str> = std::collections::HashMap::new();
        if let Some(msg_u) = msg {
            let code = msg_u.msg();
            if code == ERR_FILE_404 {
                map.insert("error", MSG_FILE_404);
            }
        }
        Template::render("index", &map)
    }

    fn save_paste<'a>(db: super::DB, paste: PasteData) -> HashMap<&'a str, String> {
        // TODO add ttl option to Form and use it here
        use plib::schema::pastes;
        use diesel::LoadDsl;

        let p_id = PasteID::new();
        let mut map = HashMap::new();
        match write_to_file(paste, &p_id) {
            Ok(res) => {
                let paste_id = format!("{}", p_id);
                let paste_key = generate_deletion_key();
                let new_paste = Paste::new(paste_id, paste_key, 60 * 60 * 24 * 7); //TODO
                map.insert("id", new_paste.get_id_cloned());
                map.insert("key", new_paste.get_key_cloned());
                map.insert("ttl", new_paste.get_ttl_u64().to_string());
                map.insert("link", res.1.to_string());
                diesel::insert(&new_paste)
                    .into(pastes::table)
                    .get_result::<Paste>(db.conn())
                    .expect("Error saving new paste");
            }
            Err(res) => {map.insert("error", res.to_string());}
        };
        map
    }

    #[post("/", format="text/plain", data = "<paste>")]
    pub fn upload(db: super::DB, paste: PasteData) -> Result<Template, Redirect> {
        let map = save_paste(db, paste);
        if map.contains_key("error") {
            return Ok(Template::render("index", &map));
        }
        Ok(Template::render("success", &map))
    }

    #[post("/", format="text/plain", data = "<paste>")]
    pub fn upload_json(db: super::DB, paste: PasteData) -> JSON<Value> {
        JSON(json!(save_paste(db, paste)))
    }

    // #[put("/<id>", format="text/plain", data = "<paste>")]
    // pub fn update(id: PasteID, paste: PasteData) -> std::io::Result<status::Custom<String>> {
    //     write_to_file(paste, id)
    // }

    fn generate_deletion_key() -> String {
        let mut key = String::with_capacity(16);
        let mut rng = rand::thread_rng();
        for _ in 0..16 {
            key.push(paste_id::BASE62[rng.gen::<usize>() % 62] as char);
        }
        key
    }

    fn write_to_file(paste: PasteData, id: &PasteID) -> std::io::Result<status::Custom<String>> {
        let filename = format!("upload/{id}", id = id);
        let output = format!("/{id}", id = id);

        paste.stream_to_file(Path::new(&filename))?;
        Ok(status::Custom(Status::Created, output))
    }

    #[get("/<id>")]
    pub fn retrieve(id: PasteID) -> Result<Template, Flash<Redirect>> {
        let filename = format!("upload/{id}", id = id);
        if let Ok(data) = get_data(filename) {
            let mut map = HashMap::new();
            map.insert("paste", data);
            return Ok(Template::render("paste", &map));
        }
        Err(Flash::error(Redirect::to("/"), ERR_FILE_404))
    }

    #[get("/<id>")]
    pub fn retrieve_json(id: PasteID) -> JSON<Value> {
        let filename = format!("upload/{id}", id = id);
        if let Ok(data) = get_data(filename) {
            return JSON(json!({"paste": data}));
        } else {
            return JSON(json!({"error": MSG_FILE_404}));
        }
    }

    fn get_data(filename: String) -> Result<String, String> {
        let mut data = String::new();
        if let Ok(mut f) = File::open(filename) {
            f.read_to_string(&mut data).expect("Unable to read string");
            return Ok(data);
        }
        Err(ERR_FILE_404.into())
    }

    #[derive(FromForm)]
    pub struct PasteDel<'r> {
        paste_id: &'r str,
        paste_key: &'r str,
    }

    #[post("/remove", data = "<del_form>")]
    pub fn remove<'a>(del_form: Form<'a, PasteDel<'a>>) -> Template {
        let paste_del = del_form.get();
        let filename = format!("upload/{id}", id = paste_del.paste_id);
        let file = Path::new(&filename);
        let mut map = HashMap::new();
        if file.exists() {
            let key = paste_del.paste_key;
            if key == get_paste_key(paste_del.paste_id.into()) && remove_file(file).is_ok() {
                map.insert("success",
                           format!("Paste {id} removed", id = paste_del.paste_id));
                super::del_paste_from_db(paste_del.paste_id.into());
            } else {
                map.insert("error", "Invalid Paste ID or Key".into());
            }
        } else {
            map.insert("error", "Invalid Paste ID or Key".into());
        }
        Template::render("index", &map)
    }

    fn get_paste_key(paste_id: String) -> String {
        use plib::schema::pastes::dsl::*;
        use diesel::prelude::*;

        if let Ok(pool_conn) = super::DB_POOL.get() {
            let conn = &(*pool_conn);
            let k = pastes.find(paste_id)
                .first::<Paste>(conn)
                .expect("Error loading paste");
            k.get_key_cloned()
        } else {
            // db connection could not be established, return random key
            generate_deletion_key()
        }
    }

    #[get("/static/<file..>")]
    pub fn get_static(file: PathBuf) -> Option<NamedFile> {
        NamedFile::open(Path::new("static/").join(file)).ok()
    }
}

#[cfg(test)]
#[allow(unused_variables, unused_mut)]
mod tests {
    use rocket;
    use rocket::http::{Status, Method, ContentType};
    use rocket::testing::MockRequest;
    use routes;

    fn post_data_req(size: usize, rocket: &rocket::Rocket) -> (Status, String) {
        let mut paste_content = String::new();
        for _ in 0..(size / 2) {
            paste_content += "XX";
        }
        let mut req = MockRequest::new(Method::Post, "/")
            .header(ContentType::new("text", "plain"))
            .body(&format!("paste={paste}", paste = paste_content));
        let mut res = req.dispatch_with(rocket);
        let body_str = res.body()
            .and_then(|b| b.into_string())
            .expect("Result has no body!");
        (res.status(), body_str)
    }

    describe! route_tests{
        before_each {
            let rocket = rocket::ignite()
                .catch(errors![routes::not_found, routes::too_large])
                .mount("/", routes![routes::get_static,
                                    routes::index,
                                    routes::upload,
                                    routes::retrieve,
                                    routes::remove]);
        }

        describe! status {
            before_each {
                let mut req = MockRequest::new(Method::Get, "/");
                let mut res = req.dispatch_with(&rocket);
                let body_str = res.body()
                            .and_then(|b| b.into_string())
                            .expect("Result has no body!");
            }

            it "responds with status OK 200" {
                assert_eq!(res.status(), Status::Ok);
            }

            it "responds with no error" {
                assert!(!body_str.contains("Error"));
            }
        }

        describe! error404 {
            it "invalid url" {
                let mut req = MockRequest::new(Method::Get, "/invalid_url");
                let res = req.dispatch_with(&rocket);
                assert_eq!(res.status(), Status::NotFound);
            }
        }

        describe! post_paste {
            it "basic paste" {
                let (status, body_str) = post_data_req(42, &rocket);
                assert_eq!(status, Status::Ok);
                assert!(body_str.contains("ID:"));
            }
        }
    }
}
<|endoftext|>


<commit_before>#![feature(rustc_private, custom_attribute)]
#![allow(unused_attributes)]

extern crate getopts;
extern crate miri;
extern crate rustc;
extern crate rustc_driver;
extern crate env_logger;
extern crate log_settings;
extern crate log;

use miri::interpreter;
use rustc::session::Session;
use rustc_driver::{driver, CompilerCalls};

struct MiriCompilerCalls;

impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
    fn build_controller(
        &mut self,
        _: &Session,
        _: &getopts::Matches
    ) -> driver::CompileController<'a> {
        let mut control = driver::CompileController::basic();

        control.after_analysis.callback = Box::new(|state| {
            state.session.abort_if_errors();
            interpreter::interpret_start_points(state.tcx.unwrap(), state.mir_map.unwrap());
        });

        control
    }
}

#[miri_run]
fn main() {
    init_logger();
    let args: Vec<String> = std::env::args().collect();
    rustc_driver::run_compiler(&args, &mut MiriCompilerCalls);
}

#[miri_run]
fn init_logger() {
    let format = |record: &log::LogRecord| {
        // prepend spaces to indent the final string
        let indentation = log_settings::settings().indentation;
        let spaces = "    |    |    |    |    |    |    |    |    ";
        let indentation = &spaces[..std::cmp::min(indentation, spaces.len())];
        format!("{}:{}|{} {}", record.level(), record.location().module_path(), indentation, record.args())
    };

    let mut builder = env_logger::LogBuilder::new();
    builder.format(format).filter(None, log::LogLevelFilter::Info);

    if std::env::var("MIRI_LOG").is_ok() {
        builder.parse(&std::env::var("MIRI_LOG").unwrap());
    }

    builder.init().unwrap();
}
<commit_msg>use a number for the maximum indentation instead of relying on str::len()<commit_after>#![feature(rustc_private, custom_attribute)]
#![allow(unused_attributes)]

extern crate getopts;
extern crate miri;
extern crate rustc;
extern crate rustc_driver;
extern crate env_logger;
extern crate log_settings;
extern crate log;

use miri::interpreter;
use rustc::session::Session;
use rustc_driver::{driver, CompilerCalls};

struct MiriCompilerCalls;

impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
    fn build_controller(
        &mut self,
        _: &Session,
        _: &getopts::Matches
    ) -> driver::CompileController<'a> {
        let mut control = driver::CompileController::basic();

        control.after_analysis.callback = Box::new(|state| {
            state.session.abort_if_errors();
            interpreter::interpret_start_points(state.tcx.unwrap(), state.mir_map.unwrap());
        });

        control
    }
}

#[miri_run]
fn main() {
    init_logger();
    let args: Vec<String> = std::env::args().collect();
    rustc_driver::run_compiler(&args, &mut MiriCompilerCalls);
}

#[miri_run]
fn init_logger() {
    let format = |record: &log::LogRecord| {
        // prepend spaces to indent the final string
        let indentation = log_settings::settings().indentation;
        let spaces = "    |    |    |    |    |    |    |    |    |";
        let indentation = &spaces[..std::cmp::min(indentation, 44)];
        format!("{}:{}|{} {}", record.level(), record.location().module_path(), indentation, record.args())
    };

    let mut builder = env_logger::LogBuilder::new();
    builder.format(format).filter(None, log::LogLevelFilter::Info);

    if std::env::var("MIRI_LOG").is_ok() {
        builder.parse(&std::env::var("MIRI_LOG").unwrap());
    }

    builder.init().unwrap();
}
<|endoftext|>


<commit_before>extern crate r6;
extern crate copperline;

use copperline::{Copperline, Encoding};

use r6::base::{libbase, base_syntax};
use r6::datum::Datum;
use r6::error::ParserErrorKind;
use r6::parser::Parser;
use r6::runtime::Runtime;

fn read(cl: &mut Copperline) -> Result<Datum<()>, String> {
    let mut input = match cl.read_line(">> ", Encoding::Utf8) {
        Ok(l) => l,
        Err(e) => return Err(e.to_string())
    };

    if let Some(datum) = try!(parse(input.as_bytes())) {
        return Ok(datum)
    }

    loop {
        let line = match cl.read_line(".. ", Encoding::Utf8) {
            Ok(l) => l,
            Err(e) => return Err(e.to_string())
        };

        input.push_str("\n");
        input.push_str(&line);

        if let Some(datum) = try!(parse(input.as_bytes())) {
            return Ok(datum)
        }
    }
}

fn parse(input: &[u8]) -> Result<Option<Datum<()>>, String> {
    let mut parser = Parser::new(input);
    match parser.parse_full() {
        Ok(code) => Ok(Some(code)),
        Err(e) => match e.kind {
            ParserErrorKind::UnexpectedEOF => Ok(None),
            _ => Err(e.to_string())
        }
    }
}

fn main() {
    let mut cl = Copperline::new();
    let mut runtime = Runtime::new(libbase(), base_syntax());

    loop {
        match read(&mut cl) {
            Ok(code) => match runtime.eval(&code) {
                Ok(v) => println!("{}", v),
                Err(e) => println!("Error: {}", e)
            },
            Err(e) => {
                println!("Error: {}", e);
                return;
            }
        }
    }
}
<commit_msg>Better UI for REPL<commit_after>extern crate r6;
extern crate copperline;

use std::process::exit;

use copperline::{Copperline, Encoding};
use copperline::Error as CopperlineError;

use r6::base::{libbase, base_syntax};
use r6::datum::Datum;
use r6::error::ParserErrorKind;
use r6::parser::Parser;
use r6::runtime::Runtime;

fn read(cl: &mut Copperline) -> Result<Datum<()>, String> {
    let mut input = match cl.read_line(">> ", Encoding::Utf8) {
        Ok(l) => l,
        Err(CopperlineError::EndOfFile) => {
            exit(0);
        },
        Err(e) => {
            println!("{}", e);
            exit(1);
        }
    };

    if let Some(datum) = try!(parse(input.as_bytes())) {
        return Ok(datum)
    }

    loop {
        let line = match cl.read_line(".. ", Encoding::Utf8) {
            Ok(l) => l,
            Err(CopperlineError::EndOfFile) => {
                println!("^D");
                exit(0);
            },
            Err(e) => {
                println!("{}", e);
                exit(1);
            }
        };

        input.push_str("\n");
        input.push_str(&line);

        if let Some(datum) = try!(parse(input.as_bytes())) {
            return Ok(datum)
        }
    }
}

fn parse(input: &[u8]) -> Result<Option<Datum<()>>, String> {
    let mut parser = Parser::new(input);
    match parser.parse_full() {
        Ok(code) => Ok(Some(code)),
        Err(e) => match e.kind {
            ParserErrorKind::UnexpectedEOF => Ok(None),
            _ => Err(e.to_string())
        }
    }
}

fn main() {
    let mut cl = Copperline::new();
    let mut runtime = Runtime::new(libbase(), base_syntax());

    loop {
        match read(&mut cl) {
            Ok(code) => match runtime.eval(&code) {
                Ok(v) => println!("{}", v),
                Err(e) => println!("Error: {}", e)
            },
            Err(e) => {
                println!("Error: {}", e);
            }
        }
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate coreutils;
extern crate extra;
extern crate syscall;

use std::{env, fmt, fs};
use std::io::{stdout, stderr, Write};
use coreutils::ArgParser;
use extra::option::OptionalExt;

const MAN_PAGE: &'static str = /* @MANSTART{stat} */ r#"
NAME
    stat - display file status

SYNOPSIS
    stat [ -h | --help ] FILE...

DESCRIPTION
    Displays file status.

OPTIONS
    --help, -h
        print this message
"#; /* @MANEND */

struct Perms(u16);

impl fmt::Display for Perms {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "(0{:o}/", self.0 & 0o777)?;
        let perm = |i, c| {
            if self.0 & ((1 << i) as u16) != 0 {
                c
            } else {
                "-"
            }
        };
        write!(f, "{}{}{}", perm(8, "r"), perm(7, "w"), perm(6, "x"))?;
        write!(f, "{}{}{}", perm(5, "r"), perm(4, "w"), perm(3, "x"))?;
        write!(f, "{}{}{}", perm(2, "r"), perm(1, "w"), perm(0, "x"))?;
        write!(f, ")")?;
        Ok(())
    }
}

fn main() {
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();
    let mut parser = ArgParser::new(1)
        .add_flag(&["h", "help"]);
    parser.parse(env::args());

    if parser.found("help") {
        stdout.write_all(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        return;
    }

    for path in &parser.args[0..] {
        let mut st = syscall::Stat::default();
        let fd = syscall::open(path, syscall::O_CLOEXEC | syscall::O_STAT | syscall::O_NOFOLLOW).unwrap();
        syscall::fstat(fd, &mut st).unwrap();
        syscall::close(fd).unwrap();
        let file_type = match st.st_mode & syscall::MODE_TYPE {
            syscall::MODE_FILE => "regular file",
            syscall::MODE_DIR => "directory",
            syscall::MODE_SYMLINK => "symbolic link",
            _ => ""
        };
        if st.st_mode & syscall::MODE_SYMLINK == syscall::MODE_SYMLINK {
            println!("File: {} -> {}", path, fs::read_link(path).unwrap().display());
        } else {
            println!("File: {}", path);
        }
        println!("Size: {}  Blocks: {}  IO Block: {} {}", st.st_size, st.st_blocks, st.st_blksize, file_type);
        println!("Device: {}  Inode: {}  Links: {}", st.st_dev, st.st_ino, st.st_nlink);
        println!("Access: {}  Uid: {}  Gid: {}", Perms(st.st_mode), st.st_uid, st.st_gid);
        println!("Access: {}.{:09}", st.st_atime, st.st_atime_nsec);
        println!("Modify: {}.{:09}", st.st_mtime, st.st_mtime_nsec);
        println!("Change: {}.{:09}", st.st_ctime, st.st_ctime_nsec);
    }
}
<commit_msg>Use libstd instead of syscall for stat<commit_after>#![deny(warnings)]

extern crate coreutils;
extern crate extra;

use std::{env, fmt, fs};
use std::io::{stdout, stderr, Write};
use coreutils::ArgParser;
use extra::option::OptionalExt;
use std::os::unix::fs::MetadataExt;

const MAN_PAGE: &'static str = /* @MANSTART{stat} */ r#"
NAME
    stat - display file status

SYNOPSIS
    stat [ -h | --help ] FILE...

DESCRIPTION
    Displays file status.

OPTIONS
    --help, -h
        print this message
"#; /* @MANEND */

struct Perms(u32);

impl fmt::Display for Perms {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "(0{:o}/", self.0 & 0o777)?;
        let perm = |i, c| {
            if self.0 & ((1 << i) as u32) != 0 {
                c
            } else {
                "-"
            }
        };
        write!(f, "{}{}{}", perm(8, "r"), perm(7, "w"), perm(6, "x"))?;
        write!(f, "{}{}{}", perm(5, "r"), perm(4, "w"), perm(3, "x"))?;
        write!(f, "{}{}{}", perm(2, "r"), perm(1, "w"), perm(0, "x"))?;
        write!(f, ")")?;
        Ok(())
    }
}

fn main() {
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();
    let mut parser = ArgParser::new(1)
        .add_flag(&["h", "help"]);
    parser.parse(env::args());

    if parser.found("help") {
        stdout.write_all(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        return;
    }

    for path in &parser.args[0..] {
        let meta = fs::symlink_metadata(path).unwrap();
        let file_type = if meta.file_type().is_symlink() {
            "symbolic link"
        } else if meta.is_file() {
            "regular file"
        } else if meta.is_dir() {
            "directory"
        } else {
            ""
        };
        if meta.file_type().is_symlink() {
            println!("File: {} -> {}", path, fs::read_link(path).unwrap().display());
        } else {
            println!("File: {}", path);
        }
        println!("Size: {}  Blocks: {}  IO Block: {} {}", meta.size(), meta.blocks(), meta.blksize(), file_type);
        println!("Device: {}  Inode: {}  Links: {}", meta.dev(), meta.ino(), meta.nlink());
        println!("Access: {}  Uid: {}  Gid: {}", Perms(meta.mode()), meta.uid(), meta.gid());
        println!("Access: {}.{:09}", meta.atime(), meta.atime_nsec());
        println!("Modify: {}.{:09}", meta.mtime(), meta.mtime_nsec());
        println!("Change: {}.{:09}", meta.ctime(), meta.ctime_nsec());
    }
}
<|endoftext|>


<commit_before>use std::io;

use features::Features;
use token::{Sentence, Token, EMPTY_TOKEN};
use error::{ErrorKind, Result, ResultExt};

/// A trait for objects that can read CoNLL-X `Sentence`s
pub trait ReadSentence {
    /// Read a `Sentence` from this object.
    ///
    /// # Errors
    ///
    /// A call to `read_sentence` may generate an error to indicate that
    /// the operation could not be completed.
    fn read_sentence(&mut self) -> Result<Option<Sentence>>;
}

/// A reader for CoNLL-X sentences.
pub struct Reader<R> {
    read: R,
}

impl<R: io::BufRead> Reader<R> {
    /// Construct a new reader from an object that implements the
    /// `io::BufRead` trait.
    pub fn new(read: R) -> Reader<R> {
        Reader { read: read }
    }

    /// Get an iterator over the `Sentence`s in this reader.
    pub fn sentences(self) -> Sentences<Reader<R>> {
        Sentences { reader: self }
    }
}

impl<R: io::BufRead> IntoIterator for Reader<R> {
    type Item = Result<Sentence>;
    type IntoIter = Sentences<Reader<R>>;

    fn into_iter(self) -> Self::IntoIter {
        self.sentences()
    }
}

impl<R: io::BufRead> ReadSentence for Reader<R> {
    fn read_sentence(&mut self) -> Result<Option<Sentence>> {
        let mut line = String::new();
        let mut tokens = Vec::new();

        loop {
            line.clear();

            // End of reader.
            if self.read.read_line(&mut line)? == 0 {
                if tokens.is_empty() {
                    return Ok(None);
                }

                return Ok(Some(Sentence::new(tokens)));
            }

            // The blank line is a sentence separator. We want to be robust
            // in the case a CoNLL file is malformed and has two newlines as
            // a separator.
            if line.trim().is_empty() {
                if tokens.is_empty() {
                    continue;
                }

                return Ok(Some(Sentence::new(tokens)));
            }

            let mut iter = line.trim().split_terminator('\t');

            parse_numeric_field(iter.next())?;

            let mut token = Token::new();
            token.set_form(parse_string_field(iter.next()));
            token.set_lemma(parse_string_field(iter.next()));
            token.set_cpos(parse_string_field(iter.next()));
            token.set_pos(parse_string_field(iter.next()));
            token.set_features(parse_string_field(iter.next()).map(Features::from_string));
            token.set_head(parse_numeric_field(iter.next())?);
            token.set_head_rel(parse_string_field(iter.next()));
            token.set_p_head(parse_numeric_field(iter.next())?);
            token.set_p_head_rel(parse_string_field(iter.next()));

            tokens.push(token);
        }
    }
}

/// An iterator over the sentences in a `Reader`.
pub struct Sentences<R> where R: ReadSentence {
    reader: R,
}

impl<R> Iterator for Sentences<R> where R: ReadSentence {
    type Item = Result<Sentence>;

    fn next(&mut self) -> Option<Result<Sentence>> {
        match self.reader.read_sentence() {
            Ok(None) => None,
            Ok(Some(sent)) => Some(Ok(sent)),
            Err(e) => Some(Err(e)),
        }
    }
}

fn parse_string_field(field: Option<&str>) -> Option<String> {
    field.and_then(|s| {
        if s == EMPTY_TOKEN {
            None
        } else {
            Some(s.to_string())
        }
    })
}

fn parse_numeric_field(field: Option<&str>) -> Result<Option<usize>> {
    match field {
        None => Ok(None),
        Some(s) => {
            if s == EMPTY_TOKEN {
                Ok(None)
            } else {
                Ok(Some(s.parse().chain_err(|| ErrorKind::ParseIntFieldError(s.to_owned()))?))
            }
        }
    }
}
<commit_msg>Add a sentences method to SentenceRead.<commit_after>use std::io;

use features::Features;
use token::{Sentence, Token, EMPTY_TOKEN};
use error::{ErrorKind, Result, ResultExt};

/// A trait for objects that can read CoNLL-X `Sentence`s
pub trait ReadSentence {
    /// Read a `Sentence` from this object.
    ///
    /// # Errors
    ///
    /// A call to `read_sentence` may generate an error to indicate that
    /// the operation could not be completed.
    fn read_sentence(&mut self) -> Result<Option<Sentence>>;

    /// Get an iterator over the sentences in this reader.
    fn sentences(self) -> Sentences<Self>
        where Self: Sized
    {
        Sentences { reader: self }
    }
}

/// A reader for CoNLL-X sentences.
pub struct Reader<R> {
    read: R,
}

impl<R: io::BufRead> Reader<R> {
    /// Construct a new reader from an object that implements the
    /// `io::BufRead` trait.
    pub fn new(read: R) -> Reader<R> {
        Reader { read: read }
    }
}

impl<R: io::BufRead> IntoIterator for Reader<R> {
    type Item = Result<Sentence>;
    type IntoIter = Sentences<Reader<R>>;

    fn into_iter(self) -> Self::IntoIter {
        self.sentences()
    }
}

impl<R: io::BufRead> ReadSentence for Reader<R> {
    fn read_sentence(&mut self) -> Result<Option<Sentence>> {
        let mut line = String::new();
        let mut tokens = Vec::new();

        loop {
            line.clear();

            // End of reader.
            if self.read.read_line(&mut line)? == 0 {
                if tokens.is_empty() {
                    return Ok(None);
                }

                return Ok(Some(Sentence::new(tokens)));
            }

            // The blank line is a sentence separator. We want to be robust
            // in the case a CoNLL file is malformed and has two newlines as
            // a separator.
            if line.trim().is_empty() {
                if tokens.is_empty() {
                    continue;
                }

                return Ok(Some(Sentence::new(tokens)));
            }

            let mut iter = line.trim().split_terminator('\t');

            parse_numeric_field(iter.next())?;

            let mut token = Token::new();
            token.set_form(parse_string_field(iter.next()));
            token.set_lemma(parse_string_field(iter.next()));
            token.set_cpos(parse_string_field(iter.next()));
            token.set_pos(parse_string_field(iter.next()));
            token.set_features(parse_string_field(iter.next()).map(Features::from_string));
            token.set_head(parse_numeric_field(iter.next())?);
            token.set_head_rel(parse_string_field(iter.next()));
            token.set_p_head(parse_numeric_field(iter.next())?);
            token.set_p_head_rel(parse_string_field(iter.next()));

            tokens.push(token);
        }
    }
}

/// An iterator over the sentences in a `Reader`.
pub struct Sentences<R>
    where R: ReadSentence
{
    reader: R,
}

impl<R> Iterator for Sentences<R>
    where R: ReadSentence
{
    type Item = Result<Sentence>;

    fn next(&mut self) -> Option<Result<Sentence>> {
        match self.reader.read_sentence() {
            Ok(None) => None,
            Ok(Some(sent)) => Some(Ok(sent)),
            Err(e) => Some(Err(e)),
        }
    }
}

fn parse_string_field(field: Option<&str>) -> Option<String> {
    field.and_then(|s| if s == EMPTY_TOKEN {
        None
    } else {
        Some(s.to_string())
    })
}

fn parse_numeric_field(field: Option<&str>) -> Result<Option<usize>> {
    match field {
        None => Ok(None),
        Some(s) => {
            if s == EMPTY_TOKEN {
                Ok(None)
            } else {
                Ok(Some(s.parse().chain_err(|| ErrorKind::ParseIntFieldError(s.to_owned()))?))
            }
        }
    }
}
<|endoftext|>


<commit_before>// (c) 2016 Joost Yervante Damad <joost@productize.be>

use std::fmt;
use std::path::PathBuf;

// from parent
use ERes;
use err;
use read_file;
use footprint;

extern crate rustysexp;
use self::rustysexp::Sexp;

pub struct Layout {
    pub version:i64,
    pub setup:Setup,
    pub elements:Vec<Element>,
}

#[derive(Clone)]
pub enum Element {
    Module(footprint::Module),
    Net(Net),
    NetClass(NetClass),
    Other(Sexp),
}

#[derive(Clone)]
pub struct Setup {
    pub elements:Vec<Sexp>,
}

#[derive(Clone,PartialEq)]
pub struct Net {
    pub num:i64,
    pub name:String,
}

#[derive(Clone,PartialEq)]
pub struct NetClass {
    pub name:String,
    pub desc:String,
    pub clearance:f64,
    pub trace_width:f64,
    pub via_dia:f64,
    pub via_drill:f64,
    pub uvia_dia:f64,
    pub uvia_drill:f64,
    pub nets:Vec<String>,
}

impl Layout {
    pub fn new() -> Layout {
        Layout {
            version:0,
            elements:vec![],
            setup:Setup{elements:vec![]},
        }
    }

    pub fn nets(&self) -> Vec<&Net> {
        let mut v = vec![];
        for element in &self.elements {
            match *element {
                Element::Net(ref net) => v.push(net),
                _ => (),
            }
        }
        v
    }

    pub fn netclasses(&self) -> Vec<&NetClass> {
        let mut v = vec![];
        for element in &self.elements {
            match *element {
                Element::NetClass(ref net_class) => v.push(net_class),
                _ => (),
            }
        }
        v
    }

    pub fn modify_module<F>(&mut self, reference:&String, fun:F) -> ERes<()>
        where F:Fn(&mut footprint::Module) -> ()
    {
        for ref mut x in &mut self.elements[..] {
            match **x {
                Element::Module(ref mut m) => {
                    if m.is_reference(reference) {
                        return Ok(fun(m))
                    }
                },
                Element::Net(_) => (),
                Element::NetClass(_) => (),
                Element::Other(_) => (),
            }
        }
        Err(format!("did not find module with reference {}", reference))
    }

    pub fn add_net(&mut self, num:i64, name:&'static str) {
        self.elements.push(Element::Net(Net { num:num, name:String::from(name) }));
    }
    pub fn add_netclass(&mut self, name:&'static str, desc:&'static str, clearance:f64, trace_width:f64, via_dia:f64, via_drill:f64, uvia_dia:f64, uvia_drill:f64, nets:Vec<String>) {
        self.elements.push(Element::NetClass(NetClass {
            name:String::from(name),
            desc:String::from(desc),
            clearance:clearance,
            trace_width:trace_width,
            via_dia:via_dia,
            via_drill:via_drill,
            uvia_dia:uvia_dia,
            uvia_drill:uvia_drill,
            nets:nets
            }));
    }
}

impl NetClass {
    pub fn equal_no_net(&self, other:&NetClass) -> bool {
        let mut s1 = self.clone();
        s1.nets = vec![];
        let mut s2 = other.clone();
        s2.nets = vec![];
        return s1 == s2;
    }
    pub fn has_net(&self, name:&'static str) -> bool {
        for net in &self.nets {
            if &net[..] == name {
                return true
            }
        }
        return false
    }
}

impl fmt::Display for Layout {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(writeln!(f, "(kicad_pcb (version {})", self.version));
        try!(writeln!(f, "  {}", self.setup));
        for element in &self.elements[..] {
            try!(writeln!(f, "  {}", element));
            try!(writeln!(f, ""));
        }
        writeln!(f, ")")
    }
}

impl fmt::Display for Element {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Element::Other(ref s) => write!(f, "{}", s),
            Element::Module(ref s) => write!(f, "{}", s),
            Element::Net(ref s) => write!(f, "{}", s),
            Element::NetClass(ref s) => write!(f, "{}", s),
        }
    }
}

impl fmt::Display for Net {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        if self.name.contains("(") || self.name.contains(")") || self.name.len()==0 {
            write!(f, "(net {} \"{}\")", self.num, self.name)
        } else {
            write!(f, "(net {} {})", self.num, self.name)
        }
    }
}
impl fmt::Display for NetClass {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(write!(f, "(net_class {} \"{}\" ", self.name, self.desc));
        try!(write!(f, "(clearance {}) ", self.clearance));
        try!(write!(f, "(trace_width {}) ", self.trace_width));
        try!(write!(f, "(via_dia {}) ", self.via_dia));
        try!(write!(f, "(via_drill {}) ", self.via_drill));
        try!(write!(f, "(uvia_dia {}) ", self.uvia_dia));
        try!(write!(f, "(uvia_drill {}) ", self.uvia_drill));
        for net in &self.nets {
            if net.contains("(") || net.contains(")") {
                try!(write!(f, "(add_net \"{}\")", net))
            } else {
                try!(write!(f, "(add_net {})", net))
            }
        }
        write!(f, ")")

    }
}

impl fmt::Display for Setup {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(write!(f, "(setup"));
        for e in &self.elements {
            try!(write!(f, " {}", e));
        }
        write!(f, ")")
    }
}

fn parse_version(e:&Sexp) -> ERes<i64> {
    let l = try!(e.slice_atom("version"));
    l[0].i()
}

fn parse_other(e:&Sexp) -> Element {
    let e2 = e.clone();
    Element::Other(e2)
}

fn parse_module(e:&Sexp) -> ERes<Element> {
    let e2 = e.clone();
    let m = try!(footprint::parse_module(e2));
    Ok(Element::Module(m))
}

fn parse_net(e:&Sexp) -> ERes<Element> {
    let l = try!(e.slice_atom("net"));
    let num = try!(l[0].i());
    let name = try!(l[1].string()).clone();
    Ok(Element::Net(Net { name:name, num:num }))
}

fn parse_net_class(e:&Sexp) -> ERes<Element> {
    fn parse(e:&Sexp, name:&str) -> ERes<f64> {
        let l = try!(e.slice_atom(name));
        l[0].f()
    }
    let l = try!(e.slice_atom("net_class"));
    let name = try!(l[0].string()).clone();
    let desc = try!(l[1].string()).clone();
    let mut clearance = 0.1524;
    let mut trace_width = 0.2032;
    let mut via_dia = 0.675;
    let mut via_drill = 0.25;
    let mut uvia_dia = 0.508;
    let mut uvia_drill = 0.127;
    let mut nets = vec![];
    for x in &l[2..] {
        let list_name = try!(x.list_name());
        let xn = &list_name[..];
        match xn {
            "add_net" => {
                let l1 = try!(x.slice_atom("add_net"));
                nets.push(try!(l1[0].string()).clone())
            },
            "clearance" => clearance = try!(parse(x, xn)),
            "trace_width" => trace_width = try!(parse(x, xn)),
            "via_dia" => via_dia = try!(parse(x, xn)),
            "via_drill" => via_drill = try!(parse(x, xn)),
            "uvia_dia" => uvia_dia = try!(parse(x, xn)),
            "uvia_drill" => uvia_drill = try!(parse(x, xn)),
            _ => return Err(format!("unknown net_class field {}", list_name))
        }
    }
    let net_class = NetClass {
        name:name, desc:desc, clearance:clearance, via_dia:via_dia,
        via_drill:via_drill, uvia_dia:uvia_dia, uvia_drill:uvia_drill,
        nets:nets, trace_width:trace_width,
    };
    Ok(Element::NetClass(net_class))
}

fn parse_setup(e:&Sexp) -> ERes<Setup> {
    let l = try!(e.slice_atom("setup"));
    let mut v = vec![];
    v.extend_from_slice(l);
    let s = Setup { elements:v };
    Ok(s)
}

fn parse(s: &str) -> ERes<Layout> {
    let exp = match rustysexp::parse_str(s) {
        Ok(s) => s,
        Err(x) => return Err(format!("ParseError: {}", x)),
    };
    let l1 = try!(exp.slice_atom("kicad_pcb"));
    let mut layout = Layout::new();

    for ref e in l1 {
        match &try!(e.list_name())[..] {
            "version" => layout.version = try!(parse_version(e)),
            "module" => layout.elements.push(try!(parse_module(e))),
            "net" => layout.elements.push(try!(parse_net(e))),
            "net_class" => layout.elements.push(try!(parse_net_class(e))),
            "setup" => layout.setup = try!(parse_setup(e)),
            _ => layout.elements.push(parse_other(e)),
        }
    }
    Ok(layout)
}

pub fn parse_str(s: &str) -> ERes<Layout> {
    parse(s)
}

pub fn parse_file(filename: &PathBuf) -> ERes<Layout> {
    let name = filename.to_str().unwrap();
    let s = try!(match read_file(name) {
        Ok(s) => Ok(s),
        Err(x) => Err(format!("io error: {}", x))
    });
    parse(&s[..])
}
<commit_msg>change Setup in HashMap<commit_after>// (c) 2016 Joost Yervante Damad <joost@productize.be>

use std::fmt;
use std::path::PathBuf;
use std::collections::HashMap;

// from parent
use ERes;
use err;
use read_file;
use footprint;

extern crate rustysexp;
use self::rustysexp::Sexp;

pub struct Layout {
    pub version:i64,
    pub setup:Setup,
    pub elements:Vec<Element>,
}

#[derive(Clone)]
pub enum Element {
    Module(footprint::Module),
    Net(Net),
    NetClass(NetClass),
    Other(Sexp),
}

#[derive(Clone)]
pub struct Setup {
    pub elements:HashMap<String, Sexp>,
}

#[derive(Clone,PartialEq)]
pub struct Net {
    pub num:i64,
    pub name:String,
}

#[derive(Clone,PartialEq)]
pub struct NetClass {
    pub name:String,
    pub desc:String,
    pub clearance:f64,
    pub trace_width:f64,
    pub via_dia:f64,
    pub via_drill:f64,
    pub uvia_dia:f64,
    pub uvia_drill:f64,
    pub nets:Vec<String>,
}

impl Layout {
    pub fn new() -> Layout {
        Layout {
            version:0,
            elements:vec![],
            setup:Setup{elements:HashMap::new()},
        }
    }

    pub fn nets(&self) -> Vec<&Net> {
        let mut v = vec![];
        for element in &self.elements {
            match *element {
                Element::Net(ref net) => v.push(net),
                _ => (),
            }
        }
        v
    }

    pub fn netclasses(&self) -> Vec<&NetClass> {
        let mut v = vec![];
        for element in &self.elements {
            match *element {
                Element::NetClass(ref net_class) => v.push(net_class),
                _ => (),
            }
        }
        v
    }

    pub fn modify_module<F>(&mut self, reference:&String, fun:F) -> ERes<()>
        where F:Fn(&mut footprint::Module) -> ()
    {
        for ref mut x in &mut self.elements[..] {
            match **x {
                Element::Module(ref mut m) => {
                    if m.is_reference(reference) {
                        return Ok(fun(m))
                    }
                },
                Element::Net(_) => (),
                Element::NetClass(_) => (),
                Element::Other(_) => (),
            }
        }
        Err(format!("did not find module with reference {}", reference))
    }

    pub fn add_net(&mut self, num:i64, name:&'static str) {
        self.elements.push(Element::Net(Net { num:num, name:String::from(name) }));
    }
    pub fn add_netclass(&mut self, name:&'static str, desc:&'static str, clearance:f64, trace_width:f64, via_dia:f64, via_drill:f64, uvia_dia:f64, uvia_drill:f64, nets:Vec<String>) {
        self.elements.push(Element::NetClass(NetClass {
            name:String::from(name),
            desc:String::from(desc),
            clearance:clearance,
            trace_width:trace_width,
            via_dia:via_dia,
            via_drill:via_drill,
            uvia_dia:uvia_dia,
            uvia_drill:uvia_drill,
            nets:nets
            }));
    }
}

impl NetClass {
    pub fn equal_no_net(&self, other:&NetClass) -> bool {
        let mut s1 = self.clone();
        s1.nets = vec![];
        let mut s2 = other.clone();
        s2.nets = vec![];
        return s1 == s2;
    }
    pub fn has_net(&self, name:&'static str) -> bool {
        for net in &self.nets {
            if &net[..] == name {
                return true
            }
        }
        return false
    }
}

impl fmt::Display for Layout {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(writeln!(f, "(kicad_pcb (version {})", self.version));
        try!(writeln!(f, "  {}", self.setup));
        for element in &self.elements[..] {
            try!(writeln!(f, "  {}", element));
            try!(writeln!(f, ""));
        }
        writeln!(f, ")")
    }
}

impl fmt::Display for Element {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Element::Other(ref s) => write!(f, "{}", s),
            Element::Module(ref s) => write!(f, "{}", s),
            Element::Net(ref s) => write!(f, "{}", s),
            Element::NetClass(ref s) => write!(f, "{}", s),
        }
    }
}

impl fmt::Display for Net {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        if self.name.contains("(") || self.name.contains(")") || self.name.len()==0 {
            write!(f, "(net {} \"{}\")", self.num, self.name)
        } else {
            write!(f, "(net {} {})", self.num, self.name)
        }
    }
}
impl fmt::Display for NetClass {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(write!(f, "(net_class {} \"{}\" ", self.name, self.desc));
        try!(write!(f, "(clearance {}) ", self.clearance));
        try!(write!(f, "(trace_width {}) ", self.trace_width));
        try!(write!(f, "(via_dia {}) ", self.via_dia));
        try!(write!(f, "(via_drill {}) ", self.via_drill));
        try!(write!(f, "(uvia_dia {}) ", self.uvia_dia));
        try!(write!(f, "(uvia_drill {}) ", self.uvia_drill));
        for net in &self.nets {
            if net.contains("(") || net.contains(")") {
                try!(write!(f, "(add_net \"{}\")", net))
            } else {
                try!(write!(f, "(add_net {})", net))
            }
        }
        write!(f, ")")

    }
}

impl fmt::Display for Setup {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(write!(f, "(setup"));
        for (_,e) in &self.elements {
            try!(write!(f, " {}", e));
        }
        write!(f, ")")
    }
}

fn parse_version(e:&Sexp) -> ERes<i64> {
    let l = try!(e.slice_atom("version"));
    l[0].i()
}

fn parse_other(e:&Sexp) -> Element {
    let e2 = e.clone();
    Element::Other(e2)
}

fn parse_module(e:&Sexp) -> ERes<Element> {
    let e2 = e.clone();
    let m = try!(footprint::parse_module(e2));
    Ok(Element::Module(m))
}

fn parse_net(e:&Sexp) -> ERes<Element> {
    let l = try!(e.slice_atom("net"));
    let num = try!(l[0].i());
    let name = try!(l[1].string()).clone();
    Ok(Element::Net(Net { name:name, num:num }))
}

fn parse_net_class(e:&Sexp) -> ERes<Element> {
    fn parse(e:&Sexp, name:&str) -> ERes<f64> {
        let l = try!(e.slice_atom(name));
        l[0].f()
    }
    let l = try!(e.slice_atom("net_class"));
    let name = try!(l[0].string()).clone();
    let desc = try!(l[1].string()).clone();
    let mut clearance = 0.1524;
    let mut trace_width = 0.2032;
    let mut via_dia = 0.675;
    let mut via_drill = 0.25;
    let mut uvia_dia = 0.508;
    let mut uvia_drill = 0.127;
    let mut nets = vec![];
    for x in &l[2..] {
        let list_name = try!(x.list_name());
        let xn = &list_name[..];
        match xn {
            "add_net" => {
                let l1 = try!(x.slice_atom("add_net"));
                nets.push(try!(l1[0].string()).clone())
            },
            "clearance" => clearance = try!(parse(x, xn)),
            "trace_width" => trace_width = try!(parse(x, xn)),
            "via_dia" => via_dia = try!(parse(x, xn)),
            "via_drill" => via_drill = try!(parse(x, xn)),
            "uvia_dia" => uvia_dia = try!(parse(x, xn)),
            "uvia_drill" => uvia_drill = try!(parse(x, xn)),
            _ => return Err(format!("unknown net_class field {}", list_name))
        }
    }
    let net_class = NetClass {
        name:name, desc:desc, clearance:clearance, via_dia:via_dia,
        via_drill:via_drill, uvia_dia:uvia_dia, uvia_drill:uvia_drill,
        nets:nets, trace_width:trace_width,
    };
    Ok(Element::NetClass(net_class))
}

fn parse_setup(e:&Sexp) -> ERes<Setup> {
    let mut h = HashMap::new();
    for v in try!(e.slice_atom("setup")) {
        h.insert(try!(v.list_name()).clone(), v.clone());
    }
    let s = Setup { elements:h };
    Ok(s)
}

fn parse(s: &str) -> ERes<Layout> {
    let exp = match rustysexp::parse_str(s) {
        Ok(s) => s,
        Err(x) => return Err(format!("ParseError: {}", x)),
    };
    let l1 = try!(exp.slice_atom("kicad_pcb"));
    let mut layout = Layout::new();

    for ref e in l1 {
        match &try!(e.list_name())[..] {
            "version" => layout.version = try!(parse_version(e)),
            "module" => layout.elements.push(try!(parse_module(e))),
            "net" => layout.elements.push(try!(parse_net(e))),
            "net_class" => layout.elements.push(try!(parse_net_class(e))),
            "setup" => layout.setup = try!(parse_setup(e)),
            _ => layout.elements.push(parse_other(e)),
        }
    }
    Ok(layout)
}

pub fn parse_str(s: &str) -> ERes<Layout> {
    parse(s)
}

pub fn parse_file(filename: &PathBuf) -> ERes<Layout> {
    let name = filename.to_str().unwrap();
    let s = try!(match read_file(name) {
        Ok(s) => Ok(s),
        Err(x) => Err(format!("io error: {}", x))
    });
    parse(&s[..])
}
<|endoftext|>


<commit_before>use stack::Stack;

/// Represents a builtin function
#[derive(Debug, Clone, PartialEq)]
pub enum Builtin {
    Dot,
    Plus,
    Minus,
    Star,
    Slash,
    Abs,
    And,
    Or,
    Xor,
    Equals,
    LessThan,
    GreaterThan,
    LessEqual,
    GreaterEqual,
    Emit,
    Dup,
    Swap,
    Over,
    Rot,
    Tuck,
    Drop,
}

impl Builtin {
    pub fn call(&self, stack: &mut Stack) {
        macro_rules! stackexpr {
            ( $($aname:ident : $atype:ty),+ => $value:expr ) => {
                {
                    $(
                        let $aname: $atype = stack.pop();
                    )+
                    stack.push($value)
                }
            }
        }

        use self::Builtin::*;
        match *self {
            Dot => print!("{}", stack.pop::<i32>()),
            Plus => stackexpr!(n2: i32, n1: i32 => n1 + n2),
            Minus => stackexpr!(n2: i32, n1: i32 => n1 - n2),
            Star => stackexpr!(n2: i32, n1: i32 => n1 * n2),
            Slash => stackexpr!(n2: i32, n1: i32 => n1 / n2),
            Abs => stackexpr!(n: i32 => n.abs()),
            And => stackexpr!(n2: i32, n1: i32 => n1 & n2),
            Or => stackexpr!(n2: i32, n1: i32 => n1 | n2),
            Xor => stackexpr!(n2: i32, n1: i32 => n1 ^ n2),
            Equals => stackexpr!(n2: i32, n1: i32 => n1 == n2),
            LessThan => stackexpr!(n2: i32, n1: i32 => n1 < n2),
            GreaterThan => stackexpr!(n2: i32, n1: i32 => n1 > n2),
            LessEqual => stackexpr!(n2: i32, n1: i32 => n1 <= n2),
            GreaterEqual => stackexpr!(n2: i32, n1: i32 => n1 >= n2),
            Emit => print!("{}", stack.pop::<char>()),
            Dup => {
                let n: i32 = stack.peak();
                stack.push(n);
            }
            Swap => {
                let n2: i32 = stack.pop();
                let n1: i32 = stack.pop();
                stack.push(n2);
                stack.push(n1);
            }
            Over => {
                let n2: i32 = stack.pop();
                let n1: i32 = stack.pop();
                stack.push(n1);
                stack.push(n2);
                stack.push(n1);
            }
            Rot => {
                let n3: i32 = stack.pop();
                let n2: i32 = stack.pop();
                let n1: i32 = stack.pop();
                stack.push(n1);
                stack.push(n3);
                stack.push(n2);
            }
            Tuck => {
                let n2: i32 = stack.pop();
                let n1: i32 = stack.pop();
                stack.push(n2);
                stack.push(n1);
                stack.push(n2);
            }
            Drop => {
                stack.pop::<i32>();
            }
        }
    }
}
<commit_msg>Make stackexpr! use closure like syntax<commit_after>use stack::Stack;

/// Represents a builtin function
#[derive(Debug, Clone, PartialEq)]
pub enum Builtin {
    Dot,
    Plus,
    Minus,
    Star,
    Slash,
    Abs,
    And,
    Or,
    Xor,
    Equals,
    LessThan,
    GreaterThan,
    LessEqual,
    GreaterEqual,
    Emit,
    Dup,
    Swap,
    Over,
    Rot,
    Tuck,
    Drop,
}

impl Builtin {
    pub fn call(&self, stack: &mut Stack) {
        macro_rules! stackexpr {
            ( | $($aname:ident : $atype:ty),+ | $value:expr ) => {
                {
                    $(
                        let $aname: $atype = stack.pop();
                    )+
                    stack.push($value)
                }
            }
        }

        use self::Builtin::*;
        match *self {
            Dot => print!("{}", stack.pop::<i32>()),
            Plus => stackexpr!(|n2: i32, n1: i32| n1 + n2),
            Minus => stackexpr!(|n2: i32, n1: i32| n1 - n2),
            Star => stackexpr!(|n2: i32, n1: i32| n1 * n2),
            Slash => stackexpr!(|n2: i32, n1: i32| n1 / n2),
            Abs => stackexpr!(|n: i32| n.abs()),
            And => stackexpr!(|n2: i32, n1: i32| n1 & n2),
            Or => stackexpr!(|n2: i32, n1: i32| n1 | n2),
            Xor => stackexpr!(|n2: i32, n1: i32| n1 ^ n2),
            Equals => stackexpr!(|n2: i32, n1: i32| n1 == n2),
            LessThan => stackexpr!(|n2: i32, n1: i32| n1 < n2),
            GreaterThan => stackexpr!(|n2: i32, n1: i32| n1 > n2),
            LessEqual => stackexpr!(|n2: i32, n1: i32| n1 <= n2),
            GreaterEqual => stackexpr!(|n2: i32, n1: i32| n1 >= n2),
            Emit => print!("{}", stack.pop::<char>()),
            Dup => {
                let n: i32 = stack.peak();
                stack.push(n);
            }
            Swap => {
                let n2: i32 = stack.pop();
                let n1: i32 = stack.pop();
                stack.push(n2);
                stack.push(n1);
            }
            Over => {
                let n2: i32 = stack.pop();
                let n1: i32 = stack.pop();
                stack.push(n1);
                stack.push(n2);
                stack.push(n1);
            }
            Rot => {
                let n3: i32 = stack.pop();
                let n2: i32 = stack.pop();
                let n1: i32 = stack.pop();
                stack.push(n1);
                stack.push(n3);
                stack.push(n2);
            }
            Tuck => {
                let n2: i32 = stack.pop();
                let n1: i32 = stack.pop();
                stack.push(n2);
                stack.push(n1);
                stack.push(n2);
            }
            Drop => {
                stack.pop::<i32>();
            }
        }
    }
}
<|endoftext|>