<commit_before>// Crates
extern crate serial;
extern crate time;
extern crate rustc_serialize;

// Modules
mod lib;
use std::thread;
use std::env;
use time::Duration;
use std::io::prelude::*;
use serial::prelude::*;
use rustc_serialize::json;

// Port Settings
const SETTINGS: serial::PortSettings = serial::PortSettings {
    baud_rate:    serial::Baud9600,
    char_size:    serial::Bits8,
    parity:       serial::ParityNone,
    stop_bits:    serial::Stop1,
    flow_control: serial::FlowNone
};

// Main
fn main() {
    for arg in env::args_os().skip(1) { // Get arguments
        println!("opening port: {:?}", arg);
        let mut port = serial::open(&arg).unwrap();
        thread::sleep_ms(1000);
        // Basic
        loop {
            interact(&mut port).unwrap(); // interact with port
        }
    }
}

// Interact with serial port
fn interact<T: SerialPort>(port: &mut T) -> serial::Result<()> {
    let in_buf: Vec<u8> = (0..15).collect();
    let mut out_buf: Vec<u8> = (0..17).collect();
    let mut t1 = time::precise_time_ns();
    let mut t2 = time::precise_time_ns();
    // Set configuration
    try!(port.configure(&SETTINGS));
    try!(port.set_timeout(Duration::seconds(3)));
    thread::sleep_ms(350);

    // Write value
    println!("[WARN] writing to device...");
    t2 = time::precise_time_ns();
    try!(port.write(&in_buf[..]));
    println!("\tok, {} ns", (time::precise_time_ns() - t2));

    // Read responses
    println!("[WARN] reading from device...");
    t2 = time::precise_time_ns();
    try!(port.read(&mut out_buf[..]));
    println!("\tok, {} ns", (time::precise_time_ns() - t2));

    // As JSON obj
    println!("[WARN] parsing to JSON...");
    let s = String::from_utf8_lossy(&out_buf);
    println!("\tstring: {}", s);
    let optb = json::Json::from_str("{\"foo\":null,\"bar\":null}").unwrap();
    let d = json::Json::from_str(&s).unwrap_or(optb); // if fails, default None obj
    println!("\tdata: {}", d);
    println!("\tis object: {}", d.is_object());
    let obj = d.as_object().unwrap();

    // Get 'foo'
    let foo = obj.get("bar").unwrap();
    println!("\tis foo u64? {}", foo.is_u64());

    // Iterate through object
    for (key, value) in obj.iter() {
        println!("\t{}: {}", key, match *value {
            json::Json::U64(v) => format!("{} (u64)", v),
            json::Json::Null => format!("null"),
            json::Json::String(ref v) => format!("{} (string)", v),
            _ => format!("other")
        });
    }
    t2 = time::precise_time_ns();
    println!("\tdone, {} Hz", 1000000000 / (t2 - t1));
    return Ok(()); // return Result type
}
<commit_msg>updates<commit_after>// Crates
extern crate serial;
extern crate time;
extern crate rustc_serialize;

// Modules
mod lib;
use std::thread;
use std::env;
use time::Duration;
use std::io::prelude::*;
use serial::prelude::*;
use rustc_serialize::json;

// Port Settings
const SETTINGS: serial::PortSettings = serial::PortSettings {
    baud_rate:    serial::Baud9600,
    char_size:    serial::Bits8,
    parity:       serial::ParityNone,
    stop_bits:    serial::Stop1,
    flow_control: serial::FlowNone
};

// Main
fn main() {
    for arg in env::args_os().skip(1) { // Get arguments
        println!("opening port: {:?}", arg);
        let mut port = serial::open(&arg).unwrap();
        thread::sleep_ms(1000);
        // Basic
        loop {
            interact(&mut port).unwrap(); // interact with port
        }
    }
}

// Interact with serial port
fn interact<T: SerialPort>(port: &mut T) -> serial::Result<()> {
    let in_buf: Vec<u8> = (0..15).collect();
    let mut out_buf: Vec<u8> = (0..17).collect();
    let mut t1 = time::precise_time_ns();
    let mut t2 = time::precise_time_ns();
    // Set configuration
    try!(port.configure(&SETTINGS));
    try!(port.set_timeout(Duration::seconds(3)));
    thread::sleep_ms(350); // fails when slower

    // Write value
    println!("[WARN] writing to device...");
    t2 = time::precise_time_ns();
    try!(port.write(&in_buf[..]));
    println!("\tok, {} ns", (time::precise_time_ns() - t2));

    // Read responses
    println!("[WARN] reading from device...");
    t2 = time::precise_time_ns();
    try!(port.read(&mut out_buf[..]));
    println!("\tok, {} ns", (time::precise_time_ns() - t2));

    // As JSON obj
    println!("[WARN] parsing to JSON...");
    let s = String::from_utf8_lossy(&out_buf);
    println!("\tstring: {}", s);
    let optb = json::Json::from_str("{\"foo\":null,\"bar\":null}").unwrap();
    let d = json::Json::from_str(&s).unwrap_or(optb); // if fails, default None obj
    println!("\tdata: {}", d);
    println!("\tis object: {}", d.is_object());
    let obj = d.as_object().unwrap();

    // Get 'foo'
    let foo = obj.get("bar").unwrap();
    println!("\tis foo u64? {}", foo.is_u64());

    // Iterate through object
    for (key, value) in obj.iter() {
        println!("\t{}: {}", key, match *value {
            json::Json::U64(v) => format!("{} (u64)", v),
            json::Json::Null => format!("null"),
            json::Json::String(ref v) => format!("{} (string)", v),
            _ => format!("other")
        });
    }
    t2 = time::precise_time_ns();
    println!("\tdone, {} Hz", 1000000000 / (t2 - t1));
    return Ok(()); // return Result type
}
<|endoftext|>


<commit_before>struct Coordinates {
    x: i32,
    y: i32,
}

fn main() {
    let origin = Coordinates { x: 0, y: 0 };

    println!("X is {} and Y is {}", origin.x + 1, origin.y + 90);

    let mut v = vec![1, 2, 3, 4, 5];

    for i in &v {
        println!("A reference to {}", i);
    }

    for i in &mut v {
        println!("A mutable reference to {}", i);
    }

    for i in v {
        println!("Take ownership of the vector and its element {}", i);
    }

    println!("X is {} and Y is {}", move_right(origin.x), move_up(origin.y));
    println!("X is {} and Y is {}", move_right(origin.x), move_up(origin.y));
}

fn move_up(y_cord: i32) -> i32 {
    y_cord - 1
}

fn move_right(x_cord: i32) -> i32 {
    x_cord + 1
}
<commit_msg>clean up - still stuck<commit_after>struct Coordinates {
    x: i32,
    y: i32,
}

fn main() {
    let origin = Coordinates { x: 0, y: 0 };

    println!("X is {} and Y is {}", origin.x + 1, origin.y + 90);

    let mut v = vec![1, 2];

    for i in &v {
        println!("A reference to {}", i);
    }

    for i in &mut v {
        println!("A mutable reference to {}", i);
    }

    for i in v {
        println!("Take ownership of the vector and its element {}", i);
    }

    println!("X is {} and Y is {}", move_right(origin.x), move_up(origin.y));
    println!("X is {} and Y is {}", move_right(origin.x), move_up(origin.y));
}

fn move_up(y_cord: i32) -> i32 {
    y_cord - 1
}

fn move_right(x_cord: i32) -> i32 {
    x_cord + 1
}
<|endoftext|>


<commit_before>
#[derive(Debug, Clone)]
enum Token {
    Integer(i32),
    Star, Slash,
    Plus, Minus,
    LParen, RParen
}

#[derive(Debug)]
struct Lexer {
    source: Vec<char>,
    position: usize,
}

impl Lexer {
    fn new(source: String) -> Lexer {
        Lexer {
            source: source.chars().collect(),
            position: 0,
        }
    }

    fn done(&self) -> bool {
        self.position >= self.source.len()
    }

    fn advance(&mut self) {
        self.position += 1;
    }

    fn string(&self, start: usize, end: usize) -> String {
        (&self.source[start..end]).to_vec().into_iter().collect()
    }

    fn next_char_is<P>(&self, pred: P) -> bool where P: Fn(char) -> bool {
        if self.position + 1 < self.source.len() {
            pred(self.source[self.position + 1])
        } else {
            false
        }
    }

    fn char(&mut self) -> Option<char> {
        if !self.done() {
            Some(self.source[self.position])
        } else {
            None
        }
    }

    fn skip_whitespace(&mut self) {
        while !self.done() && self.source[self.position].is_whitespace() {
            self.advance();
        }
    }

    fn scan_integer(&mut self) -> Token {
        let start = self.position;
        while self.next_char_is(|c| c.is_digit(10)) {
            self.advance();
        }
        Token::Integer(self.string(start, self.position + 1).parse::<i32>().unwrap())
    }

    fn get_next_token(&mut self) -> Option<Token> {
        self.skip_whitespace();
        if self.done() { return None; }
        let token = match self.char().unwrap() {
            '0' ... '9' => self.scan_integer(),
            '+'         => Token::Plus,
            '-'         => Token::Minus,
            '*'         => Token::Star,
            '/'         => Token::Slash,
            '('         => Token::LParen,
            ')'         => Token::RParen,
             c          => panic!("Error: unexpected character: '{}'.", c),
        };
        self.advance();
        Some(token)
    }
}

#[derive(Debug)]
enum AST {
    BinOp { lhs: Box<AST>, op: Token, rhs: Box<AST> },
    Num (i32),
}

#[derive(Debug)]
struct Parser {
    lexer: Lexer,
    current_token: Option<Token>,
}

impl Parser {
    fn new(source: String) -> Parser {
        let mut l = Lexer::new(source);
        let t = l.get_next_token();
        Parser {
            lexer: l,
            current_token: t,
        }
    }

    fn advance(&mut self) {
        self.current_token = self.lexer.get_next_token();
    }

    fn factor(&mut self) -> AST {
        let ast = match self.current_token {
            Some(Token::Integer(i)) => AST::Num(i),
            Some(Token::LParen) => {
                self.advance();
                let paren_ast = self.expression();
                match self.current_token {
                    Some(Token::RParen) => paren_ast,
                    ref t => panic!("Error: expected an RParen found a {:?}", t),
                }
            }
            ref t => panic!("Error: expected an integer and found a '{:?}'.", t),
        };
        self.advance();
        ast
    }

