<commit_before>extern crate rand;
extern crate hyper;

use std::fs::{File, OpenOptions, remove_file};
use std::str::FromStr;
use std::path::Path;

mod pasteid;
use pasteid::PasteID;

use std::io;
use hyper::header::{ContentLength, ContentType};
use hyper::server::{Server, Request, Response};
use hyper::status::StatusCode;
use hyper::uri::RequestUri::*;

const ID_SIZE: usize = 8;
const USAGE: &'static [u8] = b"
pastabin 0.0.1 - Minimal pastebin clone in Rust. Manual post required. CLI recommended.

    USAGE

      POST /

        accepts raw data in the body of the request and responds with a URL of
        a page containing the body's content

      GET /<id>

        retrieves the content for the paste with id `<id>`

    EXAMPLE

        Upload a file:

            curl --data-binary @file.txt https://pasta.lol/

        Upload from stdin:

            echo \"Hellow, World\" | curl --data-binary @- https://pasta.lol/

        Delete an existing paste:

            curl -X DELETE https://pasta.lol/<id>

    SOURCE CODE

        https://github.com/nopjmp/pastabin
    ";

fn retrieve_paste(id: PasteID) -> Option<File> {
    File::open(&id.filename()).ok()
}

fn create_paste(id: &PasteID) -> io::Result<File> {
    OpenOptions::new()
        .write(true)
        .create_new(true)
        .open(&id.filename())
}

macro_rules! try_handle {
    ($res:ident, $e:expr, $statuscode:expr) => {{
        match $e.ok() {
            Some(v) => v,
            None => {
                *$res.status_mut() = $statuscode;
                return;
            },
        }
    }}
}

fn handle(mut req: Request, mut res: Response) {
    match req.method {
        hyper::Get => {
            match req.uri.clone() {
                AbsolutePath(path) => {
                    if path == "/" {
                        res.headers_mut().set(ContentType::plaintext());
                        res.send(USAGE).unwrap();
                    } else if path == "/favicon.ico" {
                        // todo favicon
                        *res.status_mut() = StatusCode::NotFound;
                    } else if let Ok(id) = PasteID::from_str(path.trim_left_matches("/")) {
                        match retrieve_paste(id) {
                            Some(mut file) => {
                                let metadata = try_handle!(res,
                                                           file.metadata(),
                                                           StatusCode::InternalServerError);
                                res.headers_mut().set(ContentLength(metadata.len()));
                                res.headers_mut().set(ContentType::plaintext());
                                io::copy(&mut file, &mut res.start().unwrap()).unwrap();
                            }
                            None => *res.status_mut() = StatusCode::NotFound,
                        }
                    } else {
                        *res.status_mut() = StatusCode::BadRequest;
                    }
                }
                _ => *res.status_mut() = StatusCode::BadRequest,
            }
        }
        hyper::Post => {
            match req.uri.clone() {
                AbsolutePath(path) => {
                    if path != "/" {
                        *res.status_mut() = StatusCode::BadRequest;
                    } else {
                        let mut tries = 0;
                        let mut id = PasteID::new(ID_SIZE);
                        let mut file = create_paste(&id);
                        while file.is_err() && tries < 3 {
                            id = PasteID::new(ID_SIZE);
                            file = create_paste(&id);
                            tries += 1;
                        }
                        if file.is_err() {
                            *res.status_mut() = StatusCode::InternalServerError;
                        } else {
                            try_handle!(res,
                                        io::copy(&mut req,
                                                 &mut try_handle!(res,
                                                                  file,
                                                                  StatusCode::InternalServerError)),
                                        StatusCode::InternalServerError);
                            *res.status_mut() = StatusCode::Created;
                            res.send(format!("https://pasta.lol/{}\n", id).as_bytes())
                                .unwrap();
                        }
                    }
                }
                _ => *res.status_mut() = StatusCode::BadRequest,
            }
        }
        hyper::Delete => {
            match req.uri.clone() {
                AbsolutePath(path) => {
                    let id = try_handle!(res,
                                         PasteID::from_str(path.trim_left_matches("/")),
                                         StatusCode::BadRequest);
                    let filename = id.filename();
                    let path = Path::new(&filename);
                    if path.exists() {
                        try_handle!(res, remove_file(path), StatusCode::InternalServerError);
                    } else {
                        *res.status_mut() = StatusCode::NotFound;
                    }
                }
                _ => *res.status_mut() = StatusCode::BadRequest,
            }
        }
        _ => *res.status_mut() = StatusCode::MethodNotAllowed,
    }
}

fn main() {
    let mut ipv4 = Server::http("127.0.0.1:8080").unwrap();
    ipv4.keep_alive(None);
    let _guardipv4 = ipv4.handle(handle);
}
<commit_msg>add license to index<commit_after>extern crate rand;
extern crate hyper;

use std::fs::{File, OpenOptions, remove_file};
use std::str::FromStr;
use std::path::Path;

mod pasteid;
use pasteid::PasteID;

use std::io;
use hyper::header::{ContentLength, ContentType};
use hyper::server::{Server, Request, Response};
use hyper::status::StatusCode;
use hyper::uri::RequestUri::*;

const ID_SIZE: usize = 8;
const USAGE: &'static [u8] = b"
pastabin 0.0.1 - Minimal pastebin clone in Rust. Manual post required. CLI recommended.

    USAGE

      POST /

        accepts raw data in the body of the request and responds with a URL of
        a page containing the body's content

      GET /<id>

        retrieves the content for the paste with id `<id>`

    EXAMPLE

        Upload a file:

            curl --data-binary @file.txt https://pasta.lol/

        Upload from stdin:

            echo \"Hellow, World\" | curl --data-binary @- https://pasta.lol/

        Delete an existing paste:

            curl -X DELETE https://pasta.lol/<id>

    SOURCE CODE

        https://github.com/nopjmp/pastabin

    LICENSE

        MIT License. https://github.com/nopjmp/pastabin/blob/master/LICENSE.md
    ";

fn retrieve_paste(id: PasteID) -> Option<File> {
    File::open(&id.filename()).ok()
}

fn create_paste(id: &PasteID) -> io::Result<File> {
    OpenOptions::new()
        .write(true)
        .create_new(true)
        .open(&id.filename())
}

macro_rules! try_handle {
    ($res:ident, $e:expr, $statuscode:expr) => {{
        match $e.ok() {
            Some(v) => v,
            None => {
                *$res.status_mut() = $statuscode;
                return;
            },
        }
    }}
}

fn handle(mut req: Request, mut res: Response) {
    match req.method {
        hyper::Get => {
            match req.uri.clone() {
                AbsolutePath(path) => {
                    if path == "/" {
                        res.headers_mut().set(ContentType::plaintext());
                        res.send(USAGE).unwrap();
                    } else if path == "/favicon.ico" {
                        // todo favicon
                        *res.status_mut() = StatusCode::NotFound;
                    } else if let Ok(id) = PasteID::from_str(path.trim_left_matches("/")) {
                        match retrieve_paste(id) {
                            Some(mut file) => {
                                let metadata = try_handle!(res,
                                                           file.metadata(),
                                                           StatusCode::InternalServerError);
                                res.headers_mut().set(ContentLength(metadata.len()));
                                res.headers_mut().set(ContentType::plaintext());
                                io::copy(&mut file, &mut res.start().unwrap()).unwrap();
                            }
                            None => *res.status_mut() = StatusCode::NotFound,
                        }
                    } else {
                        *res.status_mut() = StatusCode::BadRequest;
                    }
                }
                _ => *res.status_mut() = StatusCode::BadRequest,
            }
        }
        hyper::Post => {
            match req.uri.clone() {
                AbsolutePath(path) => {
                    if path != "/" {
                        *res.status_mut() = StatusCode::BadRequest;
                    } else {
                        let mut tries = 0;
                        let mut id = PasteID::new(ID_SIZE);
                        let mut file = create_paste(&id);
                        while file.is_err() && tries < 3 {
                            id = PasteID::new(ID_SIZE);
                            file = create_paste(&id);
                            tries += 1;
                        }
                        if file.is_err() {
                            *res.status_mut() = StatusCode::InternalServerError;
                        } else {
                            try_handle!(res,
                                        io::copy(&mut req,
                                                 &mut try_handle!(res,
                                                                  file,
                                                                  StatusCode::InternalServerError)),
                                        StatusCode::InternalServerError);
                            *res.status_mut() = StatusCode::Created;
                            res.send(format!("https://pasta.lol/{}\n", id).as_bytes())
                                .unwrap();
                        }
                    }
                }
                _ => *res.status_mut() = StatusCode::BadRequest,
            }
        }
        hyper::Delete => {
            match req.uri.clone() {
                AbsolutePath(path) => {
                    let id = try_handle!(res,
                                         PasteID::from_str(path.trim_left_matches("/")),
                                         StatusCode::BadRequest);
                    let filename = id.filename();
                    let path = Path::new(&filename);
                    if path.exists() {
                        try_handle!(res, remove_file(path), StatusCode::InternalServerError);
                    } else {
                        *res.status_mut() = StatusCode::NotFound;
                    }
                }
                _ => *res.status_mut() = StatusCode::BadRequest,
            }
        }
        _ => *res.status_mut() = StatusCode::MethodNotAllowed,
    }
}

fn main() {
    let mut ipv4 = Server::http("127.0.0.1:8080").unwrap();
    ipv4.keep_alive(None);
    let _guardipv4 = ipv4.handle(handle);
}
<|endoftext|>


<commit_before><commit_msg>Start filling out skeleton of main module<commit_after>fn main() {
    // TODO: Parse command-line arguments
    // Set defaults for command line arguments

    // Process and shadow defaults.

    // Todo: Parse Config

    // Initialize/Fork

    // Main loop
    let run = true;
    while run {

    }
}
<|endoftext|>


<commit_before>extern crate curl;
extern crate serde;
extern crate serde_json;
extern crate getopts;
extern crate define;
use define::dictionaries::{Dictionary, wordnik};
use define::thesaureses::Thesaurus;
use std::collections::HashMap;
use std::env;
use getopts::{Matches, Options};

static KEY: &'static str = "a2a73e7b926c924fad7001ca3111acd55af2ffabf50eb4ae5";

fn parse_args() -> (Options, Matches) {
    let argv: Vec<String> = env::args().collect();
    let mut parser = Options::new();
    parser.optflag("t", "thesaurus", "Finds synonyms for word");
    let parsed = parser.parse(&argv[1..]).unwrap();
    (parser, parsed)
}

fn get_sources()
    -> (HashMap<String, Box<Dictionary>>,
        HashMap<String, Box<Thesaurus>>)
{
    // insert your dictionaries here
    let mut dictionaries: HashMap<String, Box<Dictionary>> = HashMap::new();
    let mut wordnik = wordnik::Wordnik::new(KEY);
    dictionaries.insert(String::from("wordnik"), Box::new(wordnik.clone()));
    dictionaries.insert(String::from("example"), Box::new(define::dictionaries::example::ExampleDictionary));
    let mut thesaureses: HashMap<String, Box<Thesaurus>> = HashMap::new();
    thesaureses.insert(String::from("wordnik"), Box::new(wordnik.clone()));
    (dictionaries, thesaureses)
}
fn print_definition<'a, T: Dictionary + ?Sized>(dict: &'a mut Box<T>,
                                                word: &str)
                                                -> Result<(), &'a str> {
    let definitions = try!(dict.get_definitions(word));
    println!("{}", definitions[0].text);
    Ok(())
}

