<commit_before>extern crate rustc_serialize;
use rustc_serialize::json;
use std::io::prelude::*;
use std::fs;
use std::fs::File;
use std::error::Error;
use std::path::Path;

#[derive(RustcDecodable, RustcEncodable)]
pub struct TransferParams {
    file_name: String,
    copy_to_path: String
}

fn main() {
    let path = Path::new("testfile.json");
    let display = path.display();

    // matching is like error checking in rust.  This match tries to open a file and switches through based on
    //  what the result is (Err, Ok, etc.)
    let mut file =  match File::open(&path) {
        Err(why) => panic!("Couldn't open {}: {}", display, why.description()),
        Ok(file) => file
    };//try!(File::open("testfile.json"));

    // define a string for the file contents
    let mut file_contents = String::new();

    match file.read_to_string(&mut file_contents) {
        Err(why) => panic!("Coulding read {}: {}", display, why.description()),
        Ok(_) => print!("{} contains: \n{}", display, file_contents),
    };

    //try!(file.read_to_string(&mut fileContents));

    //println!("contents: {}", fileContents);

    let decoded: TransferParams = json::decode(&file_contents).unwrap();

    println!("file_name: {}", decoded.file_name);
    println!("Copy path: {}", decoded.copy_to_path);

    println!("Trying to copy {} to {}", decoded.file_name, decoded.copy_to_path);

    match fs::copy(decoded.file_name, decoded.copy_to_path) {
        Err(why) => panic!("Couldn't copy the file {}: {}", display, why.description()),
        Ok(_) => println!("File copy complete!")
    };
}
<commit_msg>Started trying to put the program back together again<commit_after>extern crate rustc_serialize;
use rustc_serialize::json;
use std::io::prelude::*;
use std::fs;
use std::fs::metadata;
use std::fs::File;
use std::error::Error;
use std::path::Path;
use std::env;

#[derive(RustcDecodable, RustcEncodable)]
pub struct TransferParams {
    file_name: String,
    copy_to_path: String
}

fn main() {
    // Get the passed arguments
    let args: Vec<String> = env::args().collect();

    // check to make sure the number of arguments is correct,
    //  if there are not exactly one argument (one plus the program), exit the program.
    if args.len() != 2  {
        // print program usage
        println!("Usage: file_copy_tool <Root Folder Path>");

        // exit the program
        //std::process::exit(0);
    }

    let paths = fs::read_dir("./").unwrap();

    for path in paths {
        //println!("Name: {}", path.unwrap().path().display())
        let filename = path.unwrap().path().as_os_str();

        println!("{}", filename.to_str());
        //let attr = fs::metadata(path.unwrap().path().display()).unwrap();

        //if attr.is_dir() {
            //println!("{}, is a directory!", path.unwrap().path().display());
        //}
        println!("Name: {}", path.unwrap().path().display());
    }

    let startFolder = ".";
    copyFile(startFolder);

    /*
    let temppath = Path::new(&args[1]); //"testfile.json");
    let path = temppath.join("testfile.json");

    let display = path.display();

    //let path = Path::new("testfile.json");
    //let display = path.display();

    // matching is like error checking in rust.  This match tries to open a file and switches through based on
    //  what the result is (Err, Ok, etc.)
    let mut file =  match File::open(&path) {
        Err(why) => panic!("Couldn't open {}: {}", display, why.description()),
        Ok(file) => file
    };//try!(File::open("testfile.json"));

    // define a string for the file contents
    let mut file_contents = String::new();

    match file.read_to_string(&mut file_contents) {
        Err(why) => panic!("Coulding read {}: {}", display, why.description()),
        Ok(_) => print!("{} contains: \n{}", display, file_contents),
    };

    //try!(file.read_to_string(&mut fileContents));

    //println!("contents: {}", fileContents);

    let decoded: TransferParams = json::decode(&file_contents).unwrap();

    //println!("file_name: {}", decoded.file_name);
    //println!("Copy path: {}", decoded.copy_to_path);

    //println!("Trying to copy {} to {}", decoded.file_name, decoded.copy_to_path);

    match fs::copy(decoded.file_name, decoded.copy_to_path) {
        Err(why) => panic!("Couldn't copy the file {}: {}", display, why.description()),
        Ok(_) => println!("File copy complete!")
    };
    */
}

fn copyFile( folder_path: &str ) {

    let temppath = Path::new(&folder_path); //"testfile.json");
    let path = temppath.join("testfile.json");

    let display = path.display();

    // matching is like error checking in rust.  This match tries to open a file and switches through based on
    //  what the result is (Err, Ok, etc.)
    let mut file =  match File::open(&path) {
        Err(why) => panic!("Couldn't open {}: {}", display, why.description()),
        Ok(file) => file
    };//try!(File::open("testfile.json"));

    // define a string for the file contents
    let mut file_contents = String::new();

    match file.read_to_string(&mut file_contents) {
        Err(why) => panic!("Coulding read {}: {}", display, why.description()),
        Ok(_) => { }, // Do nothing // print!("{} contains: \n{}", display, file_contents),
    };

    let decoded: TransferParams = json::decode(&file_contents).unwrap();

    match fs::copy(decoded.file_name, decoded.copy_to_path) {
        Err(why) => panic!("Couldn't copy the file {}: {}", display, why.description()),
        Ok(_) => println!("File copy complete!")
    };
}
<|endoftext|>


<commit_before>#![crate_name = "rboy"]

extern crate clap;
extern crate sdl2;
extern crate rboy;

use rboy::device::Device;
use std::sync::{Arc,RwLock};
use std::sync::mpsc::{Sender,Receiver};
use std::sync::mpsc::TryRecvError::{Disconnected,Empty};
use std::error::Error;

const EXITCODE_SUCCESS : i32 = 0;
const EXITCODE_CPULOADFAILS : i32 = 2;

fn main() {
    let exit_status = real_main();
    if exit_status != EXITCODE_SUCCESS {
        std::process::exit(exit_status);
    }
}

fn real_main() -> i32 {
    let matches = clap::App::new("rboy")
        .version("0.1")
        .author("Mathijs van de Nes")
        .about("A Gameboy Colour emulator written in Rust")
        .arg(clap::Arg::with_name("filename")
             .help("Sets the ROM file to load")
             .required(true))
        .arg(clap::Arg::with_name("serial")
             .help("Prints the data from the serial port to stdout")
             .short("s")
             .long("serial"))
        .arg(clap::Arg::with_name("classic")
             .help("Forces the emulator to run in classic Gameboy mode")
             .short("c")
             .long("classic"))
        .arg(clap::Arg::with_name("scale")
             .help("Sets the scale of the interface. Default: 2")
             .short("x")
             .long("scale")
             .validator(|s|
                 match s.parse::<u32>() {
                     Err(e) => Err(format!("Could not parse scale: {}", e.description())),
                     Ok(s) if s < 1 => Err("Scale must be at least 1".to_owned()),
                     Ok(s) if s > 8 => Err("Scale may be at most 8".to_owned()),
                     Ok(..) => Ok(()),
                 })
             .takes_value(true))
        .get_matches();

    let opt_serial = matches.is_present("serial");
    let opt_classic = matches.is_present("classic");
    let filename = matches.value_of("filename").unwrap();
    let scale = matches.value_of("scale").unwrap_or("2").parse::<u32>().unwrap();

    let cpu = construct_cpu(filename, opt_classic, opt_serial);
    if cpu.is_none() { return EXITCODE_CPULOADFAILS; }
    let cpu = cpu.unwrap();

    let sdl_context = sdl2::init().unwrap();
    let sdl_video = sdl_context.video().ok().expect("Could not open video");
    let window = match sdl2::video::WindowBuilder::new(&sdl_video,
                                                "RBoy - A gameboy in Rust",
                                                160*scale,
                                                144*scale).build() {
        Ok(window) => window,
        Err(err) => panic!("failed to open window: {}", err),
    };
    let mut renderer = match sdl2::render::RendererBuilder::new(window).accelerated().build() {
        Ok(screen) => screen,
        Err(err) => panic!("failed to open screen: {}", err),
    };

    let (sdl_tx, cpu_rx) = std::sync::mpsc::channel();
    let (cpu_tx, sdl_rx) = std::sync::mpsc::channel();
    let rawscreen = ::std::iter::repeat(0u8).take(160*144*3).collect();
    let arc = Arc::new(RwLock::new(rawscreen));
    let arc2 = arc.clone();

    let cpuloop_thread = std::thread::spawn(move|| cpuloop(&cpu_tx, &cpu_rx, arc2, cpu));

    let mut event_queue = sdl_context.event_pump().unwrap();
    'main : loop {
        let mut refreshed = false;
        'rx : loop {
            match sdl_rx.try_recv() {
                Err(Disconnected) => break 'main,
                Ok(_) => { if !refreshed { recalculate_screen(&mut renderer, &arc, scale); refreshed = true } },
                Err(Empty) => break 'rx,
            }
        }
        for event in event_queue.wait_timeout_iter(2) {
            match event {
                sdl2::event::Event::Quit { .. } => break 'main,
                sdl2::event::Event::KeyDown { keycode: Some(sdl2::keyboard::Keycode::Escape), .. }
                    => break 'main,
                sdl2::event::Event::KeyDown { keycode: Some(sdl2::keyboard::Keycode::LShift), .. }
                    => { let _ = sdl_tx.send(GBEvent::SpeedUp); },
                sdl2::event::Event::KeyUp { keycode: Some(sdl2::keyboard::Keycode::LShift), .. }
                    => { let _ = sdl_tx.send(GBEvent::SlowDown); },
                sdl2::event::Event::KeyDown { keycode: Some(sdlkey), .. } => {
                    match sdl_to_keypad(sdlkey) {
                        Some(key) =>  { let _ = sdl_tx.send(GBEvent::KeyDown(key)); },
                        None => {},
                    }
                },
                sdl2::event::Event::KeyUp { keycode: Some(sdlkey), .. } => {
                    match sdl_to_keypad(sdlkey) {
                        Some(key) => { let _ = sdl_tx.send(GBEvent::KeyUp(key)); },
                        None => {},
                    }
                },
                _ => {}
            }
        }
    }

    drop(sdl_tx); // Disconnect such that the cpuloop will exit
    let _ = cpuloop_thread.join();

    EXITCODE_SUCCESS
}