    fn term(&mut self) -> AST {
        let mut ast = self.factor();

        loop {
            match self.current_token {
                Some(Token::Star)  => (),
                Some(Token::Slash) => (),
                _ => break,
            }
            let token = self.current_token.clone().unwrap();
            self.advance();
            ast = AST::BinOp {
                lhs: Box::new(ast), op: token, rhs: Box::new(self.factor())
            };
        }
        ast
    }

    fn expression(&mut self) -> AST {
        let mut ast = self.term();

        loop {
            match self.current_token {
                Some(Token::Plus)  => (),
                Some(Token::Minus) => (),
                _ => break,
            }
            let token = self.current_token.clone().unwrap();
            self.advance();
            ast = AST::BinOp {
                lhs: Box::new(ast), op: token, rhs: Box::new(self.term())
            };
        }
        ast
    }
}

#[derive(Debug)]
struct Interpreter {
    parser: Parser
}

impl Interpreter {
    fn new(source: String) -> Interpreter {
        Interpreter { parser: Parser::new(source) }
    }

    fn visit(&self, ast: AST) -> i32 {
        match ast {
            AST::BinOp{lhs, op, rhs} => match op {
                Token::Plus  => self.visit(*lhs) + self.visit(*rhs),
                Token::Minus => self.visit(*lhs) - self.visit(*rhs),
                Token::Star  => self.visit(*lhs) * self.visit(*rhs),
                Token::Slash => self.visit(*lhs) / self.visit(*rhs),
                _ => panic!("Error: expected arithmetic operator and found '{:?}'.", op),
            },
            AST::Num(i) => i,
        }
    }

    fn interpret(&mut self) -> i32 {
        let ast = self.parser.expression();
        self.visit(ast)
    }
}

macro_rules! prompt(
    ($($arg:tt)*) => { {
        print!($($arg)*);
        stdout().flush().expect("Could not flush stdout");
    } }
);

fn main() {
    use std::io::{BufRead, stdin, stdout, Write};

    prompt!("calc> ");
    let stdin = stdin();
    for line in stdin.lock().lines() {
        let mut interpreter = Interpreter::new(line.unwrap());
        let result = interpreter.interpret();
        println!("{:#?}", result);
        prompt!("calc> ");
    }
}
<commit_msg>Finished Part 8.<commit_after>// 5 - - - + - (3 + 4) - +2
// (1 + (3+4) - 1 - 14) * 7- +2
#[derive(Debug, Clone)]
enum Token {
    Integer(i32),
    Star, Slash,
    Plus, Minus,
    LParen, RParen
}

#[derive(Debug)]
struct Lexer {
    source: Vec<char>,
    position: usize,
}

impl Lexer {
    fn new(source: String) -> Lexer {
        Lexer {
            source: source.chars().collect(),
            position: 0,
        }
    }

    fn done(&self) -> bool {
        self.position >= self.source.len()
    }

    fn advance(&mut self) {
        self.position += 1;
    }

    fn string(&self, start: usize, end: usize) -> String {
        (&self.source[start..end]).to_vec().into_iter().collect()
    }

    fn next_char_is<P>(&self, pred: P) -> bool where P: Fn(char) -> bool {
        if self.position + 1 < self.source.len() {
            pred(self.source[self.position + 1])
        } else {
            false
        }
    }

    fn char(&mut self) -> Option<char> {
        if !self.done() {
            Some(self.source[self.position])
        } else {
            None
        }
    }

    fn skip_whitespace(&mut self) {
        while !self.done() && self.source[self.position].is_whitespace() {
            self.advance();
        }
    }

    fn scan_integer(&mut self) -> Token {
        let start = self.position;
        while self.next_char_is(|c| c.is_digit(10)) {
            self.advance();
        }
        Token::Integer(self.string(start, self.position + 1).parse::<i32>().unwrap())
    }

    fn get_next_token(&mut self) -> Option<Token> {
        self.skip_whitespace();
        if self.done() { return None; }
        let token = match self.char().unwrap() {
            '0' ... '9' => self.scan_integer(),
            '+'         => Token::Plus,
            '-'         => Token::Minus,
            '*'         => Token::Star,
            '/'         => Token::Slash,
            '('         => Token::LParen,
            ')'         => Token::RParen,
             c          => panic!("Error: unexpected character: '{}'.", c),
        };
        self.advance();
        Some(token)
    }
}

#[derive(Debug)]
enum AST {
    BinOp { lhs: Box<AST>, op: Token, rhs: Box<AST> },
    UnaryOp { op: Token, rhs: Box<AST> },
    Num (i32),
}

/// expression : term ((Plus | Minus) term)*
/// term       : factor ((Star | Slash) factor)*
/// factor     : (Plus | Minus) factor | Integer | LParen expression RParen

#[derive(Debug)]
struct Parser {
    lexer: Lexer,
    current_token: Option<Token>,
}

impl Parser {
    fn new(source: String) -> Parser {
        let mut l = Lexer::new(source);
        let t = l.get_next_token();
        Parser {
            lexer: l,
            current_token: t,
        }
    }

    fn advance(&mut self) {
        self.current_token = self.lexer.get_next_token();
    }

    ///
    /// factor : (Plus | Minus) factor | Integer | LParen expression RParen
    ///
    fn factor(&mut self) -> AST {
        match self.current_token {
            Some(Token::Plus) | Some(Token::Minus) => {
                let token = self.current_token.clone().unwrap();
                self.advance();
                AST::UnaryOp{op: token, rhs: Box::new(self.factor())}
            },

            Some(Token::Integer(i)) => {
                self.advance();
                AST::Num(i)
            },

            Some(Token::LParen) => {
                self.advance();
                let paren_ast = self.expression();
                match self.current_token {
                    Some(Token::RParen) => { self.advance(); paren_ast },
                    ref t => panic!("Error: expected an RParen found a {:?}", t),
                }
            }

            ref t => panic!("Error: expected an integer and found a '{:?}'.", t),
        }
    }

    ///
    /// factor ((Star | Slash) factor)*
    ///
    fn term(&mut self) -> AST {
        let mut ast = self.factor();

        loop {
            match self.current_token {
                Some(Token::Star)  => (),
                Some(Token::Slash) => (),
                _ => break,
            }
            let token = self.current_token.clone().unwrap();
            self.advance();
            ast = AST::BinOp {
                lhs: Box::new(ast), op: token, rhs: Box::new(self.factor())
            };
        }
        ast
    }

    ///
    /// term ((Plus | Minus) term)*
    ///
    fn expression(&mut self) -> AST {
        let mut ast = self.term();

        loop {
            match self.current_token {
                Some(Token::Plus)  => (),
                Some(Token::Minus) => (),
                _ => break,
            }
            let token = self.current_token.clone().unwrap();
            self.advance();
            ast = AST::BinOp {
                lhs: Box::new(ast), op: token, rhs: Box::new(self.term())
            };
        }
        ast
    }
}

#[derive(Debug)]
struct Interpreter {
    parser: Parser
}

impl Interpreter {
    fn new(source: String) -> Interpreter {
        Interpreter { parser: Parser::new(source) }
    }

    fn visit(&self, ast: AST) -> i32 {
        match ast {
            AST::BinOp{lhs, op, rhs} => match op {
                Token::Plus  => self.visit(*lhs) + self.visit(*rhs),
                Token::Minus => self.visit(*lhs) - self.visit(*rhs),
                Token::Star  => self.visit(*lhs) * self.visit(*rhs),
                Token::Slash => self.visit(*lhs) / self.visit(*rhs),
                _ => panic!("Error: expected arithmetic operator and found '{:?}'.", op),
            },
            AST::UnaryOp{op, rhs} => match op {
                Token::Plus  => self.visit(*rhs),
                Token::Minus => -self.visit(*rhs),
                _ => panic!("Error: expected a '+' or '-' and found '{:?}'.", op),
            },
            AST::Num(i) => i,
        }
    }

    fn interpret(&mut self) -> i32 {
        let ast = self.parser.expression();
        self.visit(ast)
    }
}

macro_rules! prompt(
    ($($arg:tt)*) => { {
        print!($($arg)*);
        stdout().flush().expect("Could not flush stdout");
    } }
);