fn print_synonyms<'a, T: Thesaurus + ?Sized>(thes: &'a mut Box<T>, word: &str) -> Result<(), &'a str> {
    let synonyms = try!(thes.get_synonyms(word));
    println!("{}", synonyms.join(", "));
    Ok(())
}
fn main() {
    let (mut dictionaries, mut thesaureses) = get_sources();
    let mut dictionary = dictionaries.get_mut("wordnik").unwrap();
    let mut thesaurus = thesaureses.get_mut("wordnik").unwrap();
    let (opts, args) = parse_args(); //we needs opts too for printing brief description
    if args.free.is_empty() {
        println!("{}", opts.usage("USAGE: define WORD"));
    }
    for word in &args.free {
        println!("{}:", word.to_uppercase());
        print_definition(dictionary, word).unwrap_or_else(|err| println!("{}", err));
        if args.opt_present("t") {
            println!("SYNONYMS:");
            print_synonyms(thesaurus, word).unwrap_or_else(|err| println!("{}", err));
        }
    }
}
<commit_msg>Added multi definition support<commit_after>extern crate curl;
extern crate serde;
extern crate serde_json;
extern crate getopts;
extern crate define;
use define::dictionaries::{Dictionary, wordnik};
use define::thesaureses::Thesaurus;
use std::collections::HashMap;
use std::env;
use getopts::{Matches, Options};

static KEY: &'static str = "a2a73e7b926c924fad7001ca3111acd55af2ffabf50eb4ae5";

fn parse_args() -> (Options, Matches) {
    let argv: Vec<String> = env::args().collect();
    let mut parser = Options::new();
    parser.optflag("t", "thesaurus", "Finds synonyms for word");
    let parsed = parser.parse(&argv[1..]).unwrap();
    (parser, parsed)
}

fn get_sources()
    -> (HashMap<String, Box<Dictionary>>,
        HashMap<String, Box<Thesaurus>>)
{
    // insert your dictionaries here
    let mut dictionaries: HashMap<String, Box<Dictionary>> = HashMap::new();
    let wordnik = wordnik::Wordnik::new(KEY);
    dictionaries.insert(String::from("wordnik"), Box::new(wordnik.clone()));
    dictionaries.insert(String::from("example"),
                        Box::new(define::dictionaries::example::ExampleDictionary));
    let mut thesaureses: HashMap<String, Box<Thesaurus>> = HashMap::new();
    thesaureses.insert(String::from("wordnik"), Box::new(wordnik.clone()));
    (dictionaries, thesaureses)
}
fn print_definition<'a, T: Dictionary + ?Sized>(dict: &'a mut Box<T>,
                                                word: &str,
                                                max_definitions: Option<usize>)
                                                -> Result<(), &'a str> {
    let definitions = try!(dict.get_definitions(word));
    let max_definitions = max_definitions.unwrap_or(1);
    if max_definitions > 1 {
        for (wordnumber, word) in definitions.iter().take(max_definitions).enumerate() {
            println!("{}. {}", wordnumber + 1, word.text);
        }
    } else {
        println!("{}", definitions[0].text);
    }
    Ok(())
}

fn print_synonyms<'a, T: Thesaurus + ?Sized>(thes: &'a mut Box<T>,
                                             word: &str)
                                             -> Result<(), &'a str> {
    let synonyms = try!(thes.get_synonyms(word));
    println!("{}", synonyms.join(", "));
    Ok(())
}
fn main() {
    let (mut dictionaries, mut thesaureses) = get_sources();
    let mut dictionary = dictionaries.get_mut("wordnik").unwrap();
    let mut thesaurus = thesaureses.get_mut("wordnik").unwrap();
    let (opts, args) = parse_args(); //we needs opts too for printing brief description
    if args.free.is_empty() {
        println!("{}", opts.usage("USAGE: define WORD"));
    }
    for word in &args.free {
        println!("{}:", word.to_uppercase());
        print_definition(dictionary, word, None).unwrap_or_else(|err| println!("{}", err));
        if args.opt_present("t") {
            println!("SYNONYMS:");
            print_synonyms(thesaurus, word).unwrap_or_else(|err| println!("{}", err));
        }
    }
}
<|endoftext|>


<commit_before>#![feature(dir_entry_ext)]
#![feature(symlink_metadata)]
#![feature(path_relative_from)]
#![feature(file_type)]
#[macro_use]
extern crate log;
extern crate env_logger;

use std::path::PathBuf;
use std::collections::HashSet;
use std::iter::FromIterator;
use std::borrow::Borrow;

use std::fs;
use std::io;

#[derive(Debug)]
struct Stage {
    path: PathBuf
}

#[derive(Debug)]
struct Checkout {
    path: PathBuf,
    ignore: HashSet<PathBuf>
}

#[derive(Debug)]
struct PathInfo {
    path: PathBuf,
    pub id: PathBuf
}

impl PathInfo {
    pub fn new<T: Into<PathBuf>, V: Into<PathBuf>>(path: T, id: V) -> PathInfo {
        PathInfo {
            path: path.into(),
            id: id.into()
        }
    }

    pub fn metadata(&self) -> Result<fs::Metadata, io::Error> {
        fs::symlink_metadata(&self.path)
    }

    pub fn copy<T: Into<PathBuf>>(&self, to: T) -> Result<(), io::Error> {
        match self.metadata() {
            Err(e) => {
                error!("Failed to get metadata for path {:?}: {}", self.path, e);
                return Err(e);
            },
            Ok(data) => {
                trace!("Successfully got metadata");
                if data.is_dir() {
                    trace!("Copying as directory");
                    self.copy_dir(to)
                } else if data.is_file() {
                    trace!("Copying as file");
                    self.copy_file(to)
                } else {
                    error!("{} is neither a file or a directory", self.path.display());
                    unimplemented!()
                }
            }
        }
    }

    fn copy_dir<T: Into<PathBuf>>(&self, to: T) -> Result<(), io::Error> {
        let dest_path = to.into().join(&self.id);
        debug!("Creating directory at {:?}", &dest_path);
        match fs::create_dir_all(dest_path) {
            Err(e) => {
                error!("Failed to create directory: {}", e);
                Err(e)
            },
            Ok(_) => {
                trace!("Directory created successfully");
                Ok(())
            }
        }
    }

    fn copy_file<T: Into<PathBuf>>(&self, to: T) -> Result<(), io::Error> {
        let dest_path = to.into().join(&self.id);

        debug!("Creating parent directory for path");
        match fs::create_dir_all(dest_path.parent().unwrap()) {
            Err(e) => {
                error!("Failed to create parent directory: {}", e);
                return Err(e);
            },
            Ok(_) => {
                trace!("Directory created");
            }
        }

        debug!("Copying {:?} to {:?}", &self.path, &dest_path);
        match fs::copy(&self.path, &dest_path) {
            Err(e) => {
                error!("Failed to copy {} to {}: {}", self.path.display(), dest_path.display(), e);
                Err(e)
            },
            Ok(_) => {
                trace!("Copy succeeded");
                Ok(())
            }
        }
    }
}

impl Default for Stage {
    fn default() -> Stage {
        Stage::new("./.h2/stage")
    }
}

impl Stage {
    pub fn new<T: Into<PathBuf>>(path: T) -> Stage {
        Stage {
            path: path.into(),
        }
    }

    pub fn init(&mut self) -> Result<(), io::Error> {
        info!("Creating Stage");
        match fs::create_dir_all(&self.path) {
            Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => {
                trace!("Directory already existed");
                Ok(())
            },
            Err(e) => {
                error!("Failed to create directory \"{}\": {}", self.path.display(), e);
                Err(e)
            },
            Ok(_) => {
                trace!("Directory created");
                Ok(())
            }
        }
    }

    pub fn add_path(&mut self, path: &PathInfo) -> Result<(), io::Error> {
        // "add" means update. If anything already exists, it's overwritten.
        info!("Adding path {:?}", path);
        path.copy(&self.path)
    }
}

impl Default for Checkout {
    fn default() -> Checkout {
        Checkout::new::<_, PathBuf, _>(".", vec![])
    }
}

impl Checkout {
    pub fn new<T: Into<PathBuf>, U: Into<PathBuf>, V: IntoIterator<Item=U>>(path: T, ignore: V) -> Checkout {
        Checkout {
            path: path.into(),
            ignore: HashSet::from_iter(ignore.into_iter().map(|x| {x.into()}))
        }
    }

    pub fn init(&mut self) -> Result<(), io::Error> {
        info!("Creating checkout");
        match fs::create_dir_all(&self.path) {
            Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => {
                trace!("Directory already existed");
                Ok(())
            },
            Err(e) => {
                error!("Failed to create directory \"{}\": {}", self.path.display(), e);
                Err(e)
            },
            Ok(_) => {
                trace!("Directory created");
                Ok(())
            }
        }
    }

    pub fn ignore<T: Into<PathBuf>>(&mut self, path: T) -> bool {
        self.ignore.insert(path.into())
    }

    pub fn track<T: Borrow<PathBuf>>(&mut self, path: T) -> bool {
        self.ignore.remove(path.borrow())
    }

    pub fn is_ignored<T: Borrow<PathBuf>>(&self, path: T) -> bool {
        self.ignore.contains(path.borrow())
    }

    pub fn stage_dir_all<T: Into<PathBuf>>(&self, stage: &mut Stage, path: T) -> Result<(), io::Error> {
        let mut to_visit = vec![self.path.join(path.into())];

        info!("Copying directory tree");
        while !to_visit.is_empty() {
            trace!("Popping directory from queue");
            let dir = to_visit.pop().unwrap();
            debug!("Reading directory {:?}", dir);
            for item in match fs::read_dir(dir) {
                Ok(iter) => iter,
                Err(e) => {
                    error!("Failed to read directory: {}", e);
                    return Err(e);
                }
            } {
                let entry = match item {
                    Ok(item) => {
                        trace!("No new error");
                        item
                    },
                    Err(e) => {
                        error!("Error reading directory: {}", e);
                        return Err(e);
                    }
                };

                trace!("Getting path relative to checkout directory");
                let id = match entry.path().relative_from(&self.path) {
                    Some(id) => {
                        trace!("Got path relative_from successfully");
                        PathBuf::from(id)
                    },
                    None => {
                        panic!("Failed to get path relative to checkout path");
                    }
                };

                trace!("Entry path: {:?}", entry.path());
                if self.is_ignored(&id) {
                    // ignore our own directory
                    trace!("Path was in ignore set");
                    continue;
                }

                trace!("Getting file type");
                match entry.file_type() {
                    Ok(ref ty) if ty.is_dir() => {
                        debug!("Adding path to visit queue");
                        to_visit.push(entry.path());
                    },
                    Ok(_) => {
                        trace!("Not adding path to visit queue");
                    },
                    Err(e) => {
                        error!("Could not get file type: {}", e);
                        return Err(e);
                    }
                }

                // create the PathInfo object
                let info = PathInfo::new(entry.path(), id);

                debug!("Adding path to stage");
                match stage.add_path(&info) {
                    Ok(()) => {
                        trace!("Add path succeeded");
                    },
                    Err(e) => {
                        error!("Add path failed: {}", e);
                        return Err(e);
                    }
                }
            }
        }

        trace!("Init finished");
        Ok(())
    }

}