fn sdl_to_keypad(key: sdl2::keyboard::Keycode) -> Option<rboy::KeypadKey> {
    match key {
        sdl2::keyboard::Keycode::Z => Some(rboy::KeypadKey::A),
        sdl2::keyboard::Keycode::X => Some(rboy::KeypadKey::B),
        sdl2::keyboard::Keycode::Up => Some(rboy::KeypadKey::Up),
        sdl2::keyboard::Keycode::Down => Some(rboy::KeypadKey::Down),
        sdl2::keyboard::Keycode::Left => Some(rboy::KeypadKey::Left),
        sdl2::keyboard::Keycode::Right => Some(rboy::KeypadKey::Right),
        sdl2::keyboard::Keycode::Space => Some(rboy::KeypadKey::Select),
        sdl2::keyboard::Keycode::Return => Some(rboy::KeypadKey::Start),
        _ => None,
    }
}

fn recalculate_screen(screen: &mut sdl2::render::Renderer, arc: &Arc<RwLock<Vec<u8>>>, scale: u32) {
    screen.set_draw_color(sdl2::pixels::Color::RGB(0xFF, 0xFF, 0xFF));
    screen.clear();

    let data =  arc.read().unwrap().clone();
    for y in 0..144 {
        for x in 0..160 {
            screen.set_draw_color(sdl2::pixels::Color::RGB(data[y*160*3 + x*3 + 0],
                                                            data[y*160*3 + x*3 + 1],
                                                            data[y*160*3 + x*3 + 2]));
            screen.fill_rect(sdl2::rect::Rect::new(x as i32 * scale as i32, y as i32 * scale as i32, scale, scale).unwrap().unwrap());
        }
    }
    screen.present();
}

enum GBEvent {
    KeyUp(rboy::KeypadKey),
    KeyDown(rboy::KeypadKey),
    SpeedUp,
    SlowDown,
}

fn warn(message: &'static str) {
    use std::io::Write;
    let _ = write!(&mut std::io::stderr(), "{}\n", message);
}

fn construct_cpu(filename: &str, classic_mode: bool, output_serial: bool) -> Option<Device> {
    let opt_c = match classic_mode {
        true => Device::new(filename),
        false => Device::new_cgb(filename),
    };
    let mut c = match opt_c
    {
        Ok(cpu) => { cpu },
        Err(message) => { warn(message); return None; },
    };
    c.set_stdout(output_serial);
    Some(c)
}

fn cpuloop(cpu_tx: &Sender<()>, cpu_rx: &Receiver<GBEvent>, arc: Arc<RwLock<Vec<u8>>>, cpu: Device) {
    let mut c = cpu;
    let periodic = timer_periodic(8);
    let mut limit_speed = true;

    let waitticks = (4194304f64 / 1000.0 * 8.0) as u32;

    let mut ticks = 0;
    'cpuloop: loop {
        while ticks < waitticks {
            ticks += c.do_cycle();
            if c.check_and_reset_gpu_updated() {
                let mut data = arc.write().unwrap();
                let gpu_data = c.get_gpu_data();
                for i in 0..data.len() { data[i] = gpu_data[i]; }
                if cpu_tx.send(()).is_err() { break 'cpuloop };
            }
        }
        ticks -= waitticks;
        if limit_speed { let _ = periodic.recv(); }

        'rx : loop {
            match cpu_rx.try_recv() {
                Ok(event) => match event {
                    GBEvent::KeyUp(key) => c.keyup(key),
                    GBEvent::KeyDown(key) => c.keydown(key),
                    GBEvent::SpeedUp => limit_speed = false,
                    GBEvent::SlowDown => limit_speed = true,
                },
                Err(Empty) => break 'rx,
                Err(Disconnected) => break 'cpuloop,
            }
        }
    }
}

fn timer_periodic(ms: u32) -> Receiver<()> {
    let (tx, rx) = std::sync::mpsc::channel();
    std::thread::spawn(move || {
        loop {
            std::thread::sleep_ms(ms);
            if tx.send(()).is_err() {
                break;
            }
        }
    });
    rx
}
<commit_msg>Use textures for SDL2 rendering<commit_after>#![crate_name = "rboy"]

extern crate clap;
extern crate sdl2;
extern crate rboy;

use rboy::device::Device;
use std::sync::{Arc,RwLock};
use std::sync::mpsc::{Sender,Receiver};
use std::sync::mpsc::TryRecvError::{Disconnected,Empty};
use std::error::Error;

const EXITCODE_SUCCESS : i32 = 0;
const EXITCODE_CPULOADFAILS : i32 = 2;

fn main() {
    let exit_status = real_main();
    if exit_status != EXITCODE_SUCCESS {
        std::process::exit(exit_status);
    }
}

fn real_main() -> i32 {
    let matches = clap::App::new("rboy")
        .version("0.1")
        .author("Mathijs van de Nes")
        .about("A Gameboy Colour emulator written in Rust")
        .arg(clap::Arg::with_name("filename")
             .help("Sets the ROM file to load")
             .required(true))
        .arg(clap::Arg::with_name("serial")
             .help("Prints the data from the serial port to stdout")
             .short("s")
             .long("serial"))
        .arg(clap::Arg::with_name("classic")
             .help("Forces the emulator to run in classic Gameboy mode")
             .short("c")
             .long("classic"))
        .arg(clap::Arg::with_name("scale")
             .help("Sets the scale of the interface. Default: 2")
             .short("x")
             .long("scale")
             .validator(|s|
                 match s.parse::<u32>() {
                     Err(e) => Err(format!("Could not parse scale: {}", e.description())),
                     Ok(s) if s < 1 => Err("Scale must be at least 1".to_owned()),
                     Ok(s) if s > 8 => Err("Scale may be at most 8".to_owned()),
                     Ok(..) => Ok(()),
                 })
             .takes_value(true))
        .get_matches();

    let opt_serial = matches.is_present("serial");
    let opt_classic = matches.is_present("classic");
    let filename = matches.value_of("filename").unwrap();
    let scale = matches.value_of("scale").unwrap_or("2").parse::<u32>().unwrap();

    let cpu = construct_cpu(filename, opt_classic, opt_serial);
    if cpu.is_none() { return EXITCODE_CPULOADFAILS; }
    let cpu = cpu.unwrap();

    let sdl_context = sdl2::init().unwrap();
    let sdl_video = sdl_context.video().ok().expect("Could not open video");
    let window = match sdl2::video::WindowBuilder::new(&sdl_video,
                                                "RBoy - A gameboy in Rust",
                                                160*scale,
                                                144*scale).build() {
        Ok(window) => window,
        Err(err) => panic!("failed to open window: {}", err),
    };
    let mut renderer = match sdl2::render::RendererBuilder::new(window).accelerated().build() {
        Ok(screen) => screen,
        Err(err) => panic!("failed to open screen: {}", err),
    };
    let mut texture = renderer.create_texture_streaming(sdl2::pixels::PixelFormatEnum::RGB24, (160, 144)).unwrap();

    let (sdl_tx, cpu_rx) = std::sync::mpsc::channel();
    let (cpu_tx, sdl_rx) = std::sync::mpsc::channel();
    let rawscreen = ::std::iter::repeat(0u8).take(160*144*3).collect();
    let arc = Arc::new(RwLock::new(rawscreen));
    let arc2 = arc.clone();

    let cpuloop_thread = std::thread::spawn(move|| cpuloop(&cpu_tx, &cpu_rx, arc2, cpu));

    let mut event_queue = sdl_context.event_pump().unwrap();
    'main : loop {
        let mut refreshed = false;
        'rx : loop {
            match sdl_rx.try_recv() {
                Err(Disconnected) => break 'main,
                Ok(_) => { if !refreshed { recalculate_screen(&mut renderer, &mut texture, &arc); refreshed = true } },
                Err(Empty) => break 'rx,
            }
        }
        for event in event_queue.wait_timeout_iter(2) {
            match event {
                sdl2::event::Event::Quit { .. } => break 'main,
                sdl2::event::Event::KeyDown { keycode: Some(sdl2::keyboard::Keycode::Escape), .. }
                    => break 'main,
                sdl2::event::Event::KeyDown { keycode: Some(sdl2::keyboard::Keycode::LShift), .. }
                    => { let _ = sdl_tx.send(GBEvent::SpeedUp); },
                sdl2::event::Event::KeyUp { keycode: Some(sdl2::keyboard::Keycode::LShift), .. }
                    => { let _ = sdl_tx.send(GBEvent::SlowDown); },
                sdl2::event::Event::KeyDown { keycode: Some(sdlkey), .. } => {
                    match sdl_to_keypad(sdlkey) {
                        Some(key) =>  { let _ = sdl_tx.send(GBEvent::KeyDown(key)); },
                        None => {},
                    }
                },
                sdl2::event::Event::KeyUp { keycode: Some(sdlkey), .. } => {
                    match sdl_to_keypad(sdlkey) {
                        Some(key) => { let _ = sdl_tx.send(GBEvent::KeyUp(key)); },
                        None => {},
                    }
                },
                _ => {}
            }
        }
    }

    drop(sdl_tx); // Disconnect such that the cpuloop will exit
    let _ = cpuloop_thread.join();

    EXITCODE_SUCCESS
}

fn sdl_to_keypad(key: sdl2::keyboard::Keycode) -> Option<rboy::KeypadKey> {
    match key {
        sdl2::keyboard::Keycode::Z => Some(rboy::KeypadKey::A),
        sdl2::keyboard::Keycode::X => Some(rboy::KeypadKey::B),
        sdl2::keyboard::Keycode::Up => Some(rboy::KeypadKey::Up),
        sdl2::keyboard::Keycode::Down => Some(rboy::KeypadKey::Down),
        sdl2::keyboard::Keycode::Left => Some(rboy::KeypadKey::Left),
        sdl2::keyboard::Keycode::Right => Some(rboy::KeypadKey::Right),
        sdl2::keyboard::Keycode::Space => Some(rboy::KeypadKey::Select),
        sdl2::keyboard::Keycode::Return => Some(rboy::KeypadKey::Start),
        _ => None,
    }
}

fn recalculate_screen(renderer: &mut sdl2::render::Renderer, texture: &mut sdl2::render::Texture, arc: &Arc<RwLock<Vec<u8>>>) {
    use std::io::Write;

    texture.with_lock(None, |ref mut buffer, _pitch| {
        buffer.write(&*arc.read().unwrap()).unwrap();
    }).unwrap();

    renderer.copy(&texture, None, None);
    renderer.present();
}

enum GBEvent {
    KeyUp(rboy::KeypadKey),
    KeyDown(rboy::KeypadKey),
    SpeedUp,
    SlowDown,
}