fn main() {
    use std::io::{BufRead, stdin, stdout, Write};

    prompt!("calc> ");
    let stdin = stdin();
    for line in stdin.lock().lines() {
        let mut interpreter = Interpreter::new(line.unwrap());
        let result = interpreter.interpret();
        println!("{:#?}", result);
        prompt!("calc> ");
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(test, allow(dead_code))]

extern crate arguments;
extern crate sqlite;

use sqlite::Database;
use std::fmt::Display;
use std::path::Path;

const CORE_LIKE: &'static str = "core%_area";
const L3_LIKE: &'static str = "l3%_area";

const USAGE: &'static str = "
Usage: planner [options]

Options:
    --database <path>        SQLite3 database (required).
    --table <name>           Table containing area estimates (required).
    --cores <number>         Number of cores (required).
    --format (3d-ice|svg)    Output format [default: 3d-ice].

    --help                   Display this message.
";

macro_rules! ok(
    ($result:expr) => (match $result {
        Ok(result) => result,
        Err(error) => raise!(error),
    });
);

macro_rules! raise(
    ($error:expr) => (return Err(Box::new($error)));
    ($($arg:tt)*) => (raise!(format!($($arg)*)));
);

mod format;
mod layout;

pub type Error = Box<Display>;
pub type Result<T> = std::result::Result<T, Error>;

fn main() {
    start().unwrap_or_else(|error| fail(error));
}

fn start() -> Result<()> {
    use format::Format;
    use layout::Layout;

    let arguments = ok!(arguments::parse(std::env::args()));

    if arguments.get::<bool>("help").unwrap_or(false) {
        help();
    }

    let database = match arguments.get::<String>("database") {
        Some(ref database) => ok!(sqlite::open(&Path::new(database))),
        _ => raise!("a database filename is required"),
    };
    let (core_area, l3_area) = match arguments.get::<String>("table") {
        Some(ref table) => {
            (ok!(find(&database, table, CORE_LIKE)), ok!(find(&database, table, L3_LIKE)))
        },
        _ => raise!("a table name is required"),
    };
    let core_count = match arguments.get::<usize>("cores") {
        Some(core_count) if core_count > 0 => core_count,
        _ => raise!("a number of cores is required"),
    };

    let spec = layout::Spec {
        core_count: core_count,
        core_area: core_area,
        l3_area: l3_area,
    };

    let layout = layout::Tiles;
    let format = match &arguments.get::<String>("format").unwrap_or("3d-ice".to_string())[..] {
        "svg" => Box::new(format::SVG) as Box<Format>,
        "3d-ice" => Box::new(format::ThreeDICE) as Box<Format>,
        _ => raise!("the output format is unknown"),
    };

    format.print(&ok!(layout.construct(&spec)), &mut std::io::stdout())
}

fn find(database: &Database, table: &str, like: &str) -> Result<f64> {
    use sqlite::State;
    let mut statement = ok!(database.prepare(&format!(
        "SELECT name, value FROM `{}` WHERE name LIKE '{}' LIMIT 1;", table, like,
    )));
    Ok(match ok!(statement.step()) {
        State::Row => ok!(statement.column::<f64>(0 + 1)),
        _ => raise!("failed to find a required value in the table"),
    })
}

fn fail(error: Error) -> ! {
    use std::io::{stderr, Write};
    stderr().write_all(format!("Error: {}.\n", &*error).as_bytes()).unwrap();
    std::process::exit(1);
}

fn help() -> ! {
    println!("{}", USAGE.trim());
    std::process::exit(0);
}
<commit_msg>Check if the database exists<commit_after>#![cfg_attr(test, allow(dead_code))]

extern crate arguments;
extern crate sqlite;

use sqlite::Database;
use std::fmt::Display;
use std::path::Path;

const CORE_LIKE: &'static str = "core%_area";
const L3_LIKE: &'static str = "l3%_area";

const USAGE: &'static str = "
Usage: planner [options]

Options:
    --database <path>        SQLite3 database (required).
    --table <name>           Table containing area estimates (required).
    --cores <number>         Number of cores (required).
    --format (3d-ice|svg)    Output format [default: 3d-ice].

    --help                   Display this message.
";

macro_rules! ok(
    ($result:expr) => (match $result {
        Ok(result) => result,
        Err(error) => raise!(error),
    });
);

macro_rules! raise(
    ($error:expr) => (return Err(Box::new($error)));
    ($($arg:tt)*) => (raise!(format!($($arg)*)));
);

mod format;
mod layout;

pub type Error = Box<Display>;
pub type Result<T> = std::result::Result<T, Error>;

fn main() {
    start().unwrap_or_else(|error| fail(error));
}

fn start() -> Result<()> {
    use format::Format;
    use layout::Layout;

    let arguments = ok!(arguments::parse(std::env::args()));

    if arguments.get::<bool>("help").unwrap_or(false) {
        help();
    }

    let database = match arguments.get::<String>("database") {
        Some(ref database) => {
            let path = Path::new(database);
            if std::fs::metadata(path).is_err() {
                raise!("the database does not exist");
            }
            ok!(sqlite::open(path))
        },
        _ => raise!("a database filename is required"),
    };
    let (core_area, l3_area) = match arguments.get::<String>("table") {
        Some(ref table) => {
            (ok!(find(&database, table, CORE_LIKE)), ok!(find(&database, table, L3_LIKE)))
        },
        _ => raise!("a table name is required"),
    };
    let core_count = match arguments.get::<usize>("cores") {
        Some(core_count) if core_count > 0 => core_count,
        _ => raise!("a number of cores is required"),
    };

    let spec = layout::Spec {
        core_count: core_count,
        core_area: core_area,
        l3_area: l3_area,
    };

    let layout = layout::Tiles;
    let format = match &arguments.get::<String>("format").unwrap_or("3d-ice".to_string())[..] {
        "svg" => Box::new(format::SVG) as Box<Format>,
        "3d-ice" => Box::new(format::ThreeDICE) as Box<Format>,
        _ => raise!("the output format is unknown"),
    };

    format.print(&ok!(layout.construct(&spec)), &mut std::io::stdout())
}

fn find(database: &Database, table: &str, like: &str) -> Result<f64> {
    use sqlite::State;
    let mut statement = ok!(database.prepare(&format!(
        "SELECT name, value FROM `{}` WHERE name LIKE '{}' LIMIT 1;", table, like,
    )));
    Ok(match ok!(statement.step()) {
        State::Row => ok!(statement.column::<f64>(0 + 1)),
        _ => raise!("failed to find a required value in the table"),
    })
}

fn help() -> ! {
    println!("{}", USAGE.trim());
    std::process::exit(0);
}

fn fail(error: Error) -> ! {
    use std::io::{stderr, Write};
    stderr().write_all(format!("Error: {}.\n", &*error).as_bytes()).unwrap();
    std::process::exit(1);
}
<|endoftext|>


<commit_before>#![feature(phase)]
extern crate serialize;
#[phase(plugin)] extern crate docopt_macros;
extern crate docopt;
extern crate graphviz;
extern crate toml;

use docopt::{Error, FlagParser};
use graphviz as dot;
use std::io::File;
use std::str;

docopt!(Flags, "
Usage: cargo dot [options]
       cargo dot --help

Options:
    -h, --help         Show this message
    -V, --version      Print version info and exit
    --lock-file=FILE   Specify location of input file, default \"Cargo.lock\"
")

fn main() {
    let config = docopt::Config { version: Some("0.1.0".to_string()) , ..docopt::DEFAULT_CONFIG };
    let flags: Flags = FlagParser::parse_conf(config).unwrap_or_else(|e| e.exit());
    println!("{}", flags);
    let lock_file = if flags.flag_lock_file.is_empty() { "Cargo.lock".to_string() } else { flags.flag_lock_file };

    let (name, direct_deps, indirect_deps) = read_cargo_lock(lock_file.as_slice());
    let mut nodes = vec!(name).append(direct_deps.as_slice());
    let mut edges = range(1, nodes.len()).map(|n| (0, n)).collect();
    add_deps(&mut nodes, &mut edges, indirect_deps);

    let graph = Graph { nodes: nodes, edges: edges };
    let mut f    = File::create(&Path::new("Cargo.dot"));

    graph.render_to(&mut f);
}

fn read_cargo_lock(file_name: &str) -> (String, Vec<String>, Vec<(String, Vec<String>)>) {
    let toml = read_toml(file_name);
    let root = toml.find(&"root".to_string()).unwrap()
                   .as_table().unwrap();
    let name = root.find(&"name".to_string()).unwrap()
                   .as_str().unwrap().to_string();
    let direct_deps = extract_deps(root);
    let all_deps = toml.find(&"package".to_string()).unwrap()
                       .as_slice().unwrap().iter().map(other_deps).collect();
    (name, direct_deps, all_deps)
}

fn extract_deps(v: &toml::Table) -> Vec<String> {
    match v.find(&"dependencies".to_string()) {
        None     => vec!(),
        Some(ds) => ds.as_slice().unwrap().iter()
                      .map(|v| parse_dep(v.as_str().unwrap())).collect()
    }
}

fn other_deps(v: &toml::Value) -> (String, Vec<String>) {
    let t = v.as_table().unwrap();
    let name = t.find(&"name".to_string()).unwrap()
                .as_str().unwrap().to_string();
    let deps = extract_deps(t);
    (name, deps)
}

fn read_toml(file_name: &str) -> toml::Table {
    let toml_str = File::open(&Path::new(file_name)).read_to_string().unwrap();
    toml::Parser::new(toml_str.as_slice()).parse().unwrap()

}

fn parse_dep(s: &str) -> String {
    s.chars().take_while(|&a| a != ' ').collect()
}

fn add_deps(nodes: &mut Vec<String>, edges: &mut Vec<(uint, uint)>, deps: Vec<(String, Vec<String>)>) {
    for (crat, crate_deps) in deps.move_iter() {
        let idl = add_or_find(nodes, crat);
        for dep in crate_deps.move_iter() {
            let idr = add_or_find(nodes, dep);
            edges.push((idl, idr));
        }
    }
}

fn add_or_find(nodes: &mut Vec<String>, new: String) -> uint {
    for i in range(0, nodes.len()) {
        let ref s = (*nodes)[i];
        if *s == new {
            return i
        }
    }
    nodes.push(new);
    nodes.len() - 1
}

type Nd = uint;
type Ed<'a> = &'a (uint, uint);
struct Graph { nodes: Vec<String>,
               edges: Vec<(uint,uint)>,
             }

impl Graph {
    fn render_to<W:Writer>(self, output: &mut W) {
        dot::render(&self, output).unwrap()
    }
}

impl<'a> dot::Labeller<'a, Nd, Ed<'a>> for Graph {
    fn graph_id(&'a self) -> dot::Id<'a> { dot::Id::new("example3") }
    fn node_id(&'a self, n: &Nd) -> dot::Id {
        dot::Id::new(format!("N{:u}", *n))
    }
    fn node_label<'a>(&'a self, i: &Nd) -> dot::LabelText<'a> {
        dot::LabelStr(str::Slice(self.nodes[*i].as_slice()))
    }
}

impl<'a> dot::GraphWalk<'a, Nd, Ed<'a>> for Graph {
    fn nodes(&'a self) -> dot::Nodes<'a,Nd> {
        range(0, self.nodes.len()).collect()
    }
    fn edges(&'a self) -> dot::Edges<'a,Ed<'a>> {
        self.edges.iter().collect()
    }
    fn source(&self, e: &Ed) -> Nd { let &(s,_) = *e; s }
    fn target(&self, e: &Ed) -> Nd { let &(_,t) = *e; t }
}
<commit_msg>Add dot-file arg<commit_after>#![feature(phase)]
extern crate serialize;
#[phase(plugin)] extern crate docopt_macros;
extern crate docopt;
extern crate graphviz;
extern crate toml;

use docopt::{Error, FlagParser};
use graphviz as dot;
use std::io::File;
use std::str;