fn main() {
    // start up logging
    match env_logger::init() {
        Ok(()) => {
            trace!("Logger initialization successful");
        },
        Err(e) => {
            panic!("Failed to start up logging: {}", e);
        }
    }

    info!("Init in current directory");
    match init() {
        Ok(()) => {
            trace!("Init successful");
        },
        Err(e) => {
            panic!("Init failed: {}", e);
        }
    }

    trace!("Creating checkout object");
    let mut checkout = Checkout::default();
    trace!("Ignoring repo directory");
    checkout.ignore(".h2");
    debug!("Initializing checkout");
    match checkout.init() {
        Ok(()) => {
            trace!("Checkout creation successful");
        },
        Err(e) => {
            panic!("Checkout creation failed: {}", e);
        }
    }

    trace!("Creating Stage object");
    let mut stage = Stage::default();
    debug!("Initializing stage");
    match stage.init() {
        Ok(()) => {
            trace!("Stage creation successful");
        },
        Err(e) => {
            panic!("Stage creation failed: {}", e);
        }
    }

    info!("Walking current directory");
    match checkout.stage_dir_all(&mut stage, PathBuf::from(".")) {
        Ok(()) => {
            debug!("Walk successful");
        },
        Err(e) => {
            panic!("Walk failed: {}", e);
        }
    }
}

fn init() -> Result<(), io::Error> {
    info!("Creating half2 directories");

    debug!("Creating ./.h2");
    match fs::create_dir("./.h2") {
        Err(e) => {
            error!("Failed to create directory \".h2\": {}", e);
            return Err(e);
        },
        Ok(_) => {
            trace!("Directory created");
        }
    }

    debug!("Creating ./.h2/logs");
    match fs::create_dir("./.h2/logs") {
        Err(e) => {
            error!("Failed to create directory \".h2/logs\": {}", e);
            return Err(e);
        },
        Ok(_) => {
            trace!("Directory created");
        }
    }

    Ok(())
}

<commit_msg>Change ignore list to only affect stage_dir_all<commit_after>#![feature(dir_entry_ext)]
#![feature(symlink_metadata)]
#![feature(path_relative_from)]
#![feature(file_type)]
#[macro_use]
extern crate log;
extern crate env_logger;

use std::path::PathBuf;
use std::collections::HashSet;
use std::iter::FromIterator;

use std::fs;
use std::io;

#[derive(Debug)]
struct Stage {
    path: PathBuf
}

#[derive(Debug)]
struct Checkout {
    path: PathBuf
}

#[derive(Debug)]
struct PathInfo {
    path: PathBuf,
    pub id: PathBuf
}

impl PathInfo {
    pub fn new<T: Into<PathBuf>, V: Into<PathBuf>>(path: T, id: V) -> PathInfo {
        PathInfo {
            path: path.into(),
            id: id.into()
        }
    }

    pub fn metadata(&self) -> Result<fs::Metadata, io::Error> {
        fs::symlink_metadata(&self.path)
    }

    pub fn copy<T: Into<PathBuf>>(&self, to: T) -> Result<(), io::Error> {
        match self.metadata() {
            Err(e) => {
                error!("Failed to get metadata for path {:?}: {}", self.path, e);
                return Err(e);
            },
            Ok(data) => {
                trace!("Successfully got metadata");
                if data.is_dir() {
                    trace!("Copying as directory");
                    self.copy_dir(to)
                } else if data.is_file() {
                    trace!("Copying as file");
                    self.copy_file(to)
                } else {
                    error!("{} is neither a file or a directory", self.path.display());
                    unimplemented!()
                }
            }
        }
    }

    fn copy_dir<T: Into<PathBuf>>(&self, to: T) -> Result<(), io::Error> {
        let dest_path = to.into().join(&self.id);
        debug!("Creating directory at {:?}", &dest_path);
        match fs::create_dir_all(dest_path) {
            Err(e) => {
                error!("Failed to create directory: {}", e);
                Err(e)
            },
            Ok(_) => {
                trace!("Directory created successfully");
                Ok(())
            }
        }
    }

    fn copy_file<T: Into<PathBuf>>(&self, to: T) -> Result<(), io::Error> {
        let dest_path = to.into().join(&self.id);

        debug!("Creating parent directory for path");
        match fs::create_dir_all(dest_path.parent().unwrap()) {
            Err(e) => {
                error!("Failed to create parent directory: {}", e);
                return Err(e);
            },
            Ok(_) => {
                trace!("Directory created");
            }
        }

        debug!("Copying {:?} to {:?}", &self.path, &dest_path);
        match fs::copy(&self.path, &dest_path) {
            Err(e) => {
                error!("Failed to copy {} to {}: {}", self.path.display(), dest_path.display(), e);
                Err(e)
            },
            Ok(_) => {
                trace!("Copy succeeded");
                Ok(())
            }
        }
    }
}

impl Default for Stage {
    fn default() -> Stage {
        Stage::new("./.h2/stage")
    }
}

impl Stage {
    pub fn new<T: Into<PathBuf>>(path: T) -> Stage {
        Stage {
            path: path.into(),
        }
    }

    pub fn init(&mut self) -> Result<(), io::Error> {
        info!("Creating Stage");
        match fs::create_dir_all(&self.path) {
            Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => {
                trace!("Directory already existed");
                Ok(())
            },
            Err(e) => {
                error!("Failed to create directory \"{}\": {}", self.path.display(), e);
                Err(e)
            },
            Ok(_) => {
                trace!("Directory created");
                Ok(())
            }
        }
    }

    pub fn add_path(&mut self, path: &PathInfo) -> Result<(), io::Error> {
        // "add" means update. If anything already exists, it's overwritten.
        info!("Adding path {:?}", path);
        path.copy(&self.path)
    }
}

impl Default for Checkout {
    fn default() -> Checkout {
        Checkout::new(".")
    }
}

impl Checkout {
    pub fn new<T: Into<PathBuf>>(path: T) -> Checkout {
        Checkout {
            path: path.into()
        }
    }

    pub fn init(&mut self) -> Result<(), io::Error> {
        info!("Creating checkout");
        match fs::create_dir_all(&self.path) {
            Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => {
                trace!("Directory already existed");
                Ok(())
            },
            Err(e) => {
                error!("Failed to create directory \"{}\": {}", self.path.display(), e);
                Err(e)
            },
            Ok(_) => {
                trace!("Directory created");
                Ok(())
            }
        }
    }

    pub fn stage_dir_all<T: Into<PathBuf>, V: IntoIterator>(&self, stage: &mut Stage, path: T, ignore: V) -> Result<(), io::Error> where V::Item: Into<PathBuf> {
        let mut to_visit = vec![self.path.join(path.into())];
        let to_ignore: HashSet<PathBuf> = HashSet::from_iter(ignore.into_iter().map(|x| {x.into()}));

        info!("Copying directory tree");
        while !to_visit.is_empty() {
            trace!("Popping directory from queue");
            let dir = to_visit.pop().unwrap();
            debug!("Reading directory {:?}", dir);
            for item in match fs::read_dir(dir) {
                Ok(iter) => iter,
                Err(e) => {
                    error!("Failed to read directory: {}", e);
                    return Err(e);
                }
            } {
                let entry = match item {
                    Ok(item) => {
                        trace!("No new error");
                        item
                    },
                    Err(e) => {
                        error!("Error reading directory: {}", e);
                        return Err(e);
                    }
                };

                trace!("Getting path relative to checkout directory");
                let id = match entry.path().relative_from(&self.path) {
                    Some(id) => {
                        trace!("Got path relative_from successfully");
                        PathBuf::from(id)
                    },
                    None => {
                        panic!("Failed to get path relative to checkout path");
                    }
                };

                trace!("Entry path: {:?}", entry.path());
                if to_ignore.contains(&id) {
                    // ignore our own directory
                    trace!("Path was in ignore set");
                    continue;
                }

                trace!("Getting file type");
                match entry.file_type() {
                    Ok(ref ty) if ty.is_dir() => {
                        debug!("Adding path to visit queue");
                        to_visit.push(entry.path());
                    },
                    Ok(_) => {
                        trace!("Not adding path to visit queue");
                    },
                    Err(e) => {
                        error!("Could not get file type: {}", e);
                        return Err(e);
                    }
                }

                trace!("Creating path info object");
                let info = PathInfo::new(entry.path(), id);

                debug!("Adding path to stage");
                match stage.add_path(&info) {
                    Ok(()) => {
                        trace!("Add path succeeded");
                    },
                    Err(e) => {
                        error!("Add path failed: {}", e);
                        return Err(e);
                    }
                }
            }
        }

        trace!("Init finished");
        Ok(())
    }

}

fn main() {
    // start up logging
    match env_logger::init() {
        Ok(()) => {
            trace!("Logger initialization successful");
        },
        Err(e) => {
            panic!("Failed to start up logging: {}", e);
        }
    }

    info!("Init in current directory");
    match init() {
        Ok(()) => {
            trace!("Init successful");
        },
        Err(e) => {
            panic!("Init failed: {}", e);
        }
    }

    trace!("Creating checkout object");
    let mut checkout = Checkout::default();
    debug!("Initializing checkout");
    match checkout.init() {
        Ok(()) => {
            trace!("Checkout creation successful");
        },
        Err(e) => {
            panic!("Checkout creation failed: {}", e);
        }
    }

    trace!("Creating Stage object");
    let mut stage = Stage::default();
    debug!("Initializing stage");
    match stage.init() {
        Ok(()) => {
            trace!("Stage creation successful");
        },
        Err(e) => {
            panic!("Stage creation failed: {}", e);
        }
    }

    info!("Walking current directory");
    match checkout.stage_dir_all(&mut stage, PathBuf::from("."), vec![".h2"]) {
        Ok(()) => {
            debug!("Walk successful");
        },
        Err(e) => {
            panic!("Walk failed: {}", e);
        }
    }
}

fn init() -> Result<(), io::Error> {
    info!("Creating half2 directories");

    debug!("Creating ./.h2");
    match fs::create_dir("./.h2") {
        Err(e) => {
            error!("Failed to create directory \".h2\": {}", e);
            return Err(e);
        },
        Ok(_) => {
            trace!("Directory created");
        }
    }

    debug!("Creating ./.h2/logs");
    match fs::create_dir("./.h2/logs") {
        Err(e) => {
            error!("Failed to create directory \".h2/logs\": {}", e);
            return Err(e);
        },
        Ok(_) => {
            trace!("Directory created");
        }
    }

    Ok(())
}