fn warn(message: &'static str) {
    use std::io::Write;
    let _ = write!(&mut std::io::stderr(), "{}\n", message);
}

fn construct_cpu(filename: &str, classic_mode: bool, output_serial: bool) -> Option<Device> {
    let opt_c = match classic_mode {
        true => Device::new(filename),
        false => Device::new_cgb(filename),
    };
    let mut c = match opt_c
    {
        Ok(cpu) => { cpu },
        Err(message) => { warn(message); return None; },
    };
    c.set_stdout(output_serial);
    Some(c)
}

fn cpuloop(cpu_tx: &Sender<()>, cpu_rx: &Receiver<GBEvent>, arc: Arc<RwLock<Vec<u8>>>, cpu: Device) {
    let mut c = cpu;
    let periodic = timer_periodic(8);
    let mut limit_speed = true;

    let waitticks = (4194304f64 / 1000.0 * 8.0) as u32;

    let mut ticks = 0;
    'cpuloop: loop {
        while ticks < waitticks {
            ticks += c.do_cycle();
            if c.check_and_reset_gpu_updated() {
                let mut data = arc.write().unwrap();
                let gpu_data = c.get_gpu_data();
                for i in 0..data.len() { data[i] = gpu_data[i]; }
                if cpu_tx.send(()).is_err() { break 'cpuloop };
            }
        }
        ticks -= waitticks;
        if limit_speed { let _ = periodic.recv(); }

        'rx : loop {
            match cpu_rx.try_recv() {
                Ok(event) => match event {
                    GBEvent::KeyUp(key) => c.keyup(key),
                    GBEvent::KeyDown(key) => c.keydown(key),
                    GBEvent::SpeedUp => limit_speed = false,
                    GBEvent::SlowDown => limit_speed = true,
                },
                Err(Empty) => break 'rx,
                Err(Disconnected) => break 'cpuloop,
            }
        }
    }
}

fn timer_periodic(ms: u32) -> Receiver<()> {
    let (tx, rx) = std::sync::mpsc::channel();
    std::thread::spawn(move || {
        loop {
            std::thread::sleep_ms(ms);
            if tx.send(()).is_err() {
                break;
            }
        }
    });
    rx
}
<|endoftext|>


<commit_before>extern crate serde_json;
#[macro_use]
extern crate quick_error;
#[macro_use]
extern crate clap;
extern crate colored;

extern crate rustfix;

use std::fs::File;
use std::io::{Read, Write};
use std::error::Error;
use std::process::Command;

use colored::Colorize;
use clap::{Arg, App};

use rustfix::Suggestion;
use rustfix::diagnostics::Diagnostic;

const USER_OPTIONS: &'static str = "What do you want to do? \
    [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving)";

fn main() {
    let program = try_main();
    match program {
        Ok(_) => std::process::exit(0),
        Err(ProgramError::UserAbort) => {
            writeln!(std::io::stdout(), "{}", ProgramError::UserAbort).unwrap();
            std::process::exit(0);
        }
        Err(error) => {
            writeln!(std::io::stderr(), "An error occured: {}", error).unwrap();
            writeln!(std::io::stderr(), "{:?}", error).unwrap();
            if let Some(cause) = error.cause() {
                writeln!(std::io::stderr(), "Cause: {:?}", cause).unwrap();
            }
            std::process::exit(1);
        }
    }
}

macro_rules! flush {
    () => (try!(std::io::stdout().flush());)
}

fn try_main() -> Result<(), ProgramError> {
    let matches = App::new("rustfix")
        .about("Automatically apply suggestions made by rustc")
        .version(crate_version!())
        .arg(Arg::with_name("clippy")
            .long("clippy")
            .help("Use `cargo clippy` for suggestions"))
        .arg(Arg::with_name("from_file")
            .long("from-file")
            .value_name("FILE")
            .takes_value(true)
            .help("Read suggestions from file (each line is a JSON object)"))
        .get_matches();

    // Get JSON output from rustc...
    let json = if let Some(file_name) = matches.value_of("from_file") {
        // either by reading a file the user saved (probably only for debugging rustfix itself)...
        try!(json_from_file(&file_name))
    } else {
        // or by spawning a subcommand that runs rustc.
        let subcommand = if matches.is_present("clippy") {
            "clippy"
        } else {
            "rustc"
        };
        try!(json_from_subcommand(subcommand))
    };

    let suggestions: Vec<Suggestion> = json.lines()
        .filter(not_empty)
        .flat_map(|line| serde_json::from_str::<Diagnostic>(&line))
        .flat_map(|diagnostic| rustfix::collect_suggestions(&diagnostic, None))
        .collect();

    try!(handle_suggestions(&suggestions));

    Ok(())
}

fn json_from_file(file_name: &str) -> Result<String, ProgramError> {
    read_file_to_string(&file_name).map_err(From::from)
}

fn json_from_subcommand(subcommand: &str) -> Result<String, ProgramError> {
    let output = try!(Command::new("cargo")
        .args(&[subcommand,
                "--quiet",
                "--color", "never",
                "--",
                "-Z", "unstable-options",
                "--error-format", "json"])
        .output());

    let content = try!(String::from_utf8(output.stderr));

    if !output.status.success() {
        return Err(ProgramError::SubcommandError(format!("cargo {}", subcommand), content));
    }

    Ok(content)
}

fn handle_suggestions(suggestions: &[Suggestion]) -> Result<(), ProgramError> {
    let mut accepted_suggestions: Vec<&Suggestion> = vec![];

    if suggestions.is_empty() {
        println!("I don't have any suggestions for you right now. Check back later!");
        return Ok(());
    }

    'suggestions: for suggestion in suggestions {
        println!("\n\n{info}: {message}\n\
            {arrow} {file}:{range}\n\
            {suggestion}\n\n\
            {text}\n\n\
            {with}\n\n\
            {replacement}\n",
            info = "Info".green().bold(),
            message = split_at_lint_name(&suggestion.message),
            arrow = "  -->".blue().bold(),
            suggestion = "Suggestion - Replace:".yellow().bold(),
            file = suggestion.file_name,
            range = suggestion.line_range,
            text = indent(4, &reset_indent(&suggestion.text)),
            with = "with:".yellow().bold(),
            replacement = indent(4, &suggestion.replacement));

        'userinput: loop {
            print!("{arrow} {user_options}\n\
                {prompt} ",
                arrow = "==>".green().bold(),
                prompt = "  >".green().bold(),
                user_options = USER_OPTIONS.green());

            flush!();
            let mut input = String::new();
            try!(std::io::stdin().read_line(&mut input));

            match input.trim() {
                "s" => {
                    println!("Skipped.");
                    continue 'suggestions;
                }
                "r" => {
                    accepted_suggestions.push(suggestion);
                    println!("Suggestion accepted. I'll remember that and apply it later.");
                    continue 'suggestions;
                }
                "q" => {
                    println!("Thanks for playing!");
                    break 'suggestions;
                }
                "a" => {
                    return Err(ProgramError::UserAbort);
                }
                _ => {
                    println!("{error}: I didn't quite get that. {user_options}",
                                error = "Error".red().bold(),
                                user_options = USER_OPTIONS);
                    continue 'userinput;
                }
            }
        }
    }

    if !accepted_suggestions.is_empty() {
        println!("Good work. Let me just apply these {} changes!",
                 accepted_suggestions.len());

        for suggestion in accepted_suggestions.iter().rev() {
            try!(apply_suggestion(suggestion));

            print!(".");
            flush!();
        }

        println!("\nDone.");
    }

    Ok(())
}

quick_error! {
    /// All possible errors in programm lifecycle
    #[derive(Debug)]
    pub enum ProgramError {
        UserAbort {
            display("Let's get outta here!")
        }
        /// Missing File
        NoFile {
            display("No input file given")
        }
        SubcommandError(subcommand: String, output: String) {
            display("Error executing subcommand `{}`", subcommand)
            description(output)
        }
        /// Error while dealing with file or stdin/stdout
        Io(err: std::io::Error) {
            from()
            cause(err)
            display("I/O error")
            description(err.description())
        }
        Utf8Error(err: std::string::FromUtf8Error) {
            from()
            display("Error reading input as UTF-8")
        }
        /// Error with deserialization
        Serde(err: serde_json::Error) {
            from()
            cause(err)
            display("Serde JSON error")
            description(err.description())
        }
    }
}

// Helpers
// -------

fn read_file_to_string(file_name: &str) -> Result<String, std::io::Error> {
    let mut file = try!(File::open(file_name));
    let mut buffer = String::new();
    try!(file.read_to_string(&mut buffer));
    Ok(buffer)
}

fn not_empty(s: &&str) -> bool {
    !s.trim().is_empty()
}

fn split_at_lint_name(s: &str) -> String {
    s.split(", #[")
        .collect::<Vec<_>>()
        .join("\n      #[") // Length of whitespace == length of "Info: "
}

fn reset_indent(s: &str) -> String {
    let leading_whitespace = s.lines()
        .nth(0)
        .unwrap_or("")
        .chars()
        .take_while(|&c| char::is_whitespace(c))
        .count();

    s.lines()
        .map(|line| String::from(&line[leading_whitespace..]))
        .collect::<Vec<_>>()
        .join("\n")
}

fn indent(size: u32, s: &str) -> String {
    let whitespace: String = std::iter::repeat(' ').take(size as usize).collect();

    s.lines()
        .map(|l| format!("{}{}", whitespace, l))
        .collect::<Vec<_>>()
        .join("\n")
}

/// Apply suggestion to a file
///
/// Please beware of ugly hacks below! Originally, I wanted to replace byte ranges, but sadly the
/// ranges rustc's JSON output gives me do not correspond to the parts of the file they are meant
/// to correspond to. So, for now, let's just replace lines!
///
/// This function is as stupid as possible. Make sure you call for the replacemnts in one file in
/// reverse order to not mess up the lines for replacements further down the road.
fn apply_suggestion(suggestion: &Suggestion) -> Result<(), ProgramError> {
    use std::cmp::max;
    use std::iter::repeat;

    let file_content = try!(read_file_to_string(&suggestion.file_name));
    let mut new_content = String::new();

    // Add the lines before the section we want to replace
    new_content.push_str(&file_content.lines()
        .take(max(suggestion.line_range.start.line - 1, 0) as usize)
        .collect::<Vec<_>>()
        .join("\n"));

    // Some suggestions seem to currently omit the trailing semicolon
    let remember_a_semicolon = suggestion.text.trim().ends_with(';');

    // Indentation
    new_content.push_str("\n");
    new_content.push_str(&repeat(" ")
        .take(suggestion.line_range.start.column - 1 as usize)
        .collect::<String>());

    // TODO(killercup): Replace sections of lines only
    new_content.push_str(suggestion.replacement.trim());

    if remember_a_semicolon {
        new_content.push_str(";");
    }

    // Add the lines after the section we want to replace
    new_content.push_str("\n");
    new_content.push_str(&file_content.lines()
        .skip(suggestion.line_range.end.line as usize)
        .collect::<Vec<_>>()
        .join("\n"));
    new_content.push_str("\n");

    let mut file = try!(File::create(&suggestion.file_name));
    let new_content = new_content.as_bytes();

    try!(file.set_len(new_content.len() as u64));
    try!(file.write_all(&new_content));

    Ok(())
}
<commit_msg>Omit Needless Borrows<commit_after>extern crate serde_json;
#[macro_use]
extern crate quick_error;
#[macro_use]
extern crate clap;
extern crate colored;