docopt!(Flags, "
Usage: cargo dot [options]
       cargo dot --help

Options:
    -h, --help         Show this message
    -V, --version      Print version info and exit
    --lock-file=FILE   Specify location of input file, default \"Cargo.lock\"
    --dot-file=FILE    Specify location of output file, default \"Cargo.dot\"
")

fn main() {
    let config = docopt::Config { version: Some("0.1.0".to_string()) , ..docopt::DEFAULT_CONFIG };
    let flags: Flags = FlagParser::parse_conf(config).unwrap_or_else(|e| e.exit());
    let lock_file = unless_empty(flags.flag_lock_file, "Cargo.lock".to_string());
    let dot_file  = unless_empty(flags.flag_dot_file, "Cargo.dot".to_string());

    let (name, direct_deps, indirect_deps) = read_cargo_lock(lock_file.as_slice());
    let mut nodes = vec!(name).append(direct_deps.as_slice());
    let mut edges = range(1, nodes.len()).map(|n| (0, n)).collect();
    add_deps(&mut nodes, &mut edges, indirect_deps);

    let graph = Graph { nodes: nodes, edges: edges };
    let mut f = File::create(&Path::new(dot_file));

    graph.render_to(&mut f);
}

fn unless_empty(s: String, default: String) -> String {
    if s.is_empty() {
        default
    } else {
        s
    }
}

fn read_cargo_lock(file_name: &str) -> (String, Vec<String>, Vec<(String, Vec<String>)>) {
    let toml = read_toml(file_name);
    let root = toml.find(&"root".to_string()).unwrap()
                   .as_table().unwrap();
    let name = root.find(&"name".to_string()).unwrap()
                   .as_str().unwrap().to_string();
    let direct_deps = extract_deps(root);
    let all_deps = toml.find(&"package".to_string()).unwrap()
                       .as_slice().unwrap().iter().map(other_deps).collect();
    (name, direct_deps, all_deps)
}

fn extract_deps(v: &toml::Table) -> Vec<String> {
    match v.find(&"dependencies".to_string()) {
        None     => vec!(),
        Some(ds) => ds.as_slice().unwrap().iter()
                      .map(|v| parse_dep(v.as_str().unwrap())).collect()
    }
}

fn other_deps(v: &toml::Value) -> (String, Vec<String>) {
    let t = v.as_table().unwrap();
    let name = t.find(&"name".to_string()).unwrap()
                .as_str().unwrap().to_string();
    let deps = extract_deps(t);
    (name, deps)
}

fn read_toml(file_name: &str) -> toml::Table {
    let toml_str = File::open(&Path::new(file_name)).read_to_string().unwrap();
    toml::Parser::new(toml_str.as_slice()).parse().unwrap()

}

fn parse_dep(s: &str) -> String {
    s.chars().take_while(|&a| a != ' ').collect()
}

fn add_deps(nodes: &mut Vec<String>, edges: &mut Vec<(uint, uint)>, deps: Vec<(String, Vec<String>)>) {
    for (crat, crate_deps) in deps.move_iter() {
        let idl = add_or_find(nodes, crat);
        for dep in crate_deps.move_iter() {
            let idr = add_or_find(nodes, dep);
            edges.push((idl, idr));
        }
    }
}

fn add_or_find(nodes: &mut Vec<String>, new: String) -> uint {
    for i in range(0, nodes.len()) {
        let ref s = (*nodes)[i];
        if *s == new {
            return i
        }
    }
    nodes.push(new);
    nodes.len() - 1
}

type Nd = uint;
type Ed<'a> = &'a (uint, uint);
struct Graph { nodes: Vec<String>,
               edges: Vec<(uint,uint)>,
             }

impl Graph {
    fn render_to<W:Writer>(self, output: &mut W) {
        dot::render(&self, output).unwrap()
    }
}

impl<'a> dot::Labeller<'a, Nd, Ed<'a>> for Graph {
    fn graph_id(&'a self) -> dot::Id<'a> { dot::Id::new("example3") }
    fn node_id(&'a self, n: &Nd) -> dot::Id {
        dot::Id::new(format!("N{:u}", *n))
    }
    fn node_label<'a>(&'a self, i: &Nd) -> dot::LabelText<'a> {
        dot::LabelStr(str::Slice(self.nodes[*i].as_slice()))
    }
}

impl<'a> dot::GraphWalk<'a, Nd, Ed<'a>> for Graph {
    fn nodes(&'a self) -> dot::Nodes<'a,Nd> {
        range(0, self.nodes.len()).collect()
    }
    fn edges(&'a self) -> dot::Edges<'a,Ed<'a>> {
        self.edges.iter().collect()
    }
    fn source(&self, e: &Ed) -> Nd { let &(s,_) = *e; s }
    fn target(&self, e: &Ed) -> Nd { let &(_,t) = *e; t }
}
<|endoftext|>


<commit_before>use crossbeam::bounded;
use crossterm::{InputEvent, KeyEvent, TerminalInput};
use rand::distributions::Uniform;
use rand::prelude::Distribution;
use rusty_audio::Audio;
use rusty_sword::coord::{key_to_direction, Coord};
use rusty_sword::monster::Monster;
use rusty_sword::render::render_loop;
use rusty_sword::timer::Timer;
use rusty_sword::world::World;
use std::thread::{sleep, spawn};
use std::time::{Duration, Instant};

fn main() {
    let mut audio = Audio::new();
    audio.add("monster_dies", "clips/monster_dies.wav");
    audio.add("monster_spawns", "clips/monster_spawns.wav");
    audio.add("player_dies", "clips/player_dies.wav");

    let mut world = World::new();

    // Make a channel to send the world to the render thread, and a channel to receive it back
    // This is a silly design, we can demonstrate using channels for thread communication. :-P
    let (render_tx, render_rx) = bounded::<World>(0);
    let (main_tx, main_rx) = bounded::<World>(0);

    // Render Thread
    let render_thread = { spawn(move || render_loop(render_rx, main_tx)) };

    // Game Loop
    sleep(Duration::from_millis(100));
    let input = TerminalInput::new();
    let mut reader = input.read_async();
    let mut rng = rand::thread_rng();
    let mut spawn_timer = Timer::from_millis(1000);
    let mut last_instant = Instant::now();
    'gameloop: loop {
        let delta = last_instant.elapsed();
        last_instant = Instant::now();
        let mut player = &mut world.player;

        // Player moves?
        let mut player_moved = false;
        loop {
            match reader.next() {
                Some(event) => match event {
                    InputEvent::Keyboard(KeyEvent::Char('q'))
                    | InputEvent::Keyboard(KeyEvent::Esc) => break 'gameloop,
                    InputEvent::Keyboard(k) => {
                        if let Some(direction) = key_to_direction(k) {
                            player_moved =
                                player.travel(direction, &world.floor, &mut world.dirty_coords);
                        }
                    }
                    _ => {}
                },
                None => break,
            }
        }

        // Update monster timers
        for monster in world.monsters.iter_mut() {
            monster.move_timer.update(delta);
        }

        // Monsters move?
        if !player_moved {
            for monster in world.monsters.iter_mut() {
                monster.try_travel(player.coord, &mut world.dirty_coords);
            }
        }

        // Did a monster die?
        let num_monsters = world.monsters.len();
        world
            .monsters
            .retain(|monster| monster.coord != player.sword_coord);
        let num_killed = num_monsters - world.monsters.len();
        if num_killed > 0 {
            player.score += num_killed as u64;
            audio.play("monster_dies");
        }

        // Spawn a new monster!
        spawn_timer.update(delta);
        if spawn_timer.ready {
            spawn_timer = Timer::from_millis(Uniform::new(1000, 5000).sample(&mut rng));
            let to_coord = Coord::new(
                Uniform::new(1, 59).sample(&mut rng),
                Uniform::new(1, 29).sample(&mut rng),
            );
            if to_coord != player.coord {
                world.monsters.push(Monster::new(to_coord, &mut rng));
                audio.play("monster_spawns");
            }
        }

        // Did the player die?
        if world
            .monsters
            .iter()
            .any(|monster| monster.coord == player.coord)
        {
            audio.play("player_dies");
            audio.wait(); // Wait until the sound finishes, so we can hear it before quitting.
            break 'gameloop;
        }

        // Give the whole world to the renderer
        render_tx.send(world).unwrap();
        // Get the whole world back
        world = main_rx.recv().unwrap();
        // Don't exceed ~60/fps
        if let Some(t) = Duration::from_secs_f64(1. / 60.).checked_sub(last_instant.elapsed()) {
            sleep(t);
        }
    }

    // Close the render_tx channel, which will trigger the render thread to exit
    drop(render_tx);
    // Wait for the render thread to actually exit
    render_thread.join().unwrap();

    println!("Thanks for playing!");
}
<commit_msg>Refactor a loop to be much nicer<commit_after>use crossbeam::bounded;
use crossterm::{InputEvent, KeyEvent, TerminalInput};
use rand::distributions::Uniform;
use rand::prelude::Distribution;
use rusty_audio::Audio;
use rusty_sword::coord::{key_to_direction, Coord};
use rusty_sword::monster::Monster;
use rusty_sword::render::render_loop;
use rusty_sword::timer::Timer;
use rusty_sword::world::World;
use std::thread::{sleep, spawn};
use std::time::{Duration, Instant};

fn main() {
    let mut audio = Audio::new();
    audio.add("monster_dies", "clips/monster_dies.wav");
    audio.add("monster_spawns", "clips/monster_spawns.wav");
    audio.add("player_dies", "clips/player_dies.wav");

    let mut world = World::new();

    // Make a channel to send the world to the render thread, and a channel to receive it back
    // This is a silly design, we can demonstrate using channels for thread communication. :-P
    let (render_tx, render_rx) = bounded::<World>(0);
    let (main_tx, main_rx) = bounded::<World>(0);

    // Render Thread
    let render_thread = { spawn(move || render_loop(render_rx, main_tx)) };

    // Game Loop
    sleep(Duration::from_millis(100));
    let input = TerminalInput::new();
    let mut reader = input.read_async();
    let mut rng = rand::thread_rng();
    let mut spawn_timer = Timer::from_millis(1000);
    let mut last_instant = Instant::now();
    'gameloop: loop {
        let delta = last_instant.elapsed();
        last_instant = Instant::now();
        let mut player = &mut world.player;

        // Player moves?
        let mut player_moved = false;
        while let Some(event) = reader.next() {
            match event {
                InputEvent::Keyboard(KeyEvent::Char('q')) | InputEvent::Keyboard(KeyEvent::Esc) => {
                    break 'gameloop
                }
                InputEvent::Keyboard(k) => {
                    if let Some(direction) = key_to_direction(k) {
                        player_moved =
                            player.travel(direction, &world.floor, &mut world.dirty_coords);
                    }
                }
                _ => {}
            }
        }

        // Update monster timers
        for monster in world.monsters.iter_mut() {
            monster.move_timer.update(delta);
        }

        // Monsters move?
        if !player_moved {
            for monster in world.monsters.iter_mut() {
                monster.try_travel(player.coord, &mut world.dirty_coords);
            }
        }

        // Did a monster die?
        let num_monsters = world.monsters.len();
        world
            .monsters
            .retain(|monster| monster.coord != player.sword_coord);
        let num_killed = num_monsters - world.monsters.len();
        if num_killed > 0 {
            player.score += num_killed as u64;
            audio.play("monster_dies");
        }

        // Spawn a new monster!
        spawn_timer.update(delta);
        if spawn_timer.ready {
            spawn_timer = Timer::from_millis(Uniform::new(1000, 5000).sample(&mut rng));
            let to_coord = Coord::new(
                Uniform::new(1, 59).sample(&mut rng),
                Uniform::new(1, 29).sample(&mut rng),
            );
            if to_coord != player.coord {
                world.monsters.push(Monster::new(to_coord, &mut rng));
                audio.play("monster_spawns");
            }
        }

        // Did the player die?
        if world
            .monsters
            .iter()
            .any(|monster| monster.coord == player.coord)
        {
            audio.play("player_dies");
            audio.wait(); // Wait until the sound finishes, so we can hear it before quitting.
            break 'gameloop;
        }

        // Give the whole world to the renderer
        render_tx.send(world).unwrap();
        // Get the whole world back
        world = main_rx.recv().unwrap();
        // Don't exceed ~60/fps
        if let Some(t) = Duration::from_secs_f64(1. / 60.).checked_sub(last_instant.elapsed()) {
            sleep(t);
        }
    }

    // Close the render_tx channel, which will trigger the render thread to exit
    drop(render_tx);
    // Wait for the render thread to actually exit
    render_thread.join().unwrap();

    println!("Thanks for playing!");
}
<|endoftext|>