<|endoftext|>


<commit_before>#![feature(core)] //this should be removed before out of beta
extern crate regex;
use regex::Regex;

enum schmAtom {
    Int(i32),
    Float(f32),
    Strng(String),
    Symb(String)
}

fn main() {

}

fn tokenize(input: String) -> Vec<String>{

    let re1 = Regex::new(r"\(").unwrap();
    let re2 = Regex::new(r"\)").unwrap();
    let mut after: String = re1.replace_all(&input,"( ");
    after = re2.replace_all(&after, " )");

    let split = after.split(" "); //split is an iterator
    split.map(|x|{x.to_string()}).collect::<Vec<String>>()
    //^to `.to_string` seems kind of hackish...
    //BUT it actaully just forces the copy and move of the string
}

fn read_from_tokens(){
}

#[cfg(test)]

#[test]
fn test_tokenize() {
    let test_input: String  = "(a b c)".to_string();
    assert_eq!(tokenize(test_input),
               vec!("(","a","b","c", ")"));
}

<commit_msg>Add documentation to tokenize.<commit_after>#![feature(core)] //this should be removed before out of beta
extern crate regex;
use regex::Regex;

enum schmAtom {
    Int(i32),
    Float(f32),
    Strng(String),
    Symb(String)
}

fn main() {

}

fn tokenize(input: String) -> Vec<String>{
    // Split input string into smaller tokens.
    let re1 = Regex::new(r"\(").unwrap();
    let re2 = Regex::new(r"\)").unwrap();
    let mut after: String = re1.replace_all(&input,"( ");
    after = re2.replace_all(&after, " )");

    let split = after.split(" "); //split is an iterator
    split.map(|x|{x.to_string()}).collect::<Vec<String>>()
    //^to `.to_string` seems kind of hackish...
    //BUT it actaully just forces the copy and move of the string
}

fn read_from_tokens(){
}

#[cfg(test)]

#[test]
fn test_tokenize() {
    let test_input: String  = "(a b c)".to_string();
    assert_eq!(tokenize(test_input),
               vec!("(","a","b","c", ")"));
}

<|endoftext|>


<commit_before>
#![feature(phase)]

extern crate crypto;
extern crate libc;
#[phase(plugin, link)] extern crate log;

use crypto::sha2::Sha512;
use crypto::digest::Digest;
use libc::{getgid, getuid};
use std::os;
use std::io::{OTHER_EXECUTE, OTHER_READ,
              GROUP_EXECUTE, GROUP_READ, GROUP_RWX,
              USER_EXECUTE,  USER_RWX, ALL_PERMISSIONS};
use std::io::fs::{File, PathExtensions, mkdir, mkdir_recursive, chmod};
use std::io::process::{Command, InheritFd, ExitStatus};

const CACHE_SUBPATH: &'static str = "pexe-runner-cache";
// TODO: support overriding cache location.
const CACHE_BASE: &'static str = "/tmp";

const RUST_PNACL_TRANS: &'static str = "rust-pnacl-trans";

pub fn main() {
    let args = os::args();
    if args.len() != 2 { return; }
    let pexe_path = Path::new(args[1].as_slice());
    let pexe_filename = Path::new(pexe_path.filename().unwrap());

    let cache = Path::new(CACHE_BASE).join(CACHE_SUBPATH);
    if !cache.exists() {
        mkdir_recursive(&cache, ALL_PERMISSIONS).unwrap();
    }

    // if the binary is rx by the world, don't use a user prefix when caching.

    let mut pexe = File::open(&pexe_path).unwrap();

    let pexe_stat = pexe.stat().unwrap();
    let (cache_dir, perms) = if pexe_stat.perm.contains(OTHER_EXECUTE | OTHER_READ) {
        let c = cache.join("other");
        if !c.exists() {
            mkdir(&c, ALL_PERMISSIONS).unwrap();
        }
        (c, ALL_PERMISSIONS)
    } else if pexe_stat.perm.contains(GROUP_EXECUTE | GROUP_READ) {
        let c = cache.join("group");
        if !c.exists() {
            mkdir(&c, ALL_PERMISSIONS).unwrap();
        }
        let gid = unsafe { getgid() };
        let c = c.join(format!("{}", gid));
        if !c.exists() {
            mkdir(&c, GROUP_RWX | USER_RWX).unwrap();
        }
        (c, GROUP_RWX | USER_RWX)
    } else if pexe_stat.perm.contains(USER_EXECUTE) {
        let c = cache.join("user");
        if !c.exists() {
            mkdir(&c, ALL_PERMISSIONS).unwrap();
        }
        let uid = unsafe { getuid() };
        let c = c.join(format!("{}", uid));
        if !c.exists() {
            mkdir(&c, USER_RWX).unwrap();
        }
        (c, USER_RWX)
    } else {
        panic!("cann't execute: permissing denied");
    };

    let pexe_bin = pexe.read_to_end().unwrap();

    let mut hasher = Sha512::new();
    hasher.input(pexe_bin.as_slice());
    let cache_dir = cache_dir.join(hasher.result_str());
    if !cache_dir.exists() {
        mkdir(&cache_dir, perms).unwrap();
    }
    let nexe_path = cache_dir
        .join(pexe_filename.with_extension("nexe"));

    let nacl_sdk_root = env!("NACL_SDK_ROOT");

    if !nexe_path.exists() {
        let mut cmd = Command::new(RUST_PNACL_TRANS);
        cmd.arg("--cross-path");
        cmd.arg(nacl_sdk_root);
        cmd.arg(pexe_path.display().to_string());
        cmd.arg("-o");
        cmd.arg(nexe_path.display().to_string());
        cmd.arg("--opt-level=2");
        debug!("trans cmd line: `{}`", cmd);
        let mut trans = cmd.spawn().unwrap();

        let output = trans.wait_with_output().unwrap();
        let status = output.status;
        match status {
            ExitStatus(0) => {
                chmod(&nexe_path, perms).unwrap();
            }
            ExitStatus(code) | ExitSignal(code) => {
                let mut stderr = ::std::io::stdio::stderr();
                let mut stdout = ::std::io::stdio::stdout();
                writeln!(stderr, "`{}` failed:", cmd);
                stdout.write(output.output.as_slice()).unwrap();
                stderr.write(output.error.as_slice()).unwrap();
                os::set_exit_status(code);
                return;
            }
        }
    }

    let nacl_sdk_root = Path::new(nacl_sdk_root);
    let tools = nacl_sdk_root.join("tools");
    let nacl_helper_bootstrap = tools.join("nacl_helper_bootstrap_x86_64");
    let sel_ldr_bin = tools.join("sel_ldr_x86_64");
    let irt_core = tools.join("irt_core_x86_64.nexe");

    let mut sel_ldr_args = vec!(sel_ldr_bin.display().to_string(),
                                "--r_debug=0xXXXXXXXXXXXXXXXX".to_string(),
                                "--reserved_at_zero=0xXXXXXXXXXXXXXXXX".to_string(),
                                //"-a".to_string(),
                                "-B".to_string(),
                                irt_core.display().to_string(),
                                "-l".to_string(), "/dev/null".to_string());
    sel_ldr_args.push("--".to_string());
    sel_ldr_args.push(nexe_path.display().to_string());
    sel_ldr_args.extend(args.slice_from(2).to_vec().into_iter());

    let mut cmd = Command::new(nacl_helper_bootstrap);
    cmd.args(sel_ldr_args.as_slice());
    cmd.stdout(InheritFd(libc::STDOUT_FILENO));
    cmd.stderr(InheritFd(libc::STDERR_FILENO));
    debug!("sel_ldr cmd line: `{}`", cmd);
    match cmd.spawn() {
        Ok(mut process) => {
            match process.wait() {
                Ok(ExitStatus(status)) => {
                    os::set_exit_status(status);
                }
                Ok(_) => {
                    os::set_exit_status(1);
                }
                Err(e) => {
                    panic!("couldn't wait on sel_ldr: {}", e);
                }
            }
        }
        Err(e) => {
            panic!("couldn't spawn sel_ldr: {}", e);
        }
    }
}
<commit_msg>Add forgotten import.<commit_after>
#![feature(phase)]

extern crate crypto;
extern crate libc;
#[phase(plugin, link)] extern crate log;

use crypto::sha2::Sha512;
use crypto::digest::Digest;
use libc::{getgid, getuid};
use std::os;
use std::io::{OTHER_EXECUTE, OTHER_READ,
              GROUP_EXECUTE, GROUP_READ, GROUP_RWX,
              USER_EXECUTE,  USER_RWX, ALL_PERMISSIONS};
use std::io::fs::{File, PathExtensions, mkdir, mkdir_recursive, chmod};
use std::io::process::{Command, InheritFd, ExitStatus, ExitSignal};

const CACHE_SUBPATH: &'static str = "pexe-runner-cache";
// TODO: support overriding cache location.
const CACHE_BASE: &'static str = "/tmp";

const RUST_PNACL_TRANS: &'static str = "rust-pnacl-trans";