extern crate rustfix;

use std::fs::File;
use std::io::{Read, Write};
use std::error::Error;
use std::process::Command;

use colored::Colorize;
use clap::{Arg, App};

use rustfix::Suggestion;
use rustfix::diagnostics::Diagnostic;

const USER_OPTIONS: &'static str = "What do you want to do? \
    [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving)";

fn main() {
    let program = try_main();
    match program {
        Ok(_) => std::process::exit(0),
        Err(ProgramError::UserAbort) => {
            writeln!(std::io::stdout(), "{}", ProgramError::UserAbort).unwrap();
            std::process::exit(0);
        }
        Err(error) => {
            writeln!(std::io::stderr(), "An error occured: {}", error).unwrap();
            writeln!(std::io::stderr(), "{:?}", error).unwrap();
            if let Some(cause) = error.cause() {
                writeln!(std::io::stderr(), "Cause: {:?}", cause).unwrap();
            }
            std::process::exit(1);
        }
    }
}

macro_rules! flush {
    () => (try!(std::io::stdout().flush());)
}

fn try_main() -> Result<(), ProgramError> {
    let matches = App::new("rustfix")
        .about("Automatically apply suggestions made by rustc")
        .version(crate_version!())
        .arg(Arg::with_name("clippy")
            .long("clippy")
            .help("Use `cargo clippy` for suggestions"))
        .arg(Arg::with_name("from_file")
            .long("from-file")
            .value_name("FILE")
            .takes_value(true)
            .help("Read suggestions from file (each line is a JSON object)"))
        .get_matches();

    // Get JSON output from rustc...
    let json = if let Some(file_name) = matches.value_of("from_file") {
        // either by reading a file the user saved (probably only for debugging rustfix itself)...
        try!(json_from_file(&file_name))
    } else {
        // or by spawning a subcommand that runs rustc.
        let subcommand = if matches.is_present("clippy") {
            "clippy"
        } else {
            "rustc"
        };
        try!(json_from_subcommand(subcommand))
    };

    let suggestions: Vec<Suggestion> = json.lines()
        .filter(not_empty)
        .flat_map(|line| serde_json::from_str::<Diagnostic>(line))
        .flat_map(|diagnostic| rustfix::collect_suggestions(&diagnostic, None))
        .collect();

    try!(handle_suggestions(&suggestions));

    Ok(())
}

fn json_from_file(file_name: &str) -> Result<String, ProgramError> {
    read_file_to_string(file_name).map_err(From::from)
}

fn json_from_subcommand(subcommand: &str) -> Result<String, ProgramError> {
    let output = try!(Command::new("cargo")
        .args(&[subcommand,
                "--quiet",
                "--color", "never",
                "--",
                "-Z", "unstable-options",
                "--error-format", "json"])
        .output());

    let content = try!(String::from_utf8(output.stderr));

    if !output.status.success() {
        return Err(ProgramError::SubcommandError(format!("cargo {}", subcommand), content));
    }

    Ok(content)
}

fn handle_suggestions(suggestions: &[Suggestion]) -> Result<(), ProgramError> {
    let mut accepted_suggestions: Vec<&Suggestion> = vec![];

    if suggestions.is_empty() {
        println!("I don't have any suggestions for you right now. Check back later!");
        return Ok(());
    }

    'suggestions: for suggestion in suggestions {
        println!("\n\n{info}: {message}\n\
            {arrow} {file}:{range}\n\
            {suggestion}\n\n\
            {text}\n\n\
            {with}\n\n\
            {replacement}\n",
            info = "Info".green().bold(),
            message = split_at_lint_name(&suggestion.message),
            arrow = "  -->".blue().bold(),
            suggestion = "Suggestion - Replace:".yellow().bold(),
            file = suggestion.file_name,
            range = suggestion.line_range,
            text = indent(4, &reset_indent(&suggestion.text)),
            with = "with:".yellow().bold(),
            replacement = indent(4, &suggestion.replacement));

        'userinput: loop {
            print!("{arrow} {user_options}\n\
                {prompt} ",
                arrow = "==>".green().bold(),
                prompt = "  >".green().bold(),
                user_options = USER_OPTIONS.green());

            flush!();
            let mut input = String::new();
            try!(std::io::stdin().read_line(&mut input));

            match input.trim() {
                "s" => {
                    println!("Skipped.");
                    continue 'suggestions;
                }
                "r" => {
                    accepted_suggestions.push(suggestion);
                    println!("Suggestion accepted. I'll remember that and apply it later.");
                    continue 'suggestions;
                }
                "q" => {
                    println!("Thanks for playing!");
                    break 'suggestions;
                }
                "a" => {
                    return Err(ProgramError::UserAbort);
                }
                _ => {
                    println!("{error}: I didn't quite get that. {user_options}",
                                error = "Error".red().bold(),
                                user_options = USER_OPTIONS);
                    continue 'userinput;
                }
            }
        }
    }

    if !accepted_suggestions.is_empty() {
        println!("Good work. Let me just apply these {} changes!",
                 accepted_suggestions.len());

        for suggestion in accepted_suggestions.iter().rev() {
            try!(apply_suggestion(suggestion));

            print!(".");
            flush!();
        }

        println!("\nDone.");
    }

    Ok(())
}

quick_error! {
    /// All possible errors in programm lifecycle
    #[derive(Debug)]
    pub enum ProgramError {
        UserAbort {
            display("Let's get outta here!")
        }
        /// Missing File
        NoFile {
            display("No input file given")
        }
        SubcommandError(subcommand: String, output: String) {
            display("Error executing subcommand `{}`", subcommand)
            description(output)
        }
        /// Error while dealing with file or stdin/stdout
        Io(err: std::io::Error) {
            from()
            cause(err)
            display("I/O error")
            description(err.description())
        }
        Utf8Error(err: std::string::FromUtf8Error) {
            from()
            display("Error reading input as UTF-8")
        }
        /// Error with deserialization
        Serde(err: serde_json::Error) {
            from()
            cause(err)
            display("Serde JSON error")
            description(err.description())
        }
    }
}

// Helpers
// -------

fn read_file_to_string(file_name: &str) -> Result<String, std::io::Error> {
    let mut file = try!(File::open(file_name));
    let mut buffer = String::new();
    try!(file.read_to_string(&mut buffer));
    Ok(buffer)
}

fn not_empty(s: &&str) -> bool {
    !s.trim().is_empty()
}

fn split_at_lint_name(s: &str) -> String {
    s.split(", #[")
        .collect::<Vec<_>>()
        .join("\n      #[") // Length of whitespace == length of "Info: "
}

fn reset_indent(s: &str) -> String {
    let leading_whitespace = s.lines()
        .nth(0)
        .unwrap_or("")
        .chars()
        .take_while(|&c| char::is_whitespace(c))
        .count();

    s.lines()
        .map(|line| String::from(&line[leading_whitespace..]))
        .collect::<Vec<_>>()
        .join("\n")
}

fn indent(size: u32, s: &str) -> String {
    let whitespace: String = std::iter::repeat(' ').take(size as usize).collect();

    s.lines()
        .map(|l| format!("{}{}", whitespace, l))
        .collect::<Vec<_>>()
        .join("\n")
}

/// Apply suggestion to a file
///
/// Please beware of ugly hacks below! Originally, I wanted to replace byte ranges, but sadly the
/// ranges rustc's JSON output gives me do not correspond to the parts of the file they are meant
/// to correspond to. So, for now, let's just replace lines!
///
/// This function is as stupid as possible. Make sure you call for the replacemnts in one file in
/// reverse order to not mess up the lines for replacements further down the road.
fn apply_suggestion(suggestion: &Suggestion) -> Result<(), ProgramError> {
    use std::cmp::max;
    use std::iter::repeat;

    let file_content = try!(read_file_to_string(&suggestion.file_name));
    let mut new_content = String::new();

    // Add the lines before the section we want to replace
    new_content.push_str(&file_content.lines()
        .take(max(suggestion.line_range.start.line - 1, 0) as usize)
        .collect::<Vec<_>>()
        .join("\n"));

    // Some suggestions seem to currently omit the trailing semicolon
    let remember_a_semicolon = suggestion.text.trim().ends_with(';');

    // Indentation
    new_content.push_str("\n");
    new_content.push_str(&repeat(" ")
        .take(suggestion.line_range.start.column - 1 as usize)
        .collect::<String>());

    // TODO(killercup): Replace sections of lines only
    new_content.push_str(suggestion.replacement.trim());

    if remember_a_semicolon {
        new_content.push_str(";");
    }

    // Add the lines after the section we want to replace
    new_content.push_str("\n");
    new_content.push_str(&file_content.lines()
        .skip(suggestion.line_range.end.line as usize)
        .collect::<Vec<_>>()
        .join("\n"));
    new_content.push_str("\n");

    let mut file = try!(File::create(&suggestion.file_name));
    let new_content = new_content.as_bytes();

    try!(file.set_len(new_content.len() as u64));
    try!(file.write_all(&new_content));

    Ok(())
}
<|endoftext|>


<commit_before>extern crate zas;

fn main() {
    let dns_server_thread = zas::dns::server::run();

    dns_server_thread.join().unwrap();
}
<commit_msg>Do not compile main function in test mode<commit_after>extern crate zas;

#[cfg(not(test))]
fn main() {
    let dns_server_thread = zas::dns::server::run();

    dns_server_thread.join().unwrap();
}
<|endoftext|>


<commit_before>#![feature(
    slice_patterns,
    fnbox,
    try_from)]