<commit_before>//
//    Copyright (C) 2015  Rory McCann
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU Affero General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU Affero General Public License for more details.
//
//    You should have received a copy of the GNU Affero General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.

extern crate num;
extern crate regex;

use std::env;
use std::fmt;
use num::integer::{div_rem, Integer};
use regex::Regex;

struct Duration<T> {
    weeks: T,
    days: T,
    hours: T,
    minutes: T,
    seconds: T,
}

impl<T:Integer> Duration<T> {
    fn new() -> Duration<T> {
        Duration{ weeks: T::zero(), days: T::zero(), hours: T::zero(), minutes: T::zero(), seconds: T::zero() }
    }

    fn set_weeks<'a>(&'a mut self, weeks: T) -> &'a mut Duration<T> {
        self.weeks = weeks;
        self
    }
    fn set_days<'a>(&'a mut self, days: T) -> &'a mut Duration<T> {
        self.days = days;
        self
    }
    fn set_hours<'a>(&'a mut self, hours: T) -> &'a mut Duration<T> {
        self.hours = hours;
        self
    }
    fn set_minutes<'a>(&'a mut self, minutes: T) -> &'a mut Duration<T> {
        self.minutes = minutes;
        self
    }
    fn set_seconds<'a>(&'a mut self, seconds: T) -> &'a mut Duration<T> {
        self.seconds = seconds;
        self
    }

}

impl fmt::Display for Duration<u64> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut writing = false;
        if self.weeks != 0 {
            try!(write!(f, "{}wk", self.weeks));
            writing = true;
        }
        if self.days != 0 || writing {
            try!(write!(f, "{}dy", self.days));
            writing = true;
        }
        if self.hours != 0 || writing {
            try!(write!(f, "{}hr", self.hours));
            writing = true;
        }
        if self.minutes != 0 || writing {
            if writing {
                try!(write!(f, "{:02}m", self.minutes));
            } else {
                try!(write!(f, "{}m", self.minutes));
            }
            writing = true;
        }
        if self.seconds != 0 || writing {
            if writing {
                try!(write!(f, "{:02}s", self.seconds));
            } else {
                try!(write!(f, "{}s", self.seconds));
            }
            //writing = true;
        }
        Ok(())
    }
}

fn sec2duration(seconds: u64) -> Duration<u64> {
    let (minutes, seconds) = div_rem(seconds, 60);
    let (hours, minutes) = div_rem(minutes, 60);
    let (days, hours) = div_rem(hours, 24);
    let (weeks, days) = div_rem(days, 7);

    Duration{ weeks: weeks, days: days, hours: hours, minutes: minutes, seconds: seconds }
}

// Converts a textual input to
fn input2sec(input:String) -> Result<u64, String> {
    // TODO replace with regex! macro so the is guaranteed to be OK

    if let Some(cap) = Regex::new(r"^\s*(?P<sec>[0-9]+)(\.[0-9]+)?\s*(s|sec|seconds?)?\s*$").unwrap().captures(&input) {
        // Just numbers, interpret as seconds. Truncate the sub-seconds
        let sec: u64 = try!(try!(cap.name("sec").ok_or("0")).parse().or(Err("Invalid seconds")));
        Ok(sec)
    } else if let Some(cap) = Regex::new(r"^\s*(?P<min>[0-9]+)\s*(m|min|minutes?)\s*((?P<sec>[0-9]+)\s*(s|sec|seconds?)?)?\s*$").unwrap().captures(&input) {
        // XmYs
        let sec: u64 = try!(cap.name("sec").unwrap_or(&"0").parse::<u64>().or(Err("Invalid seconds")));
        let min: u64 = try!(cap.name("min").unwrap_or(&"0").parse::<u64>().or(Err("Invalid minutes")));
        Ok(min*60 + sec)
    } else if let Some(cap) = Regex::new(r"^\s*(?P<min>[0-9]+):(?P<sec>[0-9][0-9])\s*$").unwrap().captures(&input) {
        // 0:00
        let sec: u64 = try!(cap.name("sec").unwrap_or(&"0").parse::<u64>().or(Err("Invalid seconds")));
        let min: u64 = try!(cap.name("min").unwrap_or(&"0").parse::<u64>().or(Err("Invalid minutes")));
        Ok(min*60 + sec)
    } else if let Some(cap) = Regex::new(r"^\s*(?P<ms>[0-9]+)\s*(ms|msec|milliseconds?)\s*$").unwrap().captures(&input) {
        // Milliseconds
        let ms: u64 = try!(try!(cap.name("ms").ok_or("0")).parse().or(Err("Invalid milliseconds")));
        let sec = ms / 1_000;
        Ok(sec)
    } else if let Some(cap) = Regex::new(r"^\s*(?P<ms>[0-9]+)\s*(μs|μsec|microsec|microseconds?)\s*$").unwrap().captures(&input) {
        // Microseconds
        let ms: u64 = try!(try!(cap.name("ms").ok_or("0")).parse().or(Err("Invalid microseconds")));
        let sec = ms / 1_000_000;
        Ok(sec)
    } else if let Some(cap) = Regex::new(r"^\s*(?P<ms>[0-9]+)\s*(ns|nsec|nanosec|nanoseconds?)\s*$").unwrap().captures(&input) {
        // Nanoseconds
        let ms: u64 = try!(try!(cap.name("ms").ok_or("0")).parse().or(Err("Invalid microseconds")));
        let sec = ms / 1_000_000_000;
        Ok(sec)
    } else {
        Err("Invalid input".to_string())
    }

}

fn prettytime(input: Vec<String>) -> Result<String, String> {
    if input.len() < 1 { return Err("No input".to_string()); }

    let input = input.join(" ");
    let seconds: u64 = try!(input2sec(input));

    let duration = sec2duration(seconds);

    Ok(format!("{}", duration))
}

fn main() {
    let args: Vec<_> = env::args().skip(1).collect();
    match prettytime(args) {
        Ok(s) => { println!("{}", s); },
        Err(s) => { println!("{}", s); }
    }
}

#[test]
fn test_print_duration() {
    assert_eq!("", format!("{}", Duration::new()));
    assert_eq!("1s", format!("{}", Duration::new().set_seconds(1)));
    assert_eq!("1m00s", format!("{}", Duration::new().set_minutes(1)));
    assert_eq!("1m03s", format!("{}", Duration::new().set_minutes(1).set_seconds(3)));
    assert_eq!("1hr00m00s", format!("{}", Duration::new().set_hours(1)));
    assert_eq!("1dy0hr00m00s", format!("{}", Duration::new().set_days(1)));
    assert_eq!("1wk0dy0hr00m00s", format!("{}", Duration::new().set_weeks(1)));
}

#[test]
fn test_parse_input() {
    // simple seconds
    assert_eq!(input2sec("10".to_string()), Ok(10));
    assert_eq!(input2sec("10s".to_string()), Ok(10));
    assert_eq!(input2sec("10 s".to_string()), Ok(10));
    assert_eq!(input2sec("10 sec".to_string()), Ok(10));
    assert_eq!(input2sec("10 foos".to_string()), Err("Invalid input".to_string()));

    // seconds with precision
    assert_eq!(input2sec("10.5".to_string()), Ok(10));
    assert_eq!(input2sec("10.5s".to_string()), Ok(10));
    assert_eq!(input2sec("10.2 s".to_string()), Ok(10));
    assert_eq!(input2sec("10.1 sec".to_string()), Ok(10));

    // minutes
    assert_eq!(input2sec("2m".to_string()), Ok(120));
    assert_eq!(input2sec("2m 20".to_string()), Ok(140));
    assert_eq!(input2sec("2m 20s".to_string()), Ok(140));
    assert_eq!(input2sec("2m20s".to_string()), Ok(140));
    assert_eq!(input2sec("   2 m   20  s   ".to_string()), Ok(140));
    assert_eq!(input2sec("2:20".to_string()), Ok(140));
    assert_eq!(input2sec("02:20".to_string()), Ok(140));
    assert_eq!(input2sec("100:00".to_string()), Ok(6000));

    // milliseconds
    assert_eq!(input2sec("2000ms".to_string()), Ok(2));
    assert_eq!(input2sec("2ms".to_string()), Ok(0));
    assert_eq!(input2sec("2000 milliseconds".to_string()), Ok(2));
    assert_eq!(input2sec("1500ms".to_string()), Ok(1));
    assert_eq!(input2sec("1100ms".to_string()), Ok(1));
    assert_eq!(input2sec("1999ms".to_string()), Ok(1));

    // microseconds
    assert_eq!(input2sec("2000000microsec".to_string()), Ok(2));
    assert_eq!(input2sec("2000000μsec".to_string()), Ok(2));
    assert_eq!(input2sec("2000000 μs".to_string()), Ok(2));

    // nanoseconds
    assert_eq!(input2sec("2000000000ns".to_string()), Ok(2));
    assert_eq!(input2sec("2000000000 ns".to_string()), Ok(2));
    assert_eq!(input2sec("2000000000 nsec".to_string()), Ok(2));
    assert_eq!(input2sec("2000000000 nanosec".to_string()), Ok(2));
}