pub fn main() {
    let args = os::args();
    if args.len() != 2 { return; }
    let pexe_path = Path::new(args[1].as_slice());
    let pexe_filename = Path::new(pexe_path.filename().unwrap());

    let cache = Path::new(CACHE_BASE).join(CACHE_SUBPATH);
    if !cache.exists() {
        mkdir_recursive(&cache, ALL_PERMISSIONS).unwrap();
    }

    // if the binary is rx by the world, don't use a user prefix when caching.

    let mut pexe = File::open(&pexe_path).unwrap();

    let pexe_stat = pexe.stat().unwrap();
    let (cache_dir, perms) = if pexe_stat.perm.contains(OTHER_EXECUTE | OTHER_READ) {
        let c = cache.join("other");
        if !c.exists() {
            mkdir(&c, ALL_PERMISSIONS).unwrap();
        }
        (c, ALL_PERMISSIONS)
    } else if pexe_stat.perm.contains(GROUP_EXECUTE | GROUP_READ) {
        let c = cache.join("group");
        if !c.exists() {
            mkdir(&c, ALL_PERMISSIONS).unwrap();
        }
        let gid = unsafe { getgid() };
        let c = c.join(format!("{}", gid));
        if !c.exists() {
            mkdir(&c, GROUP_RWX | USER_RWX).unwrap();
        }
        (c, GROUP_RWX | USER_RWX)
    } else if pexe_stat.perm.contains(USER_EXECUTE) {
        let c = cache.join("user");
        if !c.exists() {
            mkdir(&c, ALL_PERMISSIONS).unwrap();
        }
        let uid = unsafe { getuid() };
        let c = c.join(format!("{}", uid));
        if !c.exists() {
            mkdir(&c, USER_RWX).unwrap();
        }
        (c, USER_RWX)
    } else {
        panic!("cann't execute: permissing denied");
    };

    let pexe_bin = pexe.read_to_end().unwrap();

    let mut hasher = Sha512::new();
    hasher.input(pexe_bin.as_slice());
    let cache_dir = cache_dir.join(hasher.result_str());
    if !cache_dir.exists() {
        mkdir(&cache_dir, perms).unwrap();
    }
    let nexe_path = cache_dir
        .join(pexe_filename.with_extension("nexe"));

    let nacl_sdk_root = env!("NACL_SDK_ROOT");

    if !nexe_path.exists() {
        let mut cmd = Command::new(RUST_PNACL_TRANS);
        cmd.arg("--cross-path");
        cmd.arg(nacl_sdk_root);
        cmd.arg(pexe_path.display().to_string());
        cmd.arg("-o");
        cmd.arg(nexe_path.display().to_string());
        cmd.arg("--opt-level=2");
        debug!("trans cmd line: `{}`", cmd);
        let mut trans = cmd.spawn().unwrap();

        let output = trans.wait_with_output().unwrap();
        let status = output.status;
        match status {
            ExitStatus(0) => {
                chmod(&nexe_path, perms).unwrap();
            }
            ExitStatus(code) | ExitSignal(code) => {
                let mut stderr = ::std::io::stdio::stderr();
                let mut stdout = ::std::io::stdio::stdout();
                writeln!(stderr, "`{}` failed:", cmd);
                stdout.write(output.output.as_slice()).unwrap();
                stderr.write(output.error.as_slice()).unwrap();
                os::set_exit_status(code);
                return;
            }
        }
    }

    let nacl_sdk_root = Path::new(nacl_sdk_root);
    let tools = nacl_sdk_root.join("tools");
    let nacl_helper_bootstrap = tools.join("nacl_helper_bootstrap_x86_64");
    let sel_ldr_bin = tools.join("sel_ldr_x86_64");
    let irt_core = tools.join("irt_core_x86_64.nexe");

    let mut sel_ldr_args = vec!(sel_ldr_bin.display().to_string(),
                                "--r_debug=0xXXXXXXXXXXXXXXXX".to_string(),
                                "--reserved_at_zero=0xXXXXXXXXXXXXXXXX".to_string(),
                                //"-a".to_string(),
                                "-B".to_string(),
                                irt_core.display().to_string(),
                                "-l".to_string(), "/dev/null".to_string());
    sel_ldr_args.push("--".to_string());
    sel_ldr_args.push(nexe_path.display().to_string());
    sel_ldr_args.extend(args.slice_from(2).to_vec().into_iter());

    let mut cmd = Command::new(nacl_helper_bootstrap);
    cmd.args(sel_ldr_args.as_slice());
    cmd.stdout(InheritFd(libc::STDOUT_FILENO));
    cmd.stderr(InheritFd(libc::STDERR_FILENO));
    debug!("sel_ldr cmd line: `{}`", cmd);
    match cmd.spawn() {
        Ok(mut process) => {
            match process.wait() {
                Ok(ExitStatus(status)) => {
                    os::set_exit_status(status);
                }
                Ok(_) => {
                    os::set_exit_status(1);
                }
                Err(e) => {
                    panic!("couldn't wait on sel_ldr: {}", e);
                }
            }
        }
        Err(e) => {
            panic!("couldn't spawn sel_ldr: {}", e);
        }
    }
}
<|endoftext|>


<commit_before>#![allow(match_of_unit_variant_via_paren_dotdot)]

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

use std::io::Read;

mod lexer {
    use std::fmt::Display;
    use std::fmt::Formatter;
    use std::fmt;

    #[derive(Debug, Clone)]
    #[derive(PartialEq)]
    pub enum Token {
        EOF,
        Def,
        Extern,
        Identifier(String),
        Number(f32),

        Whitespace,
        Comment,
    }

    impl Token {
        pub fn contents(&self) -> Option<&str> {
            let s = match *self {
                Token::Identifier(ref s) => s,
                _ => return None,
            };
            Some(s)
        }
    }

    /// The Lexer
    #[derive(Debug)]
    pub struct Lexer<'a> {
        source: &'a str,
        remaining: &'a str,
    }

    impl<'a> Lexer<'a> {
        /// Create a new Lexer
        pub fn new(src: &'a str) -> Self {
            Lexer {
                source: src,
                remaining: src,
            }
        }
    }

    impl<'a> Iterator for Lexer<'a> {
        type Item = (Token, TextSpan);

        fn next(&mut self) -> Option<Self::Item> {
            loop {
                if let Some(token) = take_token(&mut self.remaining) {
                    if let (Token::Whitespace, _) = token {
                        continue;
                    } else {
                        let (token, span) = token;
                        let text_span = TextSpan::from(self.source, self.remaining, span);
                        return Some((token, text_span));
                    }
                } else {
                    return None;
                }
            }
        }
    }

    lexer! {
        fn take_token(text: 'a) -> (Token, &'a str); // Token and the rest

        r#"[ \t\r\n]+"# => (Token::Whitespace, text),
        // "C-style" comments (/* .. */) - can't contain "*/"
        r#"/[*](~(.*[*]/.*))[*]/"# => (Token::Comment, text),
        // "C++-style" comments (// ...)
        r#"//[^\n]*"# => (Token::Comment, text),
        r#"def"# => (Token::Def, text),
        r#"extern"# => (Token::Extern, text),
        r#"[a-zA-Z_][a-zA-Z0-9_]*"# => (Token::Identifier(text.to_owned()), text),
        r#"[0-9.]+"# => {
            (if let Ok(i) = text.parse() {
                Token::Number(i)
            } else {
                panic!("float {} is out of range", text)
            }, text)
        },
    }

    /// A structure for grouping byte offset of text spans.
    #[derive(Debug)]
    #[derive(Copy, Clone)]
    #[derive(Eq, PartialEq)]
    pub struct TextSpan {
        pub low: usize,
        pub high: usize,
    }

    impl TextSpan {
        /// Create a text span from a string and a slice of it.
        pub fn from(source: &str, remaining: &str, token: &str) -> TextSpan {
            let high = source.len() - remaining.len();
            let low = high - token.len();
            TextSpan {
                low: low,
                high: high,
            }
        }

        pub fn merge(a: TextSpan, b: TextSpan) -> TextSpan {
            let low = if a.low < b.low {
                a.low
            } else {
                b.low
            };
            let high = if a.high > b.high {
                a.high
            } else {
                b.high
            };
            TextSpan {
                low: low,
                high: high,
            }
        }
    }

    impl Display for TextSpan {
        fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
            write!(f, "[{}, {})", self.low, self.high)
        }
    }
}

fn main() {
    let mut s = String::new();
    std::io::stdin().read_to_string(&mut s).unwrap();
    let mut result = lexer::Lexer::new(&s);
    for i in result {
        println!("{:?}", i);
    }
}
<commit_msg>ast, parser: init<commit_after>#![allow(match_of_unit_variant_via_paren_dotdot)]

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

use std::io::Read;

mod lexer {
    use std::fmt::Display;
    use std::fmt::Formatter;
    use std::fmt;

    #[derive(PartialEq, Clone, Debug)]
    pub enum Token {
        Def,
        Extern,
        Delimiter, // ';' character
        OpeningParenthesis,
        ClosingParenthesis,
        Comma,
        Identifier(String),
        Number(f64),
        Operator(String),

        Whitespace,
        Comment,
    }

    // ► The Specials - Too Much Too Young

    lexer! {
        fn take_token(text: 'a) -> (Token, &'a str); // Token and the rest

        r#"[ \t\r\n]+"# => (Token::Whitespace, text),
        // "C-style" comments (/* .. */) - can't contain "*/"
        r#"/[*](~(.*[*]/.*))[*]/"# => (Token::Comment, text),
        // "C++-style" comments (// ...)
        r#"//[^\n]*"# => (Token::Comment, text),
        r#"def"# => (Token::Def, text),
        r#"extern"# => (Token::Extern, text),
        r#"[a-zA-Z_][a-zA-Z0-9_]*"# => (Token::Identifier(text.to_owned()), text),
        r#"[0-9.]+"# => {
            (if let Ok(i) = text.parse() {
                Token::Number(i)
            } else {
                panic!("float {} is out of range", text)
            }, text)
        },
        r#"\("# => (Token::OpeningParenthesis, text),
        r#"\)"# => (Token::ClosingParenthesis, text),
        r#";"# => (Token::Delimiter, text),
        r#","# => (Token::Comma, text),
        r#"[\+\-\*\/]+"# => (Token::Operator(text.to_owned()), text),
    }

    impl Token {
        pub fn contents(&self) -> Option<&str> {
            let s = match *self {
                Token::Identifier(ref s) => s,
                _ => return None,
            };
            Some(s)
        }
    }

    /// The Lexer
    #[derive(PartialEq, Clone, Debug, Copy)]
    pub struct Lexer<'a> {
        source: &'a str,
        remaining: &'a str,
    }

    impl<'a> Lexer<'a> {
        /// Create a new Lexer
        pub fn new(src: &'a str) -> Self {
            Lexer {
                source: src,
                remaining: src,
            }
        }
    }

    impl<'a> Iterator for Lexer<'a> {
        type Item = (Token, TextSpan);

        fn next(&mut self) -> Option<Self::Item> {
            loop {
                if let Some(token) = take_token(&mut self.remaining) {
                    if let (Token::Whitespace, _) = token {
                        continue;
                    } else {
                        let (token, span) = token;
                        let text_span = TextSpan::from(self.source, self.remaining, span);
                        return Some((token, text_span));
                    }
                } else {
                    return None;
                }
            }
        }
    }

    /// A structure for grouping byte offset of text spans.
    #[derive(Debug)]
    #[derive(Copy, Clone)]
    #[derive(Eq, PartialEq)]
    pub struct TextSpan {
        pub low: usize,
        pub high: usize,
    }

    impl TextSpan {
        /// Create a text span from a string and a slice of it.
        pub fn from(source: &str, remaining: &str, token: &str) -> TextSpan {
            let high = source.len() - remaining.len();
            let low = high - token.len();
            TextSpan {
                low: low,
                high: high,
            }
        }

        pub fn merge(a: TextSpan, b: TextSpan) -> TextSpan {
            let low = if a.low < b.low {
                a.low
            } else {
                b.low
            };
            let high = if a.high > b.high {
                a.high
            } else {
                b.high
            };
            TextSpan {
                low: low,
                high: high,
            }
        }
    }

    impl Display for TextSpan {
        fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
            write!(f, "[{}, {})", self.low, self.high)
        }
    }
}

mod ast {
    use std::collections::HashMap;

    use lexer::*;

    pub use self::ASTNode::{ExternNode, FunctionNode};
    pub use self::Expression::{LiteralExpr, VariableExpr, BinaryExpr, CallExpr};

    pub struct Program {
        pub astnodes: Vec<ASTNode>,
    }