#![allow(dead_code)]
#![cfg_attr(feature = "cargo-clippy", allow(
    cast_lossless,
))]

#[macro_use]
extern crate log;
extern crate log4rs;
extern crate rand;
extern crate roaring;
extern crate linear_map;
extern crate serde;
extern crate serde_json;
extern crate serde_yaml;
#[macro_use]
extern crate serde_derive;
extern crate bincode;
extern crate rocksdb;
extern crate byteorder;
extern crate etcd;
extern crate clap;
extern crate crc16;
extern crate metrics as rust_metrics;
#[macro_use]
extern crate lazy_static;
extern crate futures;
extern crate tokio_core;
extern crate tokio_io;
extern crate bytes;
extern crate num_cpus;

#[cfg(test)]
extern crate env_logger;

#[macro_use]
mod utils;
mod types;
mod version_vector;
// mod gossip;
mod inflightmap;
mod dht;
mod fabric_msg;
mod fabric;
mod storage;
mod hash;
#[macro_use]
mod database;
mod vnode;
mod vnode_sync;
mod resp;
mod server;
mod workers;
mod command;
mod config;
mod metrics;

fn configure() -> config::Config {
    use config::*;
    use clap::{Arg, App, SubCommand};
    use std::path::Path;

    let matches = App::new("SucreDB")
        .version("0.1")
        .about("A database made of sugar cubes")
        .arg(
            Arg::with_name("config_file")
                .short("c")
                .long("config")
                .takes_value(true)
                .help(".yaml config file")
                .long_help(
                    "Path to the .yaml config file. Note that configuration \
                    set through the command line will take precedence \
                    over the config file.",
                )
                .display_order(0),
        )
        .arg(
            Arg::with_name("data_dir")
                .short("d")
                .long("data")
                .takes_value(true)
                .help("Data directory"),
        )
        .arg(
            Arg::with_name("etcd_addr")
                .short("e")
                .long("etcd")
                .help("etcd addres")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("cluster_name")
                .short("n")
                .long("cluster")
                .help("The cluster name")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("listen_addr")
                .short("l")
                .long("listen")
                .help("Listen addr")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("fabric_addr")
                .short("f")
                .long("fabric")
                .help("Fabric listen addr")
                .takes_value(true),
        )
        .subcommand(
            SubCommand::with_name("init")
                .about("Init and configure the cluster")
                .arg(
                    Arg::with_name("replication_factor")
                        .short("r")
                        .help("Number of replicas")
                        .default_value(DEFAULT_REPLICATION_FACTOR),
                )
                .arg(
                    Arg::with_name("partitions")
                        .short("p")
                        .help("Number of partitions")
                        .long_help(
                            "Number of partitions, the recommended value is \
                            `expected node count * 10` rounded up to the next power of 2.",
                        )
                        .default_value(DEFAULT_PARTITIONS),
                )
                .display_order(0),
        )
        .get_matches();

    let mut config = Default::default();

    if let Some(v) = matches.value_of("config_file") {
        read_config_file(Path::new(v), &mut config);
    } else {
        setup_default_logging();
    }

    if let Some(v) = matches.value_of("data_dir") {
        config.data_dir = v.into();
    }

    if let Some(v) = matches.value_of("cluster_name") {
        config.cluster_name = v.into();
    }

    if let Some(v) = matches.value_of("listen_addr") {
        config.listen_addr = v.parse().unwrap();
    }

    if let Some(v) = matches.value_of("fabric_addr") {
        config.fabric_addr = v.parse().unwrap();
    }

    if let Some(v) = matches.value_of("etcd_addr") {
        config.etcd_addr = v.parse().unwrap();
    }

    if let Some(sub) = matches.subcommand_matches("init") {
        config.cmd_init = Some(InitCommand {
            partitions: sub.value_of("partitions").unwrap().parse().unwrap(),
            replication_factor: sub.value_of("replication_factor").unwrap().parse().unwrap(),
        });
    }

    config
}

#[cfg(not(test))]
fn main() {
    let server = server::Server::new(configure());
    server.run();
}
<commit_msg>make CI happy<commit_after>#![allow(stable_features)]
#![feature(
    slice_patterns,
    fnbox,
manually_drop, // keep CI happy
    try_from)]
#![allow(dead_code)]
#![cfg_attr(feature = "cargo-clippy", allow(
    cast_lossless,
))]

#[macro_use]
extern crate log;
extern crate log4rs;
extern crate rand;
extern crate roaring;
extern crate linear_map;
extern crate serde;
extern crate serde_json;
extern crate serde_yaml;
#[macro_use]
extern crate serde_derive;
extern crate bincode;
extern crate rocksdb;
extern crate byteorder;
extern crate etcd;
extern crate clap;
extern crate crc16;
extern crate metrics as rust_metrics;
#[macro_use]
extern crate lazy_static;
extern crate futures;
extern crate tokio_core;
extern crate tokio_io;
extern crate bytes;
extern crate num_cpus;

#[cfg(test)]
extern crate env_logger;

#[macro_use]
mod utils;
mod types;
mod version_vector;
// mod gossip;
mod inflightmap;
mod dht;
mod fabric_msg;
mod fabric;
mod storage;
mod hash;
#[macro_use]
mod database;
mod vnode;
mod vnode_sync;
mod resp;
mod server;
mod workers;
mod command;
mod config;
mod metrics;

fn configure() -> config::Config {
    use config::*;
    use clap::{Arg, App, SubCommand};
    use std::path::Path;

    let matches = App::new("SucreDB")
        .version("0.1")
        .about("A database made of sugar cubes")
        .arg(
            Arg::with_name("config_file")
                .short("c")
                .long("config")
                .takes_value(true)
                .help(".yaml config file")
                .long_help(
                    "Path to the .yaml config file. Note that configuration \
                    set through the command line will take precedence \
                    over the config file.",
                )
                .display_order(0),
        )
        .arg(
            Arg::with_name("data_dir")
                .short("d")
                .long("data")
                .takes_value(true)
                .help("Data directory"),
        )
        .arg(
            Arg::with_name("etcd_addr")
                .short("e")
                .long("etcd")
                .help("etcd addres")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("cluster_name")
                .short("n")
                .long("cluster")
                .help("The cluster name")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("listen_addr")
                .short("l")
                .long("listen")
                .help("Listen addr")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("fabric_addr")
                .short("f")
                .long("fabric")
                .help("Fabric listen addr")
                .takes_value(true),
        )
        .subcommand(
            SubCommand::with_name("init")
                .about("Init and configure the cluster")
                .arg(
                    Arg::with_name("replication_factor")
                        .short("r")
                        .help("Number of replicas")
                        .default_value(DEFAULT_REPLICATION_FACTOR),
                )
                .arg(
                    Arg::with_name("partitions")
                        .short("p")
                        .help("Number of partitions")
                        .long_help(
                            "Number of partitions, the recommended value is \
                            `expected node count * 10` rounded up to the next power of 2.",
                        )
                        .default_value(DEFAULT_PARTITIONS),
                )
                .display_order(0),
        )
        .get_matches();

    let mut config = Default::default();

    if let Some(v) = matches.value_of("config_file") {
        read_config_file(Path::new(v), &mut config);
    } else {
        setup_default_logging();
    }

    if let Some(v) = matches.value_of("data_dir") {
        config.data_dir = v.into();
    }

    if let Some(v) = matches.value_of("cluster_name") {
        config.cluster_name = v.into();
    }

    if let Some(v) = matches.value_of("listen_addr") {
        config.listen_addr = v.parse().unwrap();
    }

    if let Some(v) = matches.value_of("fabric_addr") {
        config.fabric_addr = v.parse().unwrap();
    }

    if let Some(v) = matches.value_of("etcd_addr") {
        config.etcd_addr = v.parse().unwrap();
    }

    if let Some(sub) = matches.subcommand_matches("init") {
        config.cmd_init = Some(InitCommand {
            partitions: sub.value_of("partitions").unwrap().parse().unwrap(),
            replication_factor: sub.value_of("replication_factor").unwrap().parse().unwrap(),
        });
    }

    config
}

#[cfg(not(test))]
fn main() {
    let server = server::Server::new(configure());
    server.run();
}
<|endoftext|>


<commit_before>fn main() {
    println!("Hello, world!");
}
<commit_msg>feat(main): Include both git modules in main module<commit_after>mod git_history;
mod git_client;

fn main() {
    println!("semantic.rs 🚀");
}
<|endoftext|>


<commit_before>extern crate piston;
extern crate graphics;
extern crate glutin_window;
extern crate opengl_graphics;
extern crate rand;

pub mod tetris;

use piston::window::WindowSettings;
use piston::event::*;
use glutin_window::GlutinWindow as Glutin_Window;
use opengl_graphics::{ GlGraphics, OpenGL };
use opengl_graphics::glyph_cache::GlyphCache;
use graphics::{ Transformed };
use piston::input::Button::{ Keyboard };
use piston::input::Input;
use piston::input::keyboard::Key;
use std::path::Path;

use tetris::*;

struct App {
    gl: GlGraphics,
    tetris: Tetris,
    elapsed_time: f64,
    cache: GlyphCache<'static>,
    should_redraw: bool
}

//const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0];
const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0];
const LIGHT_GRAY: [f32; 4] = [0.3, 0.3, 0.3, 1.0];
const DARK_GRAY: [f32; 4] = [0.1, 0.1, 0.1, 1.0];
const GREEN: [f32; 4] = [0.0, 1.0, 0.0, 1.0];
const CYAN: [f32; 4] = [0.0, 1.0, 1.0, 1.0];
const RED: [f32; 4] = [1.0, 0.0, 0.0, 1.0];
const BLUE: [f32; 4] = [0.0, 0.0, 1.0, 1.0];
const ORANGE: [f32; 4] = [1.0, 0.5, 0.0, 1.0];
const YELLOW: [f32; 4] = [1.0, 1.0, 0.0, 1.0];
const PURPLE: [f32; 4] = [0.5, 0.0, 1.0, 1.0];

fn get_shape_color(shape_index: i32) -> [f32; 4] {
    match shape_index {
        0 => PURPLE,
        1 => YELLOW,
        2 => RED,
        3 => GREEN,
        4 => ORANGE,
        5 => BLUE,
        6 => CYAN,
        _ => {
            BLACK
        }
    }
}

const TEXT_FONT_SIZE: u32 = 22;
const CELL_SIZE: f64 = 30.0;
const LEFT_MARGIN: f64 = 20f64;
const TOP_MARGIN: f64 = 30f64;