<commit_msg>subseconds<commit_after>//
//    Copyright (C) 2015  Rory McCann
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU Affero General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU Affero General Public License for more details.
//
//    You should have received a copy of the GNU Affero General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.

extern crate num;
extern crate regex;

use std::env;
use std::fmt;
use num::integer::{div_rem, Integer};
use regex::Regex;

struct Duration<T> {
    weeks: T,
    days: T,
    hours: T,
    minutes: T,
    seconds: T,
}

impl<T:Integer> Duration<T> {
    fn new() -> Duration<T> {
        Duration{ weeks: T::zero(), days: T::zero(), hours: T::zero(), minutes: T::zero(), seconds: T::zero() }
    }

    fn set_weeks<'a>(&'a mut self, weeks: T) -> &'a mut Duration<T> {
        self.weeks = weeks;
        self
    }
    fn set_days<'a>(&'a mut self, days: T) -> &'a mut Duration<T> {
        self.days = days;
        self
    }
    fn set_hours<'a>(&'a mut self, hours: T) -> &'a mut Duration<T> {
        self.hours = hours;
        self
    }
    fn set_minutes<'a>(&'a mut self, minutes: T) -> &'a mut Duration<T> {
        self.minutes = minutes;
        self
    }
    fn set_seconds<'a>(&'a mut self, seconds: T) -> &'a mut Duration<T> {
        self.seconds = seconds;
        self
    }

}

impl fmt::Display for Duration<u64> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut writing = false;
        if self.weeks != 0 {
            try!(write!(f, "{}wk", self.weeks));
            writing = true;
        }
        if self.days != 0 || writing {
            try!(write!(f, "{}dy", self.days));
            writing = true;
        }
        if self.hours != 0 || writing {
            try!(write!(f, "{}hr", self.hours));
            writing = true;
        }
        if self.minutes != 0 || writing {
            if writing {
                try!(write!(f, "{:02}m", self.minutes));
            } else {
                try!(write!(f, "{}m", self.minutes));
            }
            writing = true;
        }
        if self.seconds != 0 || writing {
            if writing {
                try!(write!(f, "{:02}s", self.seconds));
            } else {
                try!(write!(f, "{}s", self.seconds));
            }
            //writing = true;
        }
        Ok(())
    }
}

fn sec2duration(seconds: u64) -> Duration<u64> {
    let (minutes, seconds) = div_rem(seconds, 60);
    let (hours, minutes) = div_rem(minutes, 60);
    let (days, hours) = div_rem(hours, 24);
    let (weeks, days) = div_rem(days, 7);

    Duration{ weeks: weeks, days: days, hours: hours, minutes: minutes, seconds: seconds }
}

// Converts a textual input to
fn input2sec(input:String) -> Result<u64, String> {
    // TODO replace with regex! macro so the is guaranteed to be OK

    if let Some(cap) = Regex::new(r"^\s*(?P<sec>[0-9]+)(\.[0-9]+)?\s*(s|sec|seconds?)?\s*$").unwrap().captures(&input) {
        // Just numbers, interpret as seconds. Truncate the sub-seconds
        let sec: u64 = try!(try!(cap.name("sec").ok_or("0")).parse().or(Err("Invalid seconds")));
        Ok(sec)
    } else if let Some(cap) = Regex::new(r"^\s*(?P<min>[0-9]+)\s*(m|min|minutes?)\s*((?P<sec>[0-9]+)(\.[0-9]+)?\s*(s|sec|seconds?)?)?\s*$").unwrap().captures(&input) {
        // XmYs. Truncate the subseconds
        let sec: u64 = try!(cap.name("sec").unwrap_or(&"0").parse::<u64>().or(Err("Invalid seconds")));
        let min: u64 = try!(cap.name("min").unwrap_or(&"0").parse::<u64>().or(Err("Invalid minutes")));
        Ok(min*60 + sec)
    } else if let Some(cap) = Regex::new(r"^\s*(?P<min>[0-9]+):(?P<sec>[0-9][0-9])\s*$").unwrap().captures(&input) {
        // 0:00
        let sec: u64 = try!(cap.name("sec").unwrap_or(&"0").parse::<u64>().or(Err("Invalid seconds")));
        let min: u64 = try!(cap.name("min").unwrap_or(&"0").parse::<u64>().or(Err("Invalid minutes")));
        Ok(min*60 + sec)
    } else if let Some(cap) = Regex::new(r"^\s*(?P<ms>[0-9]+)\s*(ms|msec|milliseconds?)\s*$").unwrap().captures(&input) {
        // Milliseconds
        let ms: u64 = try!(try!(cap.name("ms").ok_or("0")).parse().or(Err("Invalid milliseconds")));
        let sec = ms / 1_000;
        Ok(sec)
    } else if let Some(cap) = Regex::new(r"^\s*(?P<ms>[0-9]+)\s*(μs|μsec|microsec|microseconds?)\s*$").unwrap().captures(&input) {
        // Microseconds
        let ms: u64 = try!(try!(cap.name("ms").ok_or("0")).parse().or(Err("Invalid microseconds")));
        let sec = ms / 1_000_000;
        Ok(sec)
    } else if let Some(cap) = Regex::new(r"^\s*(?P<ms>[0-9]+)\s*(ns|nsec|nanosec|nanoseconds?)\s*$").unwrap().captures(&input) {
        // Nanoseconds
        let ms: u64 = try!(try!(cap.name("ms").ok_or("0")).parse().or(Err("Invalid microseconds")));
        let sec = ms / 1_000_000_000;
        Ok(sec)
    } else {
        Err("Invalid input".to_string())
    }

}

fn prettytime(input: Vec<String>) -> Result<String, String> {
    if input.len() < 1 { return Err("No input".to_string()); }

    let input = input.join(" ");
    let seconds: u64 = try!(input2sec(input));

    let duration = sec2duration(seconds);

    Ok(format!("{}", duration))
}

fn main() {
    let args: Vec<_> = env::args().skip(1).collect();
    match prettytime(args) {
        Ok(s) => { println!("{}", s); },
        Err(s) => { println!("{}", s); }
    }
}

#[test]
fn test_print_duration() {
    assert_eq!("", format!("{}", Duration::new()));
    assert_eq!("1s", format!("{}", Duration::new().set_seconds(1)));
    assert_eq!("1m00s", format!("{}", Duration::new().set_minutes(1)));
    assert_eq!("1m03s", format!("{}", Duration::new().set_minutes(1).set_seconds(3)));
    assert_eq!("1hr00m00s", format!("{}", Duration::new().set_hours(1)));
    assert_eq!("1dy0hr00m00s", format!("{}", Duration::new().set_days(1)));
    assert_eq!("1wk0dy0hr00m00s", format!("{}", Duration::new().set_weeks(1)));
}

#[test]
fn test_parse_input() {
    // simple seconds
    assert_eq!(input2sec("10".to_string()), Ok(10));
    assert_eq!(input2sec("10s".to_string()), Ok(10));
    assert_eq!(input2sec("10 s".to_string()), Ok(10));
    assert_eq!(input2sec("10 sec".to_string()), Ok(10));
    assert_eq!(input2sec("10 foos".to_string()), Err("Invalid input".to_string()));

    // seconds with precision
    assert_eq!(input2sec("10.5".to_string()), Ok(10));
    assert_eq!(input2sec("10.5s".to_string()), Ok(10));
    assert_eq!(input2sec("10.2 s".to_string()), Ok(10));
    assert_eq!(input2sec("10.1 sec".to_string()), Ok(10));

    // minutes
    assert_eq!(input2sec("2m".to_string()), Ok(120));
    assert_eq!(input2sec("2m 20".to_string()), Ok(140));
    assert_eq!(input2sec("2m 20s".to_string()), Ok(140));
    assert_eq!(input2sec("2m20s".to_string()), Ok(140));
    assert_eq!(input2sec("   2 m   20  s   ".to_string()), Ok(140));
    assert_eq!(input2sec("2:20".to_string()), Ok(140));
    assert_eq!(input2sec("02:20".to_string()), Ok(140));
    assert_eq!(input2sec("100:00".to_string()), Ok(6000));

    assert_eq!(input2sec("10m12.123s".to_string()), Ok(612));

    // milliseconds
    assert_eq!(input2sec("2000ms".to_string()), Ok(2));
    assert_eq!(input2sec("2ms".to_string()), Ok(0));
    assert_eq!(input2sec("2000 milliseconds".to_string()), Ok(2));
    assert_eq!(input2sec("1500ms".to_string()), Ok(1));
    assert_eq!(input2sec("1100ms".to_string()), Ok(1));
    assert_eq!(input2sec("1999ms".to_string()), Ok(1));

    // microseconds
    assert_eq!(input2sec("2000000microsec".to_string()), Ok(2));
    assert_eq!(input2sec("2000000μsec".to_string()), Ok(2));
    assert_eq!(input2sec("2000000 μs".to_string()), Ok(2));

    // nanoseconds
    assert_eq!(input2sec("2000000000ns".to_string()), Ok(2));
    assert_eq!(input2sec("2000000000 ns".to_string()), Ok(2));
    assert_eq!(input2sec("2000000000 nsec".to_string()), Ok(2));
    assert_eq!(input2sec("2000000000 nanosec".to_string()), Ok(2));
}

<|endoftext|>


<commit_before>#![allow(unstable)]
extern crate sodiumoxide;
extern crate libc;
extern crate serialize;

use libc::*;
use sodiumoxide::crypto::hash::sha256;
use serialize::hex::ToHex;

use std::io::process::{Command, StdioContainer, ProcessOutput};
use std::io::fs::PathExtensions;
use std::ffi;
use std::str;
use std::mem;
use std::io;

use reader::*;
use controls::*;
use termios::*;
use signal::*;
use constants::*;
use util::*;
use input::*;

mod constants;
mod util;
mod termios;
mod signal;
mod controls;
mod input;
mod reader;

const RTLD_LOCAL:c_int = 0;
const RTLD_LAZY:c_int = 1;

const ENTRY_SYMBOL:&'static str = "wash_run";
const WO_PATH:&'static str = "/tmp/wash/";

// start off as null pointer
static mut uglobal_reader:*mut LineReader = 0 as *mut LineReader;