    #[derive(PartialEq, Clone, Debug)]
    pub enum ASTNode {
        ExternNode(Prototype),
        FunctionNode(Function),
    }

    #[derive(PartialEq, Clone, Debug)]
    pub struct Function {
        pub prototype: Prototype,
        pub body: Expression,
    }

    #[derive(PartialEq, Clone, Debug)]
    pub struct Prototype {
        pub name: String,
        pub args: Vec<String>,
    }

    #[derive(PartialEq, Clone, Debug)]
    pub enum Expression {
        LiteralExpr(f64),
        VariableExpr(String),
        BinaryExpr(String, Box<Expression>, Box<Expression>),
        CallExpr(String, Vec<Expression>),
    }
}

mod parser {
    // Grammar:
    //
    // program : [[statement | expression] Delimiter ?]*;
    // statement : [declaration | definition];
    // declaration : Extern prototype;
    // definition : Def prototype expression;
    // prototype : Identifier OpeningParenthesis [Identifier Comma ?]* ClosingParenthesis;
    // expression : [primary_expr (Operator primary_expr)*];
    // primary_expr : [Identifier | Number | call_expr | parenthesis_expr];
    // call_expr : Identifier OpeningParenthesis [expression Comma ?]* ClosingParenthesis;
    // parenthesis_expr: OpeningParenthesis expression ClosingParenthesis;
    //

    use ast::*;
    use lexer::*;

    use lexer::Token::*;

    parser! {
        fn parse_(Token, TextSpan);

        // Ignore spans
        (a, b) {
            TextSpan::merge(a, b)
        }

        program: Vec<ASTNode> {
            => vec![],
            stex[e] rest[mut p] => {
                p.push(e);
                p
            },
        }

        stex: ASTNode {
            statement[e] => e,
            expression[e] => e
        }

        rest: Vec<ASTNode> {
            program[p] => {
                p
            },
            Delimiter program[p] => {
                p
            },
        }

        statement: ASTNode {
            declaration[e] => {
                e
            },
            definition[e] => {
                e
            }
        }

        declaration: ASTNode {
            Extern prototype[p] => {
                ExternNode(p)
            },
        }

        definition: ASTNode {
            Def prototype[p] expr[e] => {
                FunctionNode(Function {
                    prototype: p,
                    body: e,
                })
            }
        }

        prototype: Prototype {
            Identifier(id) OpeningParenthesis arguments[a] ClosingParenthesis => Prototype {
                name: id,
                args: a,
            }
        }

        arguments: Vec<String> {
            => vec![],
            Identifier(id) extra_args[mut a] => {
                a.push(id);
                a
            }
        }

        extra_args: Vec<String> {
            Comma arguments[a] => {
                a
            },
            arguments[a] => {
                a
            }
        }

        primary_expression: Expression {
           Number(i) => LiteralExpr(i)
        }

        expression: ASTNode {
            primary_expression[e] => {
                let prototype = Prototype {name: "".to_string(), args: vec![]};
                FunctionNode (Function {
                    prototype: prototype,
                    body: e
                })
            }
        }

        expr: Expression {
            => LiteralExpr(0.0)
        }
    }

    pub fn parse<I: Iterator<Item = (Token, TextSpan)>>
        (i: I)
         -> Result<Vec<ASTNode>, (Option<(Token, TextSpan)>, &'static str)> {
        parse_(i)
    }
}

fn main() {
    let mut s = String::new();
    std::io::stdin().read_to_string(&mut s).unwrap();
    let lexer = lexer::Lexer::new(&s);
    for i in lexer {
        println!("{:?}", i);
    }
    println!("{:?}", parser::parse(lexer));
}

#[test]
fn test_parser() {
    use parser::*;
    use ast::*;
    use lexer::*;
    let tests = vec![
        ("extern sin();", vec![ExternNode(Prototype{name:"sin".to_string(), args:vec![]})]),
        ("", vec![]),
        ("def foo(x y x);", vec![FunctionNode(Function { prototype: Prototype { name: "foo".to_string(), args: vec!["x".to_string(), "y".to_string(), "x".to_string()] }, body: LiteralExpr(0.0) })]),
    ];

    for tc in tests {
        let parsed = lexer::Lexer::new(tc.0);
        let r = parser::parse(parsed).unwrap();
        assert_eq!(tc.1, r);
    }
}
<|endoftext|>


<commit_before>extern crate itertools;
extern crate num_traits;
extern crate smallvec;
extern crate rand;

pub mod board;
pub mod player;

use std::time::Duration;

use board::{Board, GameState};
use player::Player;

fn main() {
    let mut b = Board::generate(10, 6);
    let dur = Duration::new(5, 0);
    let players: [Box<Player>; 2] = [Box::new(player::MCTSPlayer::new(dur)),
                                     Box::new(player::MCTSPlayer::new(dur))];
    println!("{}", b);
    for p in players.iter().cycle() {
        let m = p.choose(&b);
        let r = b.make_legal_move(m);
        println!("{}", b);
        match r {
            GameState::Ongoing => (),
            GameState::Drawn => {
                println!("Drawn.");
                break;
            },
            GameState::Won => {
                println!("Won! ({})", b.active());
                break;
            },
        }
    }
}
<commit_msg>Let the humans have fun<commit_after>extern crate itertools;
extern crate num_traits;
extern crate smallvec;
extern crate rand;

pub mod board;
pub mod player;

use std::time::Duration;

use board::{Board, GameState};
use player::Player;

fn main() {
    let mut b = Board::generate(10, 6);
    let dur = Duration::new(5, 0);
    let players: [Box<Player>; 2] = [
        Box::new(player::HumanPlayer),
        //Box::new(player::MCTSPlayer::new(dur)),
        Box::new(player::MCTSPlayer::new(dur)),
    ];
    println!("{}", b);
    for p in players.iter().cycle() {
        let m = p.choose(&b);
        let r = b.make_legal_move(m);
        println!("{}", b);
        match r {
            GameState::Ongoing => (),
            GameState::Drawn => {
                println!("Drawn.");
                break;
            },
            GameState::Won => {
                println!("Won! ({})", b.active());
                break;
            },
        }
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::io::prelude::*;
use std::fs::File;
extern crate uuid;
use uuid::Uuid;
extern crate getopts;
use getopts::Options;
use std::io;

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} FILE [options]", program);
    print!("{}", opts.usage(&brief));
}

fn redirect_to_file(outfile: &str) -> Result<(), io::Error> {
    let mut tempfile = env::temp_dir();
    tempfile.push(Uuid::new_v4().hyphenated().to_string());
    //println!("{}", tempfile.display());

    {
        let mut buffer = [0; 512];
        let mut stdin = io::stdin();
        let mut f = File::create(&tempfile).unwrap();

        loop {
            let read_bytes = stdin.read(&mut buffer).unwrap();
            if read_bytes == 0 {
                break;
            }

            let write_bytes = match f.write(&buffer[0 .. read_bytes]) {
				Ok(m) => { m }
				Err(e) => panic!("{}", e)
			};

			assert!(write_bytes == read_bytes);
        }
    }

    match std::fs::rename(&tempfile, &outfile) {
		Ok(m) => { m }
		_ => {
			//fs::rename does not support cross-device linking
			//copy and delete instead
			assert!(std::fs::copy(&tempfile, &outfile).is_ok());
			assert!(std::fs::remove_file(&tempfile).is_ok());
		}
	};

    return Ok(());
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();
    let mut opts = Options::new();
    opts.optflag("h", "help", "prints this help info");
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => panic!(f.to_string()),
    };
    if matches.opt_present("h") {
        print_usage(&program, opts);
        return;
    }
    let infile = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        print_usage(&program, opts);
        return;
    };

    assert!(redirect_to_file(&infile).is_ok());
}
<commit_msg>rustfmt'd<commit_after>use std::env;
use std::io::prelude::*;
use std::fs::File;
extern crate uuid;
use uuid::Uuid;
extern crate getopts;
use getopts::Options;
use std::io;

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} FILE [options]", program);
    print!("{}", opts.usage(&brief));
}

fn redirect_to_file(outfile: &str) -> Result<(), io::Error> {
    let mut tempfile = env::temp_dir();
    tempfile.push(Uuid::new_v4().hyphenated().to_string());
    //println!("{}", tempfile.display());

    {
        let mut buffer = [0; 512];
        let mut stdin = io::stdin();
        let mut f = File::create(&tempfile).unwrap();

        loop {
            let read_bytes = stdin.read(&mut buffer).unwrap();
            if read_bytes == 0 {
                break;
            }

            let write_bytes = match f.write(&buffer[0..read_bytes]) {
                Ok(m) => m,
                Err(e) => panic!("{}", e),
            };

            assert!(write_bytes == read_bytes);
        }
    }

    match std::fs::rename(&tempfile, &outfile) {
        Ok(m) => m,
        _ => {
            //fs::rename does not support cross-device linking
            //copy and delete instead
            assert!(std::fs::copy(&tempfile, &outfile).is_ok());
            assert!(std::fs::remove_file(&tempfile).is_ok());
        }
    };

    return Ok(());
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();
    let mut opts = Options::new();
    opts.optflag("h", "help", "prints this help info");
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => panic!(f.to_string()),
    };
    if matches.opt_present("h") {
        print_usage(&program, opts);
        return;
    }
    let infile = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        print_usage(&program, opts);
        return;
    };

    assert!(redirect_to_file(&infile).is_ok());
}
<|endoftext|>


<commit_before>extern crate piston_window;

mod entity;

use piston_window::*;
use entity::Entity;
use std::time::SystemTime;

#[derive(Debug, Clone)]
pub struct Point(f64, f64);

const MU: f64 = 1.0;
const WIDTH: u32 = 640;
const HEIGHT: u32 = 480;
const WAIT_TIME: u32 = 300_000_000; //nanoseconds