const STATUS_LEFT_MARGIN: f64 = 400f64;
const STATUS_TOP_MARGIN: f64 = 100f64;
const LINE_HEIGHT: f64 = 40f64;
const STATUS_PREVIEW_GRID_HEIGHT: f64 = CELL_SIZE * 6f64;

struct Render;

impl Render {
    pub fn render_cell(c: &graphics::Context, gl: &mut GlGraphics, transform: [[f64; 3]; 2], color: [f32; 4]) {
        let square = graphics::rectangle::square(0f64, 0f64, CELL_SIZE - 1f64);
        let mut rectangle = graphics::Rectangle::new(color);
        rectangle.shape = graphics::rectangle::Shape::Round(4.0, 16);
        rectangle.draw(square, &c.draw_state, transform, gl);
    }

    pub fn render_next_shape(c: &graphics::Context, gl: &mut GlGraphics, tetris: &Tetris,
        transform: graphics::context::Context) -> graphics::context::Context {
        // render the next shape as a preview of what's coming next
        for point in tetris.get_next_shape().iter() {
            let color = get_shape_color(tetris.get_next_shape_index());
            // render the shape at col 2 and row 2
            let (x, y) = ((2 as i16 + point.x) as f64 * CELL_SIZE,
                (2 as i16 + point.y) as f64 * CELL_SIZE);
            Render::render_cell(&c, gl, transform.trans(x, y).transform, color);
        }
        transform.trans(0f64, STATUS_PREVIEW_GRID_HEIGHT)
    }

    pub fn render_game_over_section(c: &graphics::Context, gl: &mut GlGraphics, cache: &mut GlyphCache<'static>,
        tetris: &Tetris, transform: graphics::context::Context) -> graphics::context::Context {
        let mut result: graphics::context::Context = transform;
        let mut text = graphics::Text::new(TEXT_FONT_SIZE);
        text.color = ORANGE;
        text.draw(&"GAME OVER", cache, &c.draw_state, result.transform, gl);
        result = result.trans(0f64, LINE_HEIGHT);

        text.draw(&"Press 'N' for a new game", cache, &c.draw_state, result.transform, gl);
        result = result.trans(0f64, LINE_HEIGHT);

        text.draw(&"Use arrow keys to move and rotate", cache, &c.draw_state,
            result.transform, gl);
        result = result.trans(0f64, LINE_HEIGHT);

        text.draw(&"Press spacebar to drop", cache, &c.draw_state,
            result.transform, gl);
        result = result.trans(0f64, LINE_HEIGHT);

        text.draw(&format!("Press 'K' to decrease starting level ({})", tetris.get_starting_level()),
            cache, &c.draw_state, result.transform, gl);
        result = result.trans(0f64, LINE_HEIGHT);

        text.draw(&"Press 'L' to increase starting level",
            cache, &c.draw_state, result.transform, gl);
        result = result.trans(0f64, LINE_HEIGHT);
        result
    }

    // renders the game board cells e.g. the current shape, ghost shape, and all prior shapes that are
    // fixed in place
    pub fn render_game_board(c: &graphics::Context, gl: &mut GlGraphics, tetris: &Tetris) {
        for col in 0..COL_COUNT as i32 {
            for row in 0..ROW_COUNT as i32 {
                let cell = tetris.get_grid_cell(col, row);
                if cell.cell_type != GridCellType::Void {
                    let color = match cell.cell_type {
                        GridCellType::Shape => get_shape_color(cell.shape_index),
                        GridCellType::Fixed => get_shape_color(cell.shape_index),
                        GridCellType::Ghost => DARK_GRAY,
                        _ => {
                            assert!(false);
                            BLACK
                        }
                    };
                    let (x, y) = (col as f64 * CELL_SIZE, row as f64 * CELL_SIZE);
                    let transform = c.transform.trans(LEFT_MARGIN, TOP_MARGIN).trans(x, y);
                    Render::render_cell(&c, gl, transform, color);
                }
            }
        }
    }
}

impl App {
    fn render(&mut self, args: &RenderArgs) {
        self.should_redraw = false;

        // so that we can access inside closure
        let use_cache = &mut self.cache;
        let use_tetris = &self.tetris;

        self.gl.draw(args.viewport(), |c, gl| {
            // clear the viewport
            graphics::clear(BLACK, gl);

            // render the current score and level
            let mut text = graphics::Text::new(TEXT_FONT_SIZE);
            text.color = ORANGE;
            let mut transform: graphics::context::Context = c.trans(STATUS_LEFT_MARGIN, STATUS_TOP_MARGIN);
            text.draw(&format!("Level: {}", use_tetris.get_level()), use_cache, &c.draw_state,
                transform.transform, gl);
            transform = transform.trans(0f64, LINE_HEIGHT);

            text.draw(&format!("Score: {}", use_tetris.get_score()), use_cache, &c.draw_state,
                transform.transform, gl);
            transform = transform.trans(0f64, LINE_HEIGHT);

            transform = Render::render_next_shape(&c, gl, use_tetris, transform);

            // render GAME OVER text if necessary
            if use_tetris.get_game_over() {
                /*transform =*/ Render::render_game_over_section(&c, gl, use_cache, use_tetris, transform);
            }

            // draw a white border around the game board
            let rect_border = graphics::Rectangle::new_border(LIGHT_GRAY, 1.5);
            rect_border.draw([
                LEFT_MARGIN - 2f64,
                TOP_MARGIN - 2f64,
                (CELL_SIZE * COL_COUNT as f64) + 3f64,
                (CELL_SIZE * ROW_COUNT as f64) + 3f64,
            ], &c.draw_state, c.transform, gl);

            Render::render_game_board(&c, gl, use_tetris);
        });
    }

    fn update(&mut self, args: &UpdateArgs) {
        if self.tetris.get_game_over() {
            self.elapsed_time = 0.0;
        } else {
            // Here we increment the time elapsed between update()'s
            self.elapsed_time += args.dt;
            // if the elapsed time is now greater than the time allotted between ticks, then invoke tetris.tick()
            if self.elapsed_time > self.tetris.get_tick_time() as f64 {
                self.elapsed_time = 0.0;
                self.tetris.tick();
                self.should_redraw = true;
            }
        }
    }

    fn handle_input(&mut self, i: Input) {
        let prev_should_redraw = self.should_redraw;
        self.should_redraw = true;
        match i {
            Input::Press(Keyboard(Key::Left)) => {
                let col: i32 = self.tetris.get_col();
                self.tetris.set_col(col - 1);
            },

            Input::Press(Keyboard(Key::Right)) => {
                let col: i32 = self.tetris.get_col();
                self.tetris.set_col(col + 1);
            },

            Input::Press(Keyboard(Key::Up)) => {
                self.tetris.rotate(true);
            },

            Input::Press(Keyboard(Key::Down)) => {
                let row: i32 = self.tetris.get_row() + 1;
                self.tetris.set_row(row);
            },

            Input::Press(Keyboard(Key::Space)) => {
                let mut row: i32 = self.tetris.get_row() + 1;
                while self.tetris.set_row(row) {
                    row += 1;
                }
                // hard drop immediately spawns next shape
                self.tetris.tick();
            },

            Input::Press(Keyboard(Key::N)) => {
                self.tetris.start_game();
            },

            Input::Press(Keyboard(Key::K)) => {
                if self.tetris.get_starting_level() > 0 {
                    let new_level: u32 = self.tetris.get_starting_level() - 1;
                    self.tetris.set_starting_level(new_level);
                }
            },

            Input::Press(Keyboard(Key::L)) => {
                if self.tetris.get_starting_level() < 30 {
                    let new_level: u32 = self.tetris.get_starting_level() + 1;
                    self.tetris.set_starting_level(new_level);
                }
            },

            _ => {
                self.should_redraw = prev_should_redraw;
            }
        }
    }
}

fn main() {
    start_app();
}

fn start_app() {
    let opengl = OpenGL::_3_2;

    let window = Glutin_Window::new(
        opengl,
        WindowSettings::new("Piston Tetris", [1024, 768])
                       .exit_on_esc(true)
                       .vsync(true)
                       //TODO causes error on ubuntu
                       //.samples(1)
    );

    let font_path = Path::new("FiraMono-Bold.ttf");

    let mut app = App {
        gl: GlGraphics::new(opengl),
        tetris: Tetris::new(),
        elapsed_time: 0.0,
        cache: GlyphCache::new(font_path).unwrap(),
        should_redraw: true,
    };

    for e in window.events().max_fps(60).ups(120) {
        match e {
            Event::Input(i) => {
                app.handle_input(i);
            }

            Event::Render(args) if app.should_redraw => {
                app.render(&args);
            }

            Event::Update(args) => {
                app.update(&args);
            }

            _ => {}
        }
    }
}<commit_msg>reset elapsed time after hard drop<commit_after>extern crate piston;
extern crate graphics;
extern crate glutin_window;
extern crate opengl_graphics;
extern crate rand;

pub mod tetris;

use piston::window::WindowSettings;
use piston::event::*;
use glutin_window::GlutinWindow as Glutin_Window;
use opengl_graphics::{ GlGraphics, OpenGL };
use opengl_graphics::glyph_cache::GlyphCache;
use graphics::{ Transformed };
use piston::input::Button::{ Keyboard };
use piston::input::Input;
use piston::input::keyboard::Key;
use std::path::Path;

use tetris::*;

struct App {
    gl: GlGraphics,
    tetris: Tetris,
    elapsed_time: f64,
    cache: GlyphCache<'static>,
    should_redraw: bool
}

//const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0];
const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0];
const LIGHT_GRAY: [f32; 4] = [0.3, 0.3, 0.3, 1.0];
const DARK_GRAY: [f32; 4] = [0.1, 0.1, 0.1, 1.0];
const GREEN: [f32; 4] = [0.0, 1.0, 0.0, 1.0];
const CYAN: [f32; 4] = [0.0, 1.0, 1.0, 1.0];
const RED: [f32; 4] = [1.0, 0.0, 0.0, 1.0];
const BLUE: [f32; 4] = [0.0, 0.0, 1.0, 1.0];
const ORANGE: [f32; 4] = [1.0, 0.5, 0.0, 1.0];
const YELLOW: [f32; 4] = [1.0, 1.0, 0.0, 1.0];
const PURPLE: [f32; 4] = [0.5, 0.0, 1.0, 1.0];

fn get_shape_color(shape_index: i32) -> [f32; 4] {
    match shape_index {
        0 => PURPLE,
        1 => YELLOW,
        2 => RED,
        3 => GREEN,
        4 => ORANGE,
        5 => BLUE,
        6 => CYAN,
        _ => {
            BLACK
        }
    }
}