#[link(name = "dl")]
extern {
    fn dlopen(filename:*const c_char, flag:c_int) -> *const c_void;
    fn dlsym(handle:*const c_void, symbol:*const c_char) -> *const c_void;
    fn dlclose(handle:*const c_void) -> c_int;
    fn dlerror() -> *const c_char;
}

#[allow(unused_variables)]
unsafe extern fn reader_sigint(signum:c_int, siginfo:*const SigInfo, context:size_t) {
    // This function should only be called when the input line is actually active
    if uglobal_reader.is_null() {
        // More informative than a segfault
        panic!("Line reader location uninitialized");
    }
    // Hopefully no segfault, this *should* be safe code
    let ref mut reader:LineReader = *uglobal_reader;
    if reader.line.is_empty() {
        reader.controls.outs("Interrupt\n");
    } else {
        reader.controls.outs("\nInterrupt\n");
    }
    // reset line
    reader.clear();
}

fn set_reader_location(reader:&mut LineReader) {
    unsafe {
        if !uglobal_reader.is_null() {
            panic!("Tried to set reader location twice");
        }
        uglobal_reader = reader as *mut LineReader;
    }
}

fn terminal_settings(controls:&mut Controls) -> (Termios, Termios) {
    let mut tios = match Termios::get() {
        Some(t) => t,
        None => {
            controls.err("Warning: Could not get terminal mode\n");
            Termios::new()
        }
    };
    let ctios = tios.clone();
    tios.fdisable(0, 0, ICANON|ECHO, 0);
    return (tios, ctios);
}

fn update_terminal(tios:&Termios, controls:&mut Controls) {
    if !Termios::set(tios) {
        controls.err("Warning: Could not set terminal mode\n");
    }
}

fn set_reader_sigint(controls:&mut Controls) {
    let mut sa = SigAction {
        handler: reader_sigint,
        mask: [0; SIGSET_NWORDS],
        flags: SA_RESTART | SA_SIGINFO,
        restorer: 0 // null pointer
    };
    let mask = full_sigset().expect("Could not get a full sigset");
    sa.mask = mask;
    if !signal_handle(SIGINT, &sa) {
        controls.err("Warning: could not set handler for SIGINT\n");
    }
}

fn run_command(line:&Vec<String>, controls:&mut Controls) {
    let mut process = Command::new(&line[0]);
    process.args(line.slice_from(1));
    process.stdout(StdioContainer::InheritFd(STDOUT));
    process.stdin(StdioContainer::InheritFd(STDIN));
    process.stderr(StdioContainer::InheritFd(STDERR));
    let mut child = match process.spawn() {
        Err(e) => {
            controls.errf(format_args!("Couldn't spawn {}: {}\n", &line[0], e));
            return;
        },
        Ok(child) => child
    };
    match child.wait() {
        Err(e) => {
            controls.errf(format_args!("Couldn't wait for child to exit: {}\n", e.desc));
        },
        Ok(_) => {
            // nothing
        }
    };
}

fn run_command_directed(line:&Vec<String>, controls:&mut Controls) -> Option<ProcessOutput> {
    let mut process = Command::new(&line[0]);
    process.args(line.slice_from(1));
    match process.output() {
        Err(e) => {
            controls.errf(format_args!("Couldn't spawn {}: {}\n", &line[0], e));
            return None;
        },
        Ok(out) => Some(out)
    }
}

fn process_line(line:Vec<String>, controls:&mut Controls) -> Option<Vec<String>> {
    let mut out = strip_words(line);
    out = match process_sublines(out, controls) {
        None => return None,
        Some(l) => l
    };
    return Some(out);
}

fn process_sublines(line:Vec<String>, controls:&mut Controls) -> Option<Vec<String>> {
    let mut out = Vec::<String>::new();
    for word in line.iter() {
        if word.as_slice().starts_with("$(") &&
            word.as_slice().ends_with(")") {
                let mut subline = InputLine::process_line(String::from_str(word.slice_chars(2, word.len() - 1)));
                subline = match process_line(subline, controls) {
                    None => return None,
                    Some(l) => l
                };
                match run_command_directed(&subline, controls) {
                    None => return None,
                    Some(ProcessOutput {status, error, output}) => {
                        if status.success() {
                            let mut cout = String::from_utf8_lossy(output.as_slice()).into_owned();
                            if cout.as_slice().ends_with("\n") {
                                // remove traling newlines, they aren't useful
                                cout.pop();
                            }
                            out.push(cout);
                        } else {
                            controls.errf(format_args!("{} failed: {}\n", &subline[0],
                                                       String::from_utf8_lossy(error.as_slice())));
                            return None;
                        }
                    }
                }
            } else {
                out.push(word.clone());
            }
    }
    return Some(out);
}

#[allow(unused_variables)]
fn update(line:&Vec<String>) {
    // nothing yet
}

fn run_wash_script(line:&Vec<String>, controls:&mut Controls) {
    let inp = Path::new(&line[0]);
    let inf = match io::File::open(&inp) {
        Ok(f) => f,
        Err(e) => {
            controls.errf(format_args!("File error: {}", e));
            return;
        }
    };
    let mut reader = io::BufferedReader::new(inf);
    let contents = reader.read_to_end().unwrap();
    let bytes = contents.as_slice();
    let mut outname = sha256::hash(bytes).0.to_hex();
    outname.push_str(".wo");
    let outp = Path::new(WO_PATH).join(outname);

    if !outp.exists() {
        io::fs::mkdir_recursive(&outp.dir_path(), io::USER_RWX).unwrap();
        let mut command = Command::new("rustc");
        command.args(&["-o", outp.as_str().unwrap(), "-"]);
        let mut child = match command.spawn() {
            Err(e) => {
                panic!("Error: {}", e);
            },
            Ok(c) => c
        };

        {
            let mut input = child.stdin.as_mut().unwrap();
            input.write(bytes).unwrap();
            input.flush().unwrap();
        }

        match child.wait_with_output() {
            Err(e) => {
                controls.errf(format_args!("Could not compile script: {}", e));
            },
            Ok(o) => {
                if !o.status.success() {
                    controls.errf(format_args!("Could not compile script: {}",
                                               String::from_utf8(o.error).unwrap()));
                }
            }
        }
    }

    unsafe {
        let handle = dlopen(ffi::CString::from_slice(outp.as_str().unwrap().as_bytes()).as_ptr(),
                            RTLD_LAZY|RTLD_LOCAL);
        if handle.is_null() {
            controls.errf(format_args!("Could not load script object: {}",
                                       str::from_utf8(ffi::c_str_to_bytes(&dlerror())).unwrap()));
            return;
        }
        let ptr = dlsym(handle, ffi::CString::from_slice(ENTRY_SYMBOL.as_bytes()).as_ptr());
        if ptr.is_null() {
            controls.errf(format_args!("Could not find entry symbol: {}",
                                       str::from_utf8(ffi::c_str_to_bytes(&dlerror())).unwrap()));
            dlclose(handle);
            return;
        }
        let func:extern fn() = mem::transmute(ptr);
        func();
        dlclose(handle);
    }
}

fn process_job(line:&Vec<String>, tios:&Termios, old_tios:&Termios,
               reader:&mut LineReader, controls:&mut Controls) {
    if line.is_empty() {
        return;
    }
    if line[0].as_slice().ends_with(".ws") {
        // run as wash shell script
        update_terminal(old_tios, controls);
        signal_ignore(SIGINT);
        controls.outc(NL);
        controls.flush();
        run_wash_script(line, controls);
        set_reader_sigint(controls);
        update_terminal(tios, controls);
        reader.clear();
    } else {
        update_terminal(old_tios, controls);
        signal_ignore(SIGINT);
        controls.outc(NL);
        controls.flush();
        run_command(line, controls);
        set_reader_sigint(controls);
        update_terminal(tios, controls);
        reader.clear();
    }
}

fn main() {
    let mut controls = &mut Controls::new();
    let mut reader = LineReader::new();
    let (tios, old_tios) = terminal_settings(controls);
    update_terminal(&tios, controls);
    set_reader_location(&mut reader);
    set_reader_sigint(controls);
    let mut line:Vec<String>;
    loop {
        line = match reader.read_line() {
            None => break,
            Some(l) => l
        };
        line = match process_line(line, controls) {
            None => {
                controls.err("Command failed\n");
                continue;
            },
            Some(l) => l
        };
        update(&line);
        process_job(&line, &tios, &old_tios,
                    &mut reader, controls);
        controls.flush();
    }
    controls.outs("Exiting\n");
    update_terminal(&old_tios, controls);
}
<commit_msg>Improve error printing<commit_after>#![allow(unstable)]
extern crate sodiumoxide;
extern crate libc;
extern crate serialize;

use libc::*;
use sodiumoxide::crypto::hash::sha256;
use serialize::hex::ToHex;

use std::io::process::{Command, StdioContainer, ProcessOutput};
use std::io::fs::PathExtensions;
use std::collections::HashMap;

use std::ffi;
use std::str;
use std::mem;
use std::io;

use reader::*;
use controls::*;
use termios::*;
use signal::*;
use constants::*;
use util::*;
use input::*;

mod constants;
mod util;
mod termios;
mod signal;
mod controls;
mod input;
mod reader;

const RTLD_LOCAL:c_int = 0;
const RTLD_LAZY:c_int = 1;

const ENTRY_SYMBOL:&'static str = "wash_run";
const WO_PATH:&'static str = "/tmp/wash/";

// start off as null pointer
static mut uglobal_reader:*mut LineReader = 0 as *mut LineReader;

#[link(name = "dl")]
extern {
    fn dlopen(filename:*const c_char, flag:c_int) -> *const c_void;
    fn dlsym(handle:*const c_void, symbol:*const c_char) -> *const c_void;
    fn dlclose(handle:*const c_void) -> c_int;
    fn dlerror() -> *const c_char;
}

#[allow(unused_variables)]
unsafe extern fn reader_sigint(signum:c_int, siginfo:*const SigInfo, context:size_t) {
    // This function should only be called when the input line is actually active
    if uglobal_reader.is_null() {
        // More informative than a segfault
        panic!("Line reader location uninitialized");
    }
    // Hopefully no segfault, this *should* be safe code
    let ref mut reader:LineReader = *uglobal_reader;
    if reader.line.is_empty() {
        reader.controls.outs("Interrupt\n");
    } else {
        reader.controls.outs("\nInterrupt\n");
    }
    // reset line
    reader.clear();
}