fn main() {
    let title = "Goober";
    let mut inputs_submitted = false;
    let mut inputs = Vec::new();
    let mut timestamp = SystemTime::now();
    let mut i: usize = 0;
    let mut squares = [
        Entity::new(Point(0.0, 0.0), [0.3, 0.0, 0.7, 0.5], 25.0, 25.0),
        Entity::new(Point(100.0, 100.0), [0.7, 0.0, 0.3, 0.5], 25.0, 25.0),
    ];

    let mut window: PistonWindow = WindowSettings::new(title, [WIDTH, HEIGHT])
        .exit_on_esc(true)
        .build()
        .unwrap_or_else(|e| panic!("Failed to build PistonWindow: {}", e));

    let sprite_path = "./assets/green-blob-hi.png";
    let sprite = Texture::from_path(
            &mut window.factory,
            &sprite_path,
            Flip::None,
            &TextureSettings::new())
            .unwrap();

    let font = "assets/FiraSans-Regular.ttf";
    let factory = window.factory.clone();
    let mut glyphs = Glyphs::new(font, factory).unwrap();

    while let Some(e) = window.next() {

        if let Some(_) = e.render_args() {
            window.draw_2d(&e, |c, g| {
                clear([0.8, 0.0, 0.8, 1.0], g);
                for sq in &squares {
                    image(&sprite, c.transform.trans(sq.geometry()[0], sq.geometry()[1]), g);
                }

                text::Text::new_color([0.0, 1.0, 0.0, 1.0], 32).draw(
                    &format_inputs(&inputs),
                    &mut glyphs,
                    &c.draw_state,
                    c.transform.trans(40.0, 40.0), g
                );
            });
        }

        if let Some(button) = e.press_args() {
            if !inputs_submitted {
                match button {
                    Button::Keyboard(Key::Up)     => inputs.push(button),
                    Button::Keyboard(Key::Down)   => inputs.push(button),
                    Button::Keyboard(Key::Left)   => inputs.push(button),
                    Button::Keyboard(Key::Right)  => inputs.push(button),
                    Button::Keyboard(Key::Space)  => inputs.push(button),
                    Button::Keyboard(Key::Return) => {inputs_submitted = true; inputs.reverse()},
                    _ => ()
                }
            }
        }

        if let Some(_) = e.update_args() {
            if inputs_submitted && wait_time_elapsed(timestamp) {
                timestamp = SystemTime::now();
                match inputs.pop() {
                    Some(button) => handle_input(button, &mut squares, &mut i),
                    None => ()
                }
            }
            for square in squares.iter_mut() {
                square.nudge();
            }
        }
    }

    fn handle_input(button: Button, squares: &mut [Entity], i: &mut usize) {
        match button {
            Button::Keyboard(Key::Up)     => squares[*i].adjust_dy(-1.0),
            Button::Keyboard(Key::Down)   => squares[*i].adjust_dy(1.0),
            Button::Keyboard(Key::Left)   => squares[*i].adjust_dx(-1.0),
            Button::Keyboard(Key::Right)  => squares[*i].adjust_dx(1.0),
            Button::Keyboard(Key::Space)  => if *i == squares.len() - 1 { *i = 0 } else { *i += 1 },
            _ => ()
        }
    }

    fn wait_time_elapsed(timestamp: SystemTime) -> bool {
        match timestamp.elapsed() {
            Ok(elapsed) => elapsed.subsec_nanos() >= WAIT_TIME,
            Err(e) => {println!("{:?}", e); false}
        }
    }

    fn format_inputs(inputs: &Vec<Button>) -> String {
        inputs.iter().map(|button|
            match *button {
                Button::Keyboard(Key::Up)    => "↑",
                Button::Keyboard(Key::Down)  => "↓",
                Button::Keyboard(Key::Left)  => "←",
                Button::Keyboard(Key::Right) => "→",
                Button::Keyboard(Key::Space) => "↔",
                _ => ""
            }
        ).collect::<Vec<_>>().concat()
    }
}
<commit_msg>More goobers is better goobers<commit_after>extern crate piston_window;

mod entity;

use piston_window::*;
use entity::Entity;
use std::time::SystemTime;

#[derive(Debug, Clone)]
pub struct Point(f64, f64);

const MU: f64 = 1.0;
const WIDTH: u32 = 640;
const HEIGHT: u32 = 480;
const WAIT_TIME: u32 = 300_000_000; //nanoseconds

fn main() {
    let title = "Goober";
    let mut inputs_submitted = false;
    let mut inputs = Vec::new();
    let mut timestamp = SystemTime::now();
    let mut i: usize = 0;
    let mut squares = vec![
        Entity::new(Point(0.0, 0.0), [0.3, 0.0, 0.7, 0.5], 25.0, 25.0),
        Entity::new(Point(100.0, 100.0), [0.7, 0.0, 0.3, 0.5], 25.0, 25.0)
    ];

    let mut window: PistonWindow = WindowSettings::new(title, [WIDTH, HEIGHT])
        .exit_on_esc(true)
        .build()
        .unwrap_or_else(|e| panic!("Failed to build PistonWindow: {}", e));

    let sprite_path = "./assets/green-blob-hi.png";
    let sprite = Texture::from_path(
            &mut window.factory,
            &sprite_path,
            Flip::None,
            &TextureSettings::new())
            .unwrap();

    let font = "assets/FiraSans-Regular.ttf";
    let factory = window.factory.clone();
    let mut glyphs = Glyphs::new(font, factory).unwrap();

    while let Some(e) = window.next() {

        if let Some(_) = e.render_args() {
            window.draw_2d(&e, |c, g| {
                clear([0.8, 0.0, 0.8, 1.0], g);
                for sq in &squares {
                    image(&sprite, c.transform.trans(sq.geometry()[0], sq.geometry()[1]), g);
                }

                text::Text::new_color([0.0, 1.0, 0.0, 1.0], 32).draw(
                    &format_inputs(&inputs),
                    &mut glyphs,
                    &c.draw_state,
                    c.transform.trans(40.0, 40.0), g
                );
            });
        }

        if let Some(button) = e.press_args() {
            if !inputs_submitted {
                match button {
                    Button::Keyboard(Key::Up)     => inputs.push(button),
                    Button::Keyboard(Key::Down)   => inputs.push(button),
                    Button::Keyboard(Key::Left)   => inputs.push(button),
                    Button::Keyboard(Key::Right)  => inputs.push(button),
                    Button::Keyboard(Key::Space)  => inputs.push(button),
                    Button::Keyboard(Key::A)      => squares.push(
                        Entity::new(
                            Point(0.0, 0.0),
                            [0.3, 0.0, 0.7, 0.5],
                            25.0, 25.0
                        )
                    ),
                    Button::Keyboard(Key::Return) => {inputs_submitted = true; inputs.reverse()},
                    _ => ()
                }
            }
        }

        if let Some(_) = e.update_args() {
            if inputs_submitted && wait_time_elapsed(timestamp) {
                timestamp = SystemTime::now();
                match inputs.pop() {
                    Some(button) => handle_input(button, &mut squares, &mut i),
                    None => ()
                }
            }
            for square in squares.iter_mut() {
                square.nudge();
            }
        }
    }

    fn handle_input(button: Button, squares: &mut [Entity], i: &mut usize) {
        match button {
            Button::Keyboard(Key::Up)     => squares[*i].adjust_dy(-1.0),
            Button::Keyboard(Key::Down)   => squares[*i].adjust_dy(1.0),
            Button::Keyboard(Key::Left)   => squares[*i].adjust_dx(-1.0),
            Button::Keyboard(Key::Right)  => squares[*i].adjust_dx(1.0),
            Button::Keyboard(Key::Space)  => if *i == squares.len() - 1 { *i = 0 } else { *i += 1 },
            _ => ()
        }
    }

    fn wait_time_elapsed(timestamp: SystemTime) -> bool {
        match timestamp.elapsed() {
            Ok(elapsed) => elapsed.subsec_nanos() >= WAIT_TIME,
            Err(e) => {println!("{:?}", e); false}
        }
    }

    fn format_inputs(inputs: &Vec<Button>) -> String {
        inputs.iter().map(|button|
            match *button {
                Button::Keyboard(Key::Up)    => "↑",
                Button::Keyboard(Key::Down)  => "↓",
                Button::Keyboard(Key::Left)  => "←",
                Button::Keyboard(Key::Right) => "→",
                Button::Keyboard(Key::Space) => "↔",
                _ => ""
            }
        ).collect::<Vec<_>>().concat()
    }
}
<|endoftext|>


<commit_before>use std::io::{self, BufReader};
use std::io::BufRead;
use std::fs::File;

extern crate time;
use time::Duration;

extern crate stats;
use stats::median;

extern crate clap;
use clap::{Arg, App};

mod percentile;
use percentile::percentile;

mod http_status;

mod request_response;
use request_response::*;

pub fn open_logfile(path: &str, time_filter: Option<Duration>) -> Result<(Vec<Request>,Vec<Response>), io::Error> {
    let f = try!(File::open(path));

    let f = BufReader::new(f);

    let mut requests: Vec<Request> = Vec::new();
    let mut responses: Vec<Response> = Vec::new();

    for line in f.lines() {
        let line_value = &line.unwrap();

        if line_value.contains("->") {
            let r = try!(Request::new_from_log_line(&line_value));

            if time_filter.is_none() ||
              (time_filter.is_some() && r.is_between_times(time::now() - time_filter.unwrap(), time::now())) {
                requests.push(r);
            }
        }

        if line_value.contains("<-") {
            let r = try!(Response::new_from_log_line(&line_value));
            responses.push(r);
        }

    }

    responses.sort_by_key(|r| r.id);

    Ok((requests, responses))
}

#[derive(Eq, PartialEq)]
#[derive(Debug)]
pub struct RequestLogAnalyzerResult {
    count: usize,
    max: usize,
    min: usize,
    avg: usize,
    median: usize,
    percentile90: usize,
}

pub fn analyze(request_response_pairs: &Vec<RequestResponsePair>) -> Option<RequestLogAnalyzerResult> {
    if request_response_pairs.len() == 0 {
        return None;
    }

    let times: Vec<i64> = request_response_pairs.iter()
        .map(|rr: &RequestResponsePair| -> i64 {rr.response.response_time.num_milliseconds() })
        .collect();

    let sum: usize = times.iter().sum::<i64>() as usize;
    let avg: usize = sum / times.len();

    let max: usize = *times.iter().max().unwrap() as usize;
    let min: usize = *times.iter().min().unwrap() as usize;

    let percentile90: usize = percentile(&times, 0.9) as usize;

    let median = median(times.into_iter()).unwrap() as usize;

    Some(RequestLogAnalyzerResult {
        count: request_response_pairs.len().into(),
        max: max,
        min: min,
        avg: avg,
        median: median,
        percentile90: percentile90,
    })
}

fn render_terminal(result: RequestLogAnalyzerResult) {
    println!("count:\t{}", result.count);
    println!("time.avg:\t{}", result.avg);
    println!("time.min:\t{}", result.min);
    println!("time.median:\t{}", result.median);
    println!("time.90percent:\t{}", result.percentile90);
    println!("time.max:\t{}", result.max);
}

fn main() {
    let matches = App::new("Request.log Analyzer")
        .arg(Arg::with_name("filename")
            .index(1)
            .value_name("FILE")
            .required(true)
            .help("Log file to analyze")
            .takes_value(true))
        .arg(Arg::with_name("time_filter_minutes")
            .value_name("MINUTES")
            .short("t")
            .help("Limit to the last n minutes")
            .takes_value(true))
        .arg(Arg::with_name("include_term")
            .value_name("TERM")
            .long("include")
            .help("Only includes lines that contain this term")
            .takes_value(true))
        .arg(Arg::with_name("exclude_term")
            .value_name("TERM")
            .long("exclude")
            .help("Excludes lines that contain this term")
            .takes_value(true))
        .get_matches();

    let filename = matches.value_of("filename").unwrap();

    let time_filter = match matches.value_of("time_filter_minutes") {
        Some(minutes) => Some(Duration::minutes(minutes.parse().unwrap())),
        None => None
    };

    let lines = open_logfile(filename, time_filter);
    let (requests, responses) = lines.unwrap();

    let pairs: Vec<RequestResponsePair> = pair_requests_responses(requests, responses)
        .into_iter()
        .filter(|rr| rr.matches_include_exclude_filter(
            matches.value_of("include_term"),
            matches.value_of("exclude_term")
        ))
        .collect();

    match analyze(&pairs) {
        Some(result) => render_terminal(result),
        None => println!("No matching log lines in file.")
    }
}