const TEXT_FONT_SIZE: u32 = 22;
const CELL_SIZE: f64 = 30.0;
const LEFT_MARGIN: f64 = 20f64;
const TOP_MARGIN: f64 = 30f64;

const STATUS_LEFT_MARGIN: f64 = 400f64;
const STATUS_TOP_MARGIN: f64 = 100f64;
const LINE_HEIGHT: f64 = 40f64;
const STATUS_PREVIEW_GRID_HEIGHT: f64 = CELL_SIZE * 6f64;

struct Render;

impl Render {
    pub fn render_cell(c: &graphics::Context, gl: &mut GlGraphics, transform: [[f64; 3]; 2], color: [f32; 4]) {
        let square = graphics::rectangle::square(0f64, 0f64, CELL_SIZE - 1f64);
        let mut rectangle = graphics::Rectangle::new(color);
        rectangle.shape = graphics::rectangle::Shape::Round(4.0, 16);
        rectangle.draw(square, &c.draw_state, transform, gl);
    }

    pub fn render_next_shape(c: &graphics::Context, gl: &mut GlGraphics, tetris: &Tetris,
        transform: graphics::context::Context) -> graphics::context::Context {
        // render the next shape as a preview of what's coming next
        for point in tetris.get_next_shape().iter() {
            let color = get_shape_color(tetris.get_next_shape_index());
            // render the shape at col 2 and row 2
            let (x, y) = ((2 as i16 + point.x) as f64 * CELL_SIZE,
                (2 as i16 + point.y) as f64 * CELL_SIZE);
            Render::render_cell(&c, gl, transform.trans(x, y).transform, color);
        }
        transform.trans(0f64, STATUS_PREVIEW_GRID_HEIGHT)
    }

    pub fn render_game_over_section(c: &graphics::Context, gl: &mut GlGraphics, cache: &mut GlyphCache<'static>,
        tetris: &Tetris, transform: graphics::context::Context) -> graphics::context::Context {
        let mut result: graphics::context::Context = transform;
        let mut text = graphics::Text::new(TEXT_FONT_SIZE);
        text.color = ORANGE;
        text.draw(&"GAME OVER", cache, &c.draw_state, result.transform, gl);
        result = result.trans(0f64, LINE_HEIGHT);

        text.draw(&"Press 'N' for a new game", cache, &c.draw_state, result.transform, gl);
        result = result.trans(0f64, LINE_HEIGHT);

        text.draw(&"Use arrow keys to move and rotate", cache, &c.draw_state,
            result.transform, gl);
        result = result.trans(0f64, LINE_HEIGHT);

        text.draw(&"Press spacebar to drop", cache, &c.draw_state,
            result.transform, gl);
        result = result.trans(0f64, LINE_HEIGHT);

        text.draw(&format!("Press 'K' to decrease starting level ({})", tetris.get_starting_level()),
            cache, &c.draw_state, result.transform, gl);
        result = result.trans(0f64, LINE_HEIGHT);

        text.draw(&"Press 'L' to increase starting level",
            cache, &c.draw_state, result.transform, gl);
        result = result.trans(0f64, LINE_HEIGHT);
        result
    }

    // renders the game board cells e.g. the current shape, ghost shape, and all prior shapes that are
    // fixed in place
    pub fn render_game_board(c: &graphics::Context, gl: &mut GlGraphics, tetris: &Tetris) {
        for col in 0..COL_COUNT as i32 {
            for row in 0..ROW_COUNT as i32 {
                let cell = tetris.get_grid_cell(col, row);
                if cell.cell_type != GridCellType::Void {
                    let color = match cell.cell_type {
                        GridCellType::Shape => get_shape_color(cell.shape_index),
                        GridCellType::Fixed => get_shape_color(cell.shape_index),
                        GridCellType::Ghost => DARK_GRAY,
                        _ => {
                            assert!(false);
                            BLACK
                        }
                    };
                    let (x, y) = (col as f64 * CELL_SIZE, row as f64 * CELL_SIZE);
                    let transform = c.transform.trans(LEFT_MARGIN, TOP_MARGIN).trans(x, y);
                    Render::render_cell(&c, gl, transform, color);
                }
            }
        }
    }
}

impl App {
    fn render(&mut self, args: &RenderArgs) {
        self.should_redraw = false;

        // so that we can access inside closure
        let use_cache = &mut self.cache;
        let use_tetris = &self.tetris;

        self.gl.draw(args.viewport(), |c, gl| {
            // clear the viewport
            graphics::clear(BLACK, gl);

            // render the current score and level
            let mut text = graphics::Text::new(TEXT_FONT_SIZE);
            text.color = ORANGE;
            let mut transform: graphics::context::Context = c.trans(STATUS_LEFT_MARGIN, STATUS_TOP_MARGIN);
            text.draw(&format!("Level: {}", use_tetris.get_level()), use_cache, &c.draw_state,
                transform.transform, gl);
            transform = transform.trans(0f64, LINE_HEIGHT);

            text.draw(&format!("Score: {}", use_tetris.get_score()), use_cache, &c.draw_state,
                transform.transform, gl);
            transform = transform.trans(0f64, LINE_HEIGHT);

            transform = Render::render_next_shape(&c, gl, use_tetris, transform);

            // render GAME OVER text if necessary
            if use_tetris.get_game_over() {
                /*transform =*/ Render::render_game_over_section(&c, gl, use_cache, use_tetris, transform);
            }

            // draw a white border around the game board
            let rect_border = graphics::Rectangle::new_border(LIGHT_GRAY, 1.5);
            rect_border.draw([
                LEFT_MARGIN - 2f64,
                TOP_MARGIN - 2f64,
                (CELL_SIZE * COL_COUNT as f64) + 3f64,
                (CELL_SIZE * ROW_COUNT as f64) + 3f64,
            ], &c.draw_state, c.transform, gl);

            Render::render_game_board(&c, gl, use_tetris);
        });
    }

    fn update(&mut self, args: &UpdateArgs) {
        if self.tetris.get_game_over() {
            self.elapsed_time = 0.0;
        } else {
            // Here we increment the time elapsed between update()'s
            self.elapsed_time += args.dt;
            // if the elapsed time is now greater than the time allotted between ticks, then invoke tetris.tick()
            if self.elapsed_time > self.tetris.get_tick_time() as f64 {
                self.elapsed_time = 0.0;
                self.tetris.tick();
                self.should_redraw = true;
            }
        }
    }

    fn handle_input(&mut self, i: Input) {
        let prev_should_redraw = self.should_redraw;
        self.should_redraw = true;
        match i {
            Input::Press(Keyboard(Key::Left)) => {
                let col: i32 = self.tetris.get_col();
                self.tetris.set_col(col - 1);
            },

            Input::Press(Keyboard(Key::Right)) => {
                let col: i32 = self.tetris.get_col();
                self.tetris.set_col(col + 1);
            },

            Input::Press(Keyboard(Key::Up)) => {
                self.tetris.rotate(true);
            },

            Input::Press(Keyboard(Key::Down)) => {
                let row: i32 = self.tetris.get_row() + 1;
                self.tetris.set_row(row);
            },

            Input::Press(Keyboard(Key::Space)) => {
                let mut row: i32 = self.tetris.get_row() + 1;
                while self.tetris.set_row(row) {
                    row += 1;
                }
                // hard drop immediately spawns next shape
                self.tetris.tick();
                self.elapsed_time = 0.0;
            },

            Input::Press(Keyboard(Key::N)) => {
                self.tetris.start_game();
            },

            Input::Press(Keyboard(Key::K)) => {
                if self.tetris.get_starting_level() > 0 {
                    let new_level: u32 = self.tetris.get_starting_level() - 1;
                    self.tetris.set_starting_level(new_level);
                }
            },

            Input::Press(Keyboard(Key::L)) => {
                if self.tetris.get_starting_level() < 30 {
                    let new_level: u32 = self.tetris.get_starting_level() + 1;
                    self.tetris.set_starting_level(new_level);
                }
            },

            _ => {
                self.should_redraw = prev_should_redraw;
            }
        }
    }
}

fn main() {
    start_app();
}

fn start_app() {
    let opengl = OpenGL::_3_2;

    let window = Glutin_Window::new(
        opengl,
        WindowSettings::new("Piston Tetris", [1024, 768])
                       .exit_on_esc(true)
                       .vsync(true)
                       //TODO causes error on ubuntu
                       //.samples(1)
    );

    let font_path = Path::new("FiraMono-Bold.ttf");

    let mut app = App {
        gl: GlGraphics::new(opengl),
        tetris: Tetris::new(),
        elapsed_time: 0.0,
        cache: GlyphCache::new(font_path).unwrap(),
        should_redraw: true,
    };

    for e in window.events().max_fps(60).ups(120) {
        match e {
            Event::Input(i) => {
                app.handle_input(i);
            }

            Event::Render(args) if app.should_redraw => {
                app.render(&args);
            }

            Event::Update(args) => {
                app.update(&args);
            }

            _ => {}
        }
    }
}<|endoftext|>


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

extern crate num;
extern crate regex;

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

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

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

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

}

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

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

    Duration::new().set_seconds(seconds).set_minutes(minutes).set_hours(hours).set_days(days).set_weeks(weeks)
}

// Converts a textual input to the number of seconds this represents. String error if something went wrong.
fn input2sec(input:String) -> Result<u64, String> {
    // TODO replace with regex! macro so the is guaranteed to be OK

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

}

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

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

    let duration = sec2duration(seconds);

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

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

#[test]
fn test_print_duration() {
    assert_eq!("", format!("{}", Duration::new()));
    assert_eq!("1s", format!("{}", Duration::new().set_seconds(1)));
    assert_eq!("1m 0s", format!("{}", Duration::new().set_minutes(1)));
    assert_eq!("1m 3s", format!("{}", Duration::new().set_minutes(1).set_seconds(3)));
    assert_eq!("1hr 0m 0s", format!("{}", Duration::new().set_hours(1)));
    assert_eq!("1dy 0hr 0m 0s", format!("{}", Duration::new().set_days(1)));
    assert_eq!("1wk 0dy 0hr 0m 0s", format!("{}", Duration::new().set_weeks(1)));
}

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

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

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

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

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

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

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

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

extern crate num;
extern crate regex;

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

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

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

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

}

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

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

    Duration::new().set_seconds(seconds).set_minutes(minutes).set_hours(hours).set_days(days).set_weeks(weeks)
}