fn set_reader_location(reader:&mut LineReader) {
    unsafe {
        if !uglobal_reader.is_null() {
            panic!("Tried to set reader location twice");
        }
        uglobal_reader = reader as *mut LineReader;
    }
}

fn terminal_settings(controls:&mut Controls) -> (Termios, Termios) {
    let mut tios = match Termios::get() {
        Some(t) => t,
        None => {
            controls.err("Warning: Could not get terminal mode\n");
            Termios::new()
        }
    };
    let ctios = tios.clone();
    tios.fdisable(0, 0, ICANON|ECHO, 0);
    return (tios, ctios);
}

fn update_terminal(tios:&Termios, controls:&mut Controls) {
    if !Termios::set(tios) {
        controls.err("Warning: Could not set terminal mode\n");
    }
}

fn set_reader_sigint(controls:&mut Controls) {
    let mut sa = SigAction {
        handler: reader_sigint,
        mask: [0; SIGSET_NWORDS],
        flags: SA_RESTART | SA_SIGINFO,
        restorer: 0 // null pointer
    };
    let mask = full_sigset().expect("Could not get a full sigset");
    sa.mask = mask;
    if !signal_handle(SIGINT, &sa) {
        controls.err("Warning: could not set handler for SIGINT\n");
    }
}

fn run_command(line:&Vec<String>, controls:&mut Controls) {
    let mut process = Command::new(&line[0]);
    process.args(line.slice_from(1));
    process.stdout(StdioContainer::InheritFd(STDOUT));
    process.stdin(StdioContainer::InheritFd(STDIN));
    process.stderr(StdioContainer::InheritFd(STDERR));
    let mut child = match process.spawn() {
        Err(e) => {
            controls.errf(format_args!("Couldn't spawn {}: {}\n", &line[0], e));
            return;
        },
        Ok(child) => child
    };
    match child.wait() {
        Err(e) => {
            controls.errf(format_args!("Couldn't wait for child to exit: {}\n", e.desc));
        },
        Ok(_) => {
            // nothing
        }
    };
}

fn run_command_directed(line:&Vec<String>, controls:&mut Controls) -> Option<ProcessOutput> {
    let mut process = Command::new(&line[0]);
    process.args(line.slice_from(1));
    match process.output() {
        Err(e) => {
            controls.errf(format_args!("Couldn't spawn {}: {}\n", &line[0], e));
            return None;
        },
        Ok(out) => Some(out)
    }
}

fn process_line(line:Vec<String>, controls:&mut Controls) -> Option<Vec<String>> {
    let mut out = strip_words(line);
    out = match process_sublines(out, controls) {
        None => return None,
        Some(l) => l
    };
    return Some(out);
}

fn process_sublines(line:Vec<String>, controls:&mut Controls) -> Option<Vec<String>> {
    let mut out = Vec::<String>::new();
    for word in line.iter() {
        if word.as_slice().starts_with("$(") &&
            word.as_slice().ends_with(")") {
                let mut subline = InputLine::process_line(String::from_str(word.slice_chars(2, word.len() - 1)));
                subline = match process_line(subline, controls) {
                    None => return None,
                    Some(l) => l
                };
                match run_command_directed(&subline, controls) {
                    None => return None,
                    Some(ProcessOutput {status, error, output}) => {
                        if status.success() {
                            let mut cout = String::from_utf8_lossy(output.as_slice()).into_owned();
                            if cout.as_slice().ends_with("\n") {
                                // remove traling newlines, they aren't useful
                                cout.pop();
                            }
                            out.push(cout);
                        } else {
                            controls.errf(format_args!("{} failed: {}\n", &subline[0],
                                                       String::from_utf8_lossy(error.as_slice())));
                            return None;
                        }
                    }
                }
            } else {
                out.push(word.clone());
            }
    }
    return Some(out);
}

#[allow(unused_variables)]
fn update(line:&Vec<String>) {
    // nothing yet
}

fn run_wash_script(line:&Vec<String>, controls:&mut Controls) {
    let inp = Path::new(&line[0]);
    let inf = match io::File::open(&inp) {
        Ok(f) => f,
        Err(e) => {
            controls.errf(format_args!("File error: {}\n", e));
            return;
        }
    };
    let mut reader = io::BufferedReader::new(inf);
    let contents = reader.read_to_end().unwrap();
    let bytes = contents.as_slice();
    let mut outname = sha256::hash(bytes).0.to_hex();
    outname.push_str(".wo");
    let outp = Path::new(WO_PATH).join(outname);

    if !outp.exists() {
        io::fs::mkdir_recursive(&outp.dir_path(), io::USER_RWX).unwrap();
        let mut command = Command::new("rustc");
        command.args(&["-o", outp.as_str().unwrap(), "-"]);
        let mut child = match command.spawn() {
            Err(e) => {
                panic!("Error: {}\n", e);
            },
            Ok(c) => c
        };

        {
            let mut input = child.stdin.as_mut().unwrap();
            input.write(bytes).unwrap();
            input.flush().unwrap();
        }

        match child.wait_with_output() {
            Err(e) => {
                controls.errf(format_args!("Could not compile script: {}\n", e));
            },
            Ok(o) => {
                if !o.status.success() {
                    controls.errf(format_args!("Could not compile script: {}\n",
                                               String::from_utf8(o.error).unwrap()));
                }
            }
        }
    }

    unsafe {
        let handle = dlopen(ffi::CString::from_slice(outp.as_str().unwrap().as_bytes()).as_ptr(),
                            RTLD_LAZY|RTLD_LOCAL);
        if handle.is_null() {
            controls.errf(format_args!("Could not load script object: {}\n",
                                       str::from_utf8(ffi::c_str_to_bytes(&dlerror())).unwrap()));
            return;
        }
        let ptr = dlsym(handle, ffi::CString::from_slice(ENTRY_SYMBOL.as_bytes()).as_ptr());
        if ptr.is_null() {
            controls.errf(format_args!("Could not find entry symbol: {}\n",
                                       str::from_utf8(ffi::c_str_to_bytes(&dlerror())).unwrap()));
            dlclose(handle);
            return;
        }
        let func:extern fn() = mem::transmute(ptr);
        func();
        dlclose(handle);
    }
}

fn process_job(line:&Vec<String>, tios:&Termios, old_tios:&Termios,
               reader:&mut LineReader, controls:&mut Controls) {
    if line.is_empty() {
        return;
    }
    if line[0].as_slice().ends_with(".ws") {
        // run as wash shell script
        update_terminal(old_tios, controls);
        signal_ignore(SIGINT);
        controls.outc(NL);
        controls.flush();
        run_wash_script(line, controls);
        set_reader_sigint(controls);
        update_terminal(tios, controls);
        reader.clear();
    } else {
        update_terminal(old_tios, controls);
        signal_ignore(SIGINT);
        controls.outc(NL);
        controls.flush();
        run_command(line, controls);
        set_reader_sigint(controls);
        update_terminal(tios, controls);
        reader.clear();
    }
}

fn main() {
    let mut controls = &mut Controls::new();
    let mut reader = LineReader::new();
    let mut map = HashMap::<&str, &fn(Vec<String>) -> Vec<String>>::new();
    let (tios, old_tios) = terminal_settings(controls);
    update_terminal(&tios, controls);
    set_reader_location(&mut reader);
    set_reader_sigint(controls);
    let mut line:Vec<String>;
    loop {
        line = match reader.read_line() {
            None => break,
            Some(l) => l
        };
        line = match process_line(line, controls) {
            None => {
                controls.err("Command failed\n");
                continue;
            },
            Some(l) => l
        };
        update(&line);
        process_job(&line, &tios, &old_tios,
                    &mut reader, controls);
        controls.flush();
    }
    controls.outs("Exiting\n");
    update_terminal(&old_tios, controls);
}
<|endoftext|>


<commit_before>struct Item(str);

struct Location {
    // literal string as this is static
    description: Box<str>,
    items: Vec<Box<Item>>,
}

fn main() {
    let item1 = Item("Little key");
    let item2 = Item("Big key");
    let hall = Location{ description: "A wide open space. Streams of lava flow on both sides of the entry gate.",
                         items: vec![item1, item2] };
}
<commit_msg>Changed string types and type of reference to item so that everything compiles again. Already worth examining what causes this.<commit_after>struct Item(&'static str);

struct Location {
    // literal string as this is static
    description: &'static str,
    items: Vec<Item>,
}

fn main() {
    let item1 = Item("Little key");
    let item2 = Item("Big key");
    let hall = Location{ description: "A wide open space. Streams of lava flow on both sides of the entry gate.",
                         items: vec![item1, item2] };
}
<|endoftext|>


<commit_before>
extern crate sha2;
extern crate base64;
extern crate sha1;

use std::path::Path;
use std::process;
use std::env;

mod checker;

fn main() {

    let args: Vec<_> = env::args().collect();

    if args.len() != 2 {
        println!("Missing folder.");
        process::exit(0);
    }

    let ref path = args[1];
    let dir = Path::new(path);
    println!("Scanning: {}", path);
    checker::walk_recursive_path(dir);
}
<commit_msg>add proper commandline argument parser;<commit_after>
extern crate sha2;
extern crate base64;
extern crate sha1;
extern crate getopts;

use getopts::Options;
use std::path::Path;
use std::process;
use std::env;

mod checker;

fn do_scan_task(dir_txt: &str) {
    println!("Scanning: {}", dir_txt);
    let dir = Path::new(dir_txt);

    checker::walk_recursive_path(dir);
}

fn show_usage(program_name: &str, opts: Options){
    let brief = format!("usage: {} scan DIRECTORY_PATH [options]", program_name);
    print!("{}", opts.usage(&brief));
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program_name = args[0].clone();
    let mut opts = Options::new();

    //register options
    opts.optopt("o", "output", "specifies the name of output file", "FILENAME");
    opts.optflag("h", "help", "shows usage help");

    //parse command-line arguments
    let matches = match opts.parse(&args[1..]){
        Ok(m)   => { m },
        Err(f)  => { panic!(f.to_string()) }
    };

    //did user asked to see help menu
    if matches.opt_present("h") {
        show_usage(&program_name, opts);
        return;
    }

    //extract input arguments
    let output = matches.opt_str("o");
    let input = if !matches.free.is_empty(){
        matches.free[0].clone()
    } else {
        show_usage(&program_name, opts);
        return;
    };

    do_scan_task(&input);
}
<|endoftext|>