#[cfg(test)]
mod tests {
	use super::*;
    use request_response::*;
    extern crate time;
    use time::Duration;

    #[test]
    fn test_open_logfile() {
        let lines = open_logfile("src/test/simple-1.log", None);
        let (requests, responses) = lines.unwrap();

        assert_eq!(requests.len(), 2);
        assert_eq!(responses.len(), 2);
    }

    #[test]
    fn test_open_logfile_time_filter() {
        let time_filter: Duration = Duration::minutes(1);
        let lines = open_logfile("src/test/simple-1.log", Some(time_filter));
        let (requests, responses) = lines.unwrap();

        assert_eq!(requests.len(), 0);

        let time_filter: Duration = Duration::minutes(52560000); // 100 years
        let lines = open_logfile("src/test/simple-1.log", Some(time_filter));
        let (requests, responses) = lines.unwrap();

        assert_eq!(requests.len(), 2);
    }

    #[test]
    fn test_pair_requests_resonses() {
        let lines = open_logfile("src/test/simple-1.log", None);
        let (requests, responses) = lines.unwrap();

        let result = pair_requests_responses(requests, responses);

        assert_eq!(result.len(), 2);

        assert_eq!(result[0].request.id, result[0].response.id);
        assert_eq!(result[1].request.id, result[1].response.id);
    }

    #[test]
    fn test_request_log_analyzer_result() {
        let lines = open_logfile("src/test/response-time-calculations.log", None);
        let (requests, responses) = lines.unwrap();

        let request_response_pairs = pair_requests_responses(requests, responses);

        let result = analyze(&request_response_pairs);

        let expected = Some(RequestLogAnalyzerResult {
            count: 3,
            max: 100,
            min: 1,
            avg: 37,
            median: 10,
            percentile90: 100,
        });

        assert_eq!(result, expected);
    }

    #[test]
    fn test_request_log_analyze_none_matching() {
        let lines = open_logfile("src/test/simple-1.log", Some(Duration::minutes(0)));
        let (requests, responses) = lines.unwrap();

        let request_response_pairs = pair_requests_responses(requests, responses);

        let result = analyze(&request_response_pairs);

        let expected = None;

        assert_eq!(result, expected);
    }

    #[test]
    fn test_90_percentile_calculation() {
        let lines = open_logfile("src/test/percentile.log", None);
        let (requests, responses) = lines.unwrap();

        let request_response_pairs = pair_requests_responses(requests, responses);

        let result: RequestLogAnalyzerResult = analyze(&request_response_pairs).unwrap();

        assert_eq!(result.percentile90, 9);
    }
}
<commit_msg>Set up mock of TcpStream for testing<commit_after>use std::io::{self, BufReader, Write};
use std::io::BufRead;
use std::fs::File;

extern crate time;
use time::Duration;
use time::Tm;

extern crate stats;
use stats::median;

extern crate clap;
use clap::{Arg, App};

mod percentile;
use percentile::percentile;

mod http_status;

mod request_response;
use request_response::*;

pub fn open_logfile(path: &str, time_filter: Option<Duration>) -> Result<(Vec<Request>,Vec<Response>), io::Error> {
    let f = try!(File::open(path));

    let f = BufReader::new(f);

    let mut requests: Vec<Request> = Vec::new();
    let mut responses: Vec<Response> = Vec::new();

    for line in f.lines() {
        let line_value = &line.unwrap();

        if line_value.contains("->") {
            let r = try!(Request::new_from_log_line(&line_value));

            if time_filter.is_none() ||
              (time_filter.is_some() && r.is_between_times(time::now() - time_filter.unwrap(), time::now())) {
                requests.push(r);
            }
        }

        if line_value.contains("<-") {
            let r = try!(Response::new_from_log_line(&line_value));
            responses.push(r);
        }

    }

    responses.sort_by_key(|r| r.id);

    Ok((requests, responses))
}

#[derive(Eq, PartialEq)]
#[derive(Debug)]
pub struct RequestLogAnalyzerResult {
    count: usize,
    max: usize,
    min: usize,
    avg: usize,
    median: usize,
    percentile90: usize,
}

pub fn analyze(request_response_pairs: &Vec<RequestResponsePair>) -> Option<RequestLogAnalyzerResult> {
    if request_response_pairs.len() == 0 {
        return None;
    }

    let times: Vec<i64> = request_response_pairs.iter()
        .map(|rr: &RequestResponsePair| -> i64 {rr.response.response_time.num_milliseconds() })
        .collect();

    let sum: usize = times.iter().sum::<i64>() as usize;
    let avg: usize = sum / times.len();

    let max: usize = *times.iter().max().unwrap() as usize;
    let min: usize = *times.iter().min().unwrap() as usize;

    let percentile90: usize = percentile(&times, 0.9) as usize;

    let median = median(times.into_iter()).unwrap() as usize;

    Some(RequestLogAnalyzerResult {
        count: request_response_pairs.len().into(),
        max: max,
        min: min,
        avg: avg,
        median: median,
        percentile90: percentile90,
    })
}

fn render_terminal(result: RequestLogAnalyzerResult) {
    println!("count:\t{}", result.count);
    println!("time.avg:\t{}", result.avg);
    println!("time.min:\t{}", result.min);
    println!("time.median:\t{}", result.median);
    println!("time.90percent:\t{}", result.percentile90);
    println!("time.max:\t{}", result.max);
}

pub fn render_graphite<T: Write>(result: RequestLogAnalyzerResult, time: Tm, mut stream: T) {
    stream.write(
        format!(
            "count {} {:?}\n",
            result.count,
            time.to_timespec().sec
        )
        .as_bytes()
    );
}

fn main() {
    let matches = App::new("Request.log Analyzer")
        .arg(Arg::with_name("filename")
            .index(1)
            .value_name("FILE")
            .required(true)
            .help("Log file to analyze")
            .takes_value(true))
        .arg(Arg::with_name("time_filter_minutes")
            .value_name("MINUTES")
            .short("t")
            .help("Limit to the last n minutes")
            .takes_value(true))
        .arg(Arg::with_name("include_term")
            .value_name("TERM")
            .long("include")
            .help("Only includes lines that contain this term")
            .takes_value(true))
        .arg(Arg::with_name("exclude_term")
            .value_name("TERM")
            .long("exclude")
            .help("Excludes lines that contain this term")
            .takes_value(true))
        .get_matches();

    let filename = matches.value_of("filename").unwrap();

    let time_filter = match matches.value_of("time_filter_minutes") {
        Some(minutes) => Some(Duration::minutes(minutes.parse().unwrap())),
        None => None
    };

    let lines = open_logfile(filename, time_filter);
    let (requests, responses) = lines.unwrap();

    let pairs: Vec<RequestResponsePair> = pair_requests_responses(requests, responses)
        .into_iter()
        .filter(|rr| rr.matches_include_exclude_filter(
            matches.value_of("include_term"),
            matches.value_of("exclude_term")
        ))
        .collect();

    match analyze(&pairs) {
        Some(result) => render_terminal(result),
        None => println!("No matching log lines in file.")
    }
}

#[cfg(test)]
mod tests {
	use super::*;
    use request_response::*;
    extern crate time;
    use time::Duration;
    use time::strptime;

    #[test]
    fn test_open_logfile() {
        let lines = open_logfile("src/test/simple-1.log", None);
        let (requests, responses) = lines.unwrap();

        assert_eq!(requests.len(), 2);
        assert_eq!(responses.len(), 2);
    }

    #[test]
    fn test_open_logfile_time_filter() {
        let time_filter: Duration = Duration::minutes(1);
        let lines = open_logfile("src/test/simple-1.log", Some(time_filter));
        let (requests, responses) = lines.unwrap();

        assert_eq!(requests.len(), 0);

        let time_filter: Duration = Duration::minutes(52560000); // 100 years
        let lines = open_logfile("src/test/simple-1.log", Some(time_filter));
        let (requests, responses) = lines.unwrap();

        assert_eq!(requests.len(), 2);
    }

    #[test]
    fn test_pair_requests_resonses() {
        let lines = open_logfile("src/test/simple-1.log", None);
        let (requests, responses) = lines.unwrap();

        let result = pair_requests_responses(requests, responses);

        assert_eq!(result.len(), 2);

        assert_eq!(result[0].request.id, result[0].response.id);
        assert_eq!(result[1].request.id, result[1].response.id);
    }

    #[test]
    fn test_request_log_analyzer_result() {
        let lines = open_logfile("src/test/response-time-calculations.log", None);
        let (requests, responses) = lines.unwrap();

        let request_response_pairs = pair_requests_responses(requests, responses);

        let result = analyze(&request_response_pairs);

        let expected = Some(RequestLogAnalyzerResult {
            count: 3,
            max: 100,
            min: 1,
            avg: 37,
            median: 10,
            percentile90: 100,
        });

        assert_eq!(result, expected);
    }

    #[test]
    fn test_request_log_analyze_none_matching() {
        let lines = open_logfile("src/test/simple-1.log", Some(Duration::minutes(0)));
        let (requests, responses) = lines.unwrap();

        let request_response_pairs = pair_requests_responses(requests, responses);

        let result = analyze(&request_response_pairs);

        let expected = None;

        assert_eq!(result, expected);
    }

    #[test]
    fn test_90_percentile_calculation() {
        let lines = open_logfile("src/test/percentile.log", None);
        let (requests, responses) = lines.unwrap();

        let request_response_pairs = pair_requests_responses(requests, responses);

        let result: RequestLogAnalyzerResult = analyze(&request_response_pairs).unwrap();

        assert_eq!(result.percentile90, 9);
    }

    #[test]
    fn test_render_graphite() {
        use std::io::{self, BufReader};
        use std::io::prelude::Write;
        use std::str;

        struct MockTcpStream {
            write_calls: Vec<String>,
        };

        impl Write for MockTcpStream {
            fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
                self.write_calls.push(str::from_utf8(buf).unwrap().to_string());
                Ok(1)
            }

            fn flush(&mut self) -> io::Result<()> { Ok(()) }
        }

        let mut mock_tcp_stream = MockTcpStream {
            write_calls: vec![]
        };

        render_graphite(RequestLogAnalyzerResult {
                count: 3,
                max: 100,
                min: 1,
                avg: 37,
                median: 10,
                percentile90: 100,
            },
            strptime("22/Sep/2016:22:41:59 +0200", "%d/%b/%Y:%H:%M:%S %z").unwrap(),
            &mut mock_tcp_stream
        );

        assert_eq!(&mock_tcp_stream.write_calls[0], "requests.count 3 1474576919\n");
    }
}
<|endoftext|>