// Converts a textual input to the number of seconds this represents. String error if something went wrong.
fn input2sec(input:String) -> Result<u64, String> {
    // TODO replace with regex! macro so the is guaranteed to be OK

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

}

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

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

    let duration = sec2duration(seconds);

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

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

#[test]
fn test_print_duration() {
    assert_eq!("", format!("{}", Duration::new()));
    assert_eq!("1s", format!("{}", Duration::new().set_seconds(1)));
    assert_eq!("1m 0s", format!("{}", Duration::new().set_minutes(1)));
    assert_eq!("1m 3s", format!("{}", Duration::new().set_minutes(1).set_seconds(3)));
    assert_eq!("1hr 0m 0s", format!("{}", Duration::new().set_hours(1)));
    assert_eq!("1dy 0hr 0m 0s", format!("{}", Duration::new().set_days(1)));
    assert_eq!("1wk 0dy 0hr 0m 0s", format!("{}", Duration::new().set_weeks(1)));
}

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

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

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

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

    // milliseconds
    assert_eq!(input2sec("2000ms".to_string()), Ok(2));
    assert_eq!(input2sec("2ms".to_string()), Ok(0));
    assert_eq!(input2sec("2000 milliseconds".to_string()), Ok(2));
    assert_eq!(input2sec("1500ms".to_string()), Ok(1));
    assert_eq!(input2sec("1100ms".to_string()), Ok(1));
    assert_eq!(input2sec("1999ms".to_string()), Ok(1));
    // Drop sub-millisecond precision
    assert_eq!(input2sec("1000.000ms".to_string()), Ok(1));
    assert_eq!(input2sec("1000.5ms".to_string()), Ok(1));
    assert_eq!(input2sec("1000.4ms".to_string()), Ok(1));
    assert_eq!(input2sec("1000.9ms".to_string()), Ok(1));

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

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

<|endoftext|>


<commit_before>extern crate byteorder;
extern crate stats;
extern crate iron;
extern crate staticfile;
extern crate mount;
extern crate persistent;
#[macro_use]
extern crate lazy_static;
mod lib;

use std::fs::File;
use std::io::*;
use iron::{Iron, Request, Response, IronResult, IronError, Plugin};
use iron::typemap::Key;
use iron::status;
use iron::mime::Mime;
use mount::Mount;
use staticfile::Static;
use std::path::Path;
use lib::caching::CorrelationCache;
use std::ascii::AsciiExt;

const PER_PAGE : usize = 100;

#[derive(Copy, Clone)]
pub struct CorrCache;
impl Key for CorrCache { type Value = CorrelationCache; }

lazy_static! {
    static ref DATA_SETS: Vec<lib::btsf::BinaryTimeSeries> = {
        let mut all_data = Vec::with_capacity(390141);
        lib::btsf::read_btsf_file(&mut BufReader::new(File::open("./btsf/fred.btsf").unwrap()), &mut all_data).unwrap();
        lib::btsf::read_btsf_file(&mut File::open("./btsf/mortality.btsf").unwrap(), &mut all_data).unwrap();
        lib::btsf::read_btsf_file(&mut File::open("./btsf/canada_gdp.btsf").unwrap(), &mut all_data).unwrap();
        all_data
    };
}

fn main() {
    fn find_handler(req: &mut Request) -> IronResult<Response>{
        let mut buffer: Vec<u8> = Vec::new();
        req.body.read_to_end(&mut buffer).unwrap();
        let mut input_charts = Vec::with_capacity(1);
        if let Err(e) = lib::btsf::read_btsf_file(&mut Cursor::new(&mut buffer), &mut input_charts) {
            return Err(IronError::new(e, status::BadRequest))
        };
        if input_charts.len() != 1 {
            return Ok(Response::with((status::BadRequest, "Please send a BTSF file with precisely one chart in it")))
        }

        let result = {
            let mutex = req.get::<persistent::Write<CorrCache>>().unwrap();
            let mut cache = mutex.lock().unwrap();
            cache.correlate(&input_charts[0], &DATA_SETS[..])
        };

        // TODO: URL decode query so you can search for spaces and it doesn't try to search for '%20'
        // TODO: Faster filtering algorithm
        // TODO: fuzzy matching
        let filter : String = req.url.query.as_ref().map(|x| &**x).unwrap_or("").to_ascii_lowercase();
        let filtered : Vec<lib::btsf::CorrelatedTimeSeries> = result.into_iter().filter(|s| s.series.name.to_ascii_lowercase().contains(&filter)).take(PER_PAGE).collect();

        let mut response_data: Vec<u8> = Vec::new();
        if let Err(e) = lib::btsf::write_correlated_btsf_file(&filtered[..], &mut response_data) {
            return Err(IronError::new(e, status::InternalServerError));
        }

        let content_type: Mime = "application/octet-stream".parse().unwrap();
        return Ok(Response::with((status::Ok, content_type, response_data)));
    };

    fn raw_handler(req: &mut Request) -> IronResult<Response>{
        let filter : String = req.url.query.as_ref().map(|x| &**x).unwrap_or("").to_ascii_lowercase();
        let result: Vec<&lib::btsf::BinaryTimeSeries> = DATA_SETS.iter().filter(|s| s.name.to_ascii_lowercase().contains(&filter)).take(PER_PAGE).collect();

        let mut response_data: Vec<u8> = Vec::new();
        if let Err(e) = lib::btsf::write_btsf_file(&result[..], &mut response_data) {
            return Err(IronError::new(e, status::InternalServerError));
        }

        let content_type: Mime = "application/octet-stream".parse().unwrap();
        return Ok(Response::with((status::Ok, content_type, response_data)));
    };

    let mut mount = Mount::new();
    mount
        .mount("/", Static::new(Path::new("./public")))
        .mount("/raw", raw_handler)
        .mount("/find", find_handler);

    let corr_cache = CorrelationCache::new();
    let mut chain = iron::Chain::new(mount);
    chain.link_before(persistent::Write::<CorrCache>::one(corr_cache));

    // This print statement is partially just to invoke the lazy static
    println!("Serving up {} data sets!", DATA_SETS.len());
    Iron::new(chain).http("localhost:8080").unwrap();
}
<commit_msg>Only load FRED file if it exists<commit_after>extern crate byteorder;
extern crate stats;
extern crate iron;
extern crate staticfile;
extern crate mount;
extern crate persistent;
#[macro_use]
extern crate lazy_static;
mod lib;

use std::fs::File;
use std::io::*;
use iron::{Iron, Request, Response, IronResult, IronError, Plugin};
use iron::typemap::Key;
use iron::status;
use iron::mime::Mime;
use mount::Mount;
use staticfile::Static;
use std::path::Path;
use lib::caching::CorrelationCache;
use std::ascii::AsciiExt;

const PER_PAGE : usize = 100;

#[derive(Copy, Clone)]
pub struct CorrCache;
impl Key for CorrCache { type Value = CorrelationCache; }

lazy_static! {
    static ref DATA_SETS: Vec<lib::btsf::BinaryTimeSeries> = {
        let mut all_data = Vec::new();
        lib::btsf::read_btsf_file(&mut File::open("./btsf/mortality.btsf").unwrap(), &mut all_data).unwrap();
        lib::btsf::read_btsf_file(&mut File::open("./btsf/canada_gdp.btsf").unwrap(), &mut all_data).unwrap();
        if Path::new("./btsf/fred.btsf").exists() {
            lib::btsf::read_btsf_file(&mut BufReader::new(File::open("./btsf/fred.btsf").unwrap()), &mut all_data).unwrap();
        }
        all_data
    };
}

fn main() {
    fn find_handler(req: &mut Request) -> IronResult<Response>{
        let mut buffer: Vec<u8> = Vec::new();
        req.body.read_to_end(&mut buffer).unwrap();
        let mut input_charts = Vec::with_capacity(1);
        if let Err(e) = lib::btsf::read_btsf_file(&mut Cursor::new(&mut buffer), &mut input_charts) {
            return Err(IronError::new(e, status::BadRequest))
        };
        if input_charts.len() != 1 {
            return Ok(Response::with((status::BadRequest, "Please send a BTSF file with precisely one chart in it")))
        }

        let result = {
            let mutex = req.get::<persistent::Write<CorrCache>>().unwrap();
            let mut cache = mutex.lock().unwrap();
            cache.correlate(&input_charts[0], &DATA_SETS[..])
        };

        // TODO: URL decode query so you can search for spaces and it doesn't try to search for '%20'
        // TODO: Faster filtering algorithm
        // TODO: fuzzy matching
        let filter : String = req.url.query.as_ref().map(|x| &**x).unwrap_or("").to_ascii_lowercase();
        let filtered : Vec<lib::btsf::CorrelatedTimeSeries> = result.into_iter().filter(|s| s.series.name.to_ascii_lowercase().contains(&filter)).take(PER_PAGE).collect();

        let mut response_data: Vec<u8> = Vec::new();
        if let Err(e) = lib::btsf::write_correlated_btsf_file(&filtered[..], &mut response_data) {
            return Err(IronError::new(e, status::InternalServerError));
        }

        let content_type: Mime = "application/octet-stream".parse().unwrap();
        return Ok(Response::with((status::Ok, content_type, response_data)));
    };

    fn raw_handler(req: &mut Request) -> IronResult<Response>{
        let filter : String = req.url.query.as_ref().map(|x| &**x).unwrap_or("").to_ascii_lowercase();
        let result: Vec<&lib::btsf::BinaryTimeSeries> = DATA_SETS.iter().filter(|s| s.name.to_ascii_lowercase().contains(&filter)).take(PER_PAGE).collect();

        let mut response_data: Vec<u8> = Vec::new();
        if let Err(e) = lib::btsf::write_btsf_file(&result[..], &mut response_data) {
            return Err(IronError::new(e, status::InternalServerError));
        }

        let content_type: Mime = "application/octet-stream".parse().unwrap();
        return Ok(Response::with((status::Ok, content_type, response_data)));
    };

    let mut mount = Mount::new();
    mount
        .mount("/", Static::new(Path::new("./public")))
        .mount("/raw", raw_handler)
        .mount("/find", find_handler);

    let corr_cache = CorrelationCache::new();
    let mut chain = iron::Chain::new(mount);
    chain.link_before(persistent::Write::<CorrCache>::one(corr_cache));

    // This print statement is partially just to invoke the lazy static
    println!("Serving up {} data sets!", DATA_SETS.len());
    Iron::new(chain).http("localhost:8080").unwrap();
}
<|endoftext|>