<commit_before>extern crate osmio;
extern crate image;
extern crate gif;
extern crate clap;

use clap::{Arg, App};

use std::fs;
use osmio::OSMReader;
use osmio::pbf::PBFReader;
use std::io::BufReader;
use std::collections::{HashMap, HashSet};

use gif::SetParameter;

type Frames = Vec<(u32, Vec<u32>)>;

fn read_file(filename: &str, height: u32, sec_per_frame: u32, bbox: &[f32; 4]) -> Frames {
    let file = BufReader::new(fs::File::open(&filename).unwrap());
    let mut node_reader = PBFReader::new(file);
    let node_reader = node_reader.nodes();

    println!("Parsing {}", filename);

    let mut results: HashMap<u32, HashSet<u32>> = HashMap::new();

    let left = bbox[0]; let bottom = bbox[1]; let right = bbox[2]; let top = bbox[3];
    let bbox_width = right - left;
    let bbox_height = top - bottom;
    let width = ((bbox_width / bbox_height) * (height as f32)) as u32;

    // 1st April 2005, midnight GMT. We presume no OSM editing before then.
    let osm_epoch = 1109635200;

    // FIXME use a btreemap?

    let mut first_frame_no = std::u32::MAX;
    let mut last_frame_no = 0;

    let mut num_nodes = 0;
    for node in node_reader {
        if let (Some(lat), Some(lon)) = (node.lat, node.lon) {
            if lat > top || lat < bottom || lon > right || lon < left {
                continue;
            }

            let timestamp = node.timestamp.to_epoch_number() as u64;
            if timestamp < osm_epoch {
                panic!("timestamp before epoch. Change code. {}", timestamp);
            }
            let offset = (timestamp - osm_epoch) as u32;
            // TODO double check that this rounds down
            let frame_no = offset / sec_per_frame;

            if frame_no < first_frame_no {
                first_frame_no = frame_no;
            }
            if frame_no > last_frame_no {
                last_frame_no = frame_no;
            }

            let pixel_idx = latlon_to_pixel_index(lat, lon, width, height, &bbox);
            results.entry(frame_no).or_insert(HashSet::new()).insert(pixel_idx);

            num_nodes += 1;
            if num_nodes % 10_000_000 == 0 {
                println!("Done {} nodes", num_nodes);
            }
        }
    }
    let num_frames = last_frame_no - first_frame_no + 1;
    println!("There are {} frames, which is {} sec", num_frames, num_frames as f32/30.);

    let mut sorted_results = Vec::with_capacity((last_frame_no-first_frame_no+1) as usize);

    for frame_no in 0..num_frames {
        match results.remove(&(frame_no+first_frame_no)) {
            None => { sorted_results.push((frame_no, Vec::with_capacity(0))) },
            Some(pixels) => {
                let pixels = pixels.into_iter().collect();
                sorted_results.push((frame_no, pixels));
            }
        }
    }

    sorted_results
}

#[inline(always)]
fn age_to_colour(age: &Option<u32>) -> [u8; 4] {
    match *age {
        None => [0, 0, 0, 0xff],
        Some(age) => {
            let age = age * 3;
            if age > 255 {
                [0, 0, 0, 0xff]
            } else {
                [(255 - age) as u8, 0, 0, 0xff]
            }
        }
    }
}

fn latlon_to_pixel_index(lat: f32, lon: f32, width: u32, height: u32, bbox: &[f32; 4]) -> u32 {
    let left = bbox[0]; let bottom = bbox[1]; let right = bbox[2]; let top = bbox[3];
    assert!(top > bottom);
    let bbox_width = right - left;
    let bbox_height = top - bottom;
    let lat = top - lat;
    let lon = lon - left;

    let x = ((lon/bbox_width)*(width as f32)) as u32;
    let y = ((lat/bbox_height)*(height as f32)) as u32;

    //println!("lat = {} lon = {} x = {} y = {} y*width+x = {}", lat, lon, x, y, y*width+x);
    let i = y * width + x;

    i
}

fn create_equirectangular_map(frames: Frames, output_image_filename: &str, height: u32, bbox: &[f32; 4]) {
    let mut output_file = fs::File::create(output_image_filename).expect("Can't create image");

    let left = bbox[0]; let bottom = bbox[1]; let right = bbox[2]; let top = bbox[3];
    let bbox_width = right - left;
    let bbox_height = top - bottom;
    let width = ((bbox_width / bbox_height) * (height as f32)) as u32;

    // FIXME change width/height to u16?
    let mut encoder = gif::Encoder::new(&mut output_file, width as u16, height as u16, &[]).expect("Couldn't create encoder");
    encoder.set(gif::Repeat::Infinite).expect("Couldn't get inf repeat");

    let mut image = vec![None; (width*height) as usize];

    for (frame_no, pixels) in frames.into_iter() {
        for i in pixels {
            image[i as usize] = Some(frame_no);
        }

        let mut pixels = Vec::with_capacity(image.len() * 4);
        for p in image.iter().cloned() {
            pixels.extend(age_to_colour(&p.clone()).iter());
        }

        let mut frame = gif::Frame::from_rgba(width as u16, height as u16, pixels.as_mut_slice());
        // 30 fps, and delay is in units of 10ms.
        frame.delay = 100 / 30;

        encoder.write_frame(&frame).expect("Couldn't write frame");

        println!("Wrote frame {}", frame_no);

    }

}

fn main() {
    let matches = App::new("osm-history-animation")
                          .arg(Arg::with_name("pbf_file").long("pbf-file").short("i")
                               .takes_value(true))
                          .arg(Arg::with_name("output_image") .long("output-image").short("o")
                               .takes_value(true))
                          .arg(Arg::with_name("height") .long("height").short("h")
                               .takes_value(true))
                          .arg(Arg::with_name("spf") .long("sec-per-frame").short("s")
                               .takes_value(true))
                          .get_matches();

    let input_filename = matches.value_of("pbf_file").unwrap();
    let output_image = matches.value_of("output_image").unwrap();
    let height: u32 = matches.value_of("height").unwrap().parse().unwrap();
    let frames_per_sec: u32 = matches.value_of("spf").unwrap().parse().unwrap();

    let bbox = [-13.1, 49.28, -3.26, 56.69];

    let frames = read_file(&input_filename, height, frames_per_sec, &bbox);

    println!("Creating image {}", output_image);

    create_equirectangular_map(frames, &output_image, height, &bbox);

    println!("\nFinished");
}
<commit_msg>stuff<commit_after>extern crate osmio;
extern crate image;
extern crate gif;
extern crate clap;

use clap::{Arg, App};

use std::fs;
use osmio::OSMReader;
use osmio::pbf::PBFReader;
use std::io::{Read, Write, BufReader, BufRead, BufWriter};
use std::collections::{HashMap, HashSet};

use gif::SetParameter;

type Frames = Vec<(u32, Vec<u32>)>;

struct ColourRamp {
    empty_colour: (u8, u8, u8),
    steps: Vec<(u32, (u8, u8, u8))>,
}

impl ColourRamp {
    fn new_from_filename(filename: &str) -> Self {
        let mut contents = String::new();
        let mut file = fs::File::open(filename).unwrap();
        file.read_to_string(&mut contents).expect("Couldn't read colour ramp file");
        Self::new_from_text(&contents)

    }
    fn new_from_text(source: &str) -> Self {
        let lines: Vec<_> = source.lines().collect();
        let empty_vec = lines[0].split(",").filter_map(|x| x.parse::<u8>().ok()).take(3).collect::<Vec<_>>();
        let empty = (empty_vec[0], empty_vec[1], empty_vec[2]);

        let mut steps = Vec::new();
        for line in lines.iter().skip(1) {
            let line = line.split(",").filter_map(|x| x.parse::<u32>().ok()).take(4).collect::<Vec<_>>();
            let age = line[0];
            let colour = (line[1] as u8, line[2] as u8, line[3] as u8);
            steps.push((age, colour));
        }

        if steps.len() > 254 {
            panic!("Too many steps");
        }

        ColourRamp{ empty_colour: empty, steps: steps }
    }

    fn palette(&self) -> Vec<u8> {
        let mut results = Vec::with_capacity((self.steps.len()+1)*3);
        results.push(self.empty_colour.0);
        results.push(self.empty_colour.1);
        results.push(self.empty_colour.2);

        for &(_, (r, g, b)) in self.steps.iter() {
            results.push(r);
            results.push(g);
            results.push(b);
        }

        results
    }

    fn index_for_age(&self, age: Option<u32>) -> u8 {
        match age {
            None => 0,
            Some(age) => match self.steps.iter().position(|&(x, _)| x == age) {
                None => 0,
                Some(i) => i as u8,
            }
        }
    }
}

fn read_pbf(filename: &str, height: u32, sec_per_frame: u32, bbox: &[f32; 4]) -> Frames {
    let file = BufReader::new(fs::File::open(&filename).unwrap());
    let mut node_reader = PBFReader::new(file);
    let node_reader = node_reader.nodes();

    println!("Parsing {}", filename);

    let mut results: HashMap<u32, HashSet<u32>> = HashMap::new();

    let left = bbox[0]; let bottom = bbox[1]; let right = bbox[2]; let top = bbox[3];
    let bbox_width = right - left;
    let bbox_height = top - bottom;
    let width = ((bbox_width / bbox_height) * (height as f32)) as u32;

    // 1st April 2005, midnight GMT. We presume no OSM editing before then.
    let osm_epoch = 1109635200;

    // FIXME use a btreemap?

    let mut first_frame_no = std::u32::MAX;
    let mut last_frame_no = 0;

    let mut num_nodes = 0;
    for node in node_reader {
        if let (Some(lat), Some(lon)) = (node.lat, node.lon) {
            if lat > top || lat < bottom || lon > right || lon < left {
                continue;
            }

            let timestamp = node.timestamp.to_epoch_number() as u64;
            if timestamp < osm_epoch {
                panic!("timestamp before epoch. Change code. {}", timestamp);
            }
            let offset = (timestamp - osm_epoch) as u32;
            // TODO double check that this rounds down
            let frame_no = offset / sec_per_frame;

            if frame_no < first_frame_no {
                first_frame_no = frame_no;
            }
            if frame_no > last_frame_no {
                last_frame_no = frame_no;
            }

            let pixel_idx = latlon_to_pixel_index(lat, lon, width, height, &bbox);
            results.entry(frame_no).or_insert(HashSet::new()).insert(pixel_idx);

            num_nodes += 1;
            if num_nodes % 10_000_000 == 0 {
                println!("Done {} nodes", num_nodes);
            }
        }
    }
    let num_frames = last_frame_no - first_frame_no + 1;
    println!("There are {} frames, which is {} sec", num_frames, num_frames as f32/30.);

    let mut sorted_results = Vec::with_capacity((last_frame_no-first_frame_no+1) as usize);

    for frame_no in 0..num_frames {
        match results.remove(&(frame_no+first_frame_no)) {
            None => { sorted_results.push((frame_no, Vec::with_capacity(0))) },
            Some(pixels) => {
                let pixels = pixels.into_iter().collect();
                sorted_results.push((frame_no, pixels));
            }
        }
    }

    sorted_results
}

fn write_frames(frames: Frames, filename: &str) {
    let mut file = BufWriter::new(fs::File::create(&filename).unwrap());
    for (frame_no, pixels) in frames.into_iter() {
        write!(file, "{},", frame_no).unwrap();
        for p in pixels {
            write!(file, "{},", p).unwrap();
        }
        write!(file, "\n").unwrap()
    }
}

fn read_frames(filename: &str) -> Frames {
    let file = BufReader::new(fs::File::open(&filename).unwrap());
    let mut results = Frames::new();

    for line in file.lines() {
        let line = line.unwrap();
        let mut nums: Vec<u32> = line.split(",").filter_map(|s| s.parse().ok()).collect();
        let frame_no = nums.remove(0);
        let pixels = nums;
        results.push((frame_no, pixels))
    }

    results
}

fn latlon_to_pixel_index(lat: f32, lon: f32, width: u32, height: u32, bbox: &[f32; 4]) -> u32 {
    let left = bbox[0]; let bottom = bbox[1]; let right = bbox[2]; let top = bbox[3];
    assert!(top > bottom);
    let bbox_width = right - left;
    let bbox_height = top - bottom;
    let lat = top - lat;
    let lon = lon - left;

    let x = ((lon/bbox_width)*(width as f32)) as u32;
    let y = ((lat/bbox_height)*(height as f32)) as u32;

    //println!("lat = {} lon = {} x = {} y = {} y*width+x = {}", lat, lon, x, y, y*width+x);
    let i = y * width + x;

    i
}

fn create_equirectangular_map(frames: Frames, output_image_filename: &str, height: u32, bbox: &[f32; 4], colour_ramp: &ColourRamp) {
    let mut output_file = fs::File::create(output_image_filename).expect("Can't create image");

    let left = bbox[0]; let bottom = bbox[1]; let right = bbox[2]; let top = bbox[3];
    let bbox_width = right - left;
    let bbox_height = top - bottom;
    let width = ((bbox_width / bbox_height) * (height as f32)) as u32;

    // FIXME change width/height to u16?
    let mut encoder = gif::Encoder::new(&mut output_file, width as u16, height as u16, &[]).expect("Couldn't create encoder");
    encoder.set(gif::Repeat::Infinite).expect("Couldn't get inf repeat");

    let mut image = vec![None; (width*height) as usize];

    for (frame_no, pixels) in frames.into_iter() {
        for i in pixels {
            image[i as usize] = Some(frame_no);
        }

        let mut pixels = Vec::with_capacity(image.len() * 4);
        for p in image.iter().cloned() {
            let index = colour_ramp.index_for_age(p.map(|t| frame_no - t));
            pixels.push(index);
        }

        let mut frame = gif::Frame::from_palette_pixels(width as u16, height as u16, &colour_ramp.palette(), pixels.as_mut_slice());
        // 30 fps, and delay is in units of 10ms.
        frame.delay = 100 / 30;

        encoder.write_frame(&frame).expect("Couldn't write frame");

        if frame_no % 30 == 0 {
            println!("Wrote frame {}", frame_no);
        }

    }

}

fn main() {
    let matches = App::new("osm-history-animation")
                          .arg(Arg::with_name("input").long("input").short("i")
                               .takes_value(true))
                          .arg(Arg::with_name("output") .long("output").short("o")
                               .takes_value(true))
                          .arg(Arg::with_name("height") .long("height").short("h")
                               .takes_value(true))
                          .arg(Arg::with_name("spf") .long("sec-per-frame").short("s")
                               .takes_value(true))
                          .arg(Arg::with_name("colour_ramp") .long("colour-ramp")
                               .takes_value(true))
                          .arg(Arg::with_name("save-intermediate").long("save-intermediate"))
                          .arg(Arg::with_name("load-intermediate").long("load-intermediate"))
                          .arg(Arg::with_name("bbox").long("bbox"))
                          .get_matches();

    let input_filename = matches.value_of("input").unwrap();
    let output_filename = matches.value_of("output").unwrap();
    let height: u32 = matches.value_of("height").unwrap().parse().unwrap();
    let frames_per_sec: u32 = matches.value_of("spf").unwrap().parse().unwrap();

    let bbox = match matches.value_of("bbox") {
        None => [-180., -90., 180., 90.],
        Some(text) => {
            let coords: Vec<f32> = text.split(",").map(|x| x.parse().unwrap() ).collect();
            [coords[0], coords[1], coords[2], coords[3]]
        }
    };

    //let bbox = [-13.1, 49.28, -3.26, 56.69];

    let frames = if matches.is_present("load-intermediate") {
        println!("Reading frames from {}", input_filename);
        read_frames(&input_filename)
    } else {
        println!("Reading frames from {}", input_filename);
        read_pbf(&input_filename, height, frames_per_sec, &bbox)
    };

    if matches.is_present("save-intermediate") {
        println!("Saving frame details to {}", output_filename);
        write_frames(frames, &output_filename);
    } else {
        let colour_ramp = ColourRamp::new_from_filename(matches.value_of("colour_ramp").unwrap());
        println!("Creating image {}", output_filename);
        create_equirectangular_map(frames, &output_filename, height, &bbox, &colour_ramp);
    }
    println!("\nFinished");
}
<|endoftext|>


<commit_before>extern crate unicode_width;

mod args;
mod matching;
mod screen;
#[cfg(not(windows))] mod ansi;

use std::collections::HashSet;
use std::process;
use std::io::{stdin, BufRead};
use std::cmp::min;
use screen::Screen;
use screen::Key;
use screen::Key::*;
use self::SearchState::*;
use unicode_width::UnicodeWidthStr;

#[cfg(windows)] pub const NEWLINE: &'static str = "\r\n";
#[cfg(not(windows))] pub const NEWLINE: &'static str = "\n";

const VERSION: &'static str = include_str!(concat!(env!("OUT_DIR"), "/version.txt"));
const TIMESTAMP: &'static str = include_str!(concat!(env!("OUT_DIR"), "/timestamp.txt"));
const TARGET: &'static str = include_str!(concat!(env!("OUT_DIR"), "/target.txt"));
const COMMIT: &'static str = include_str!(concat!(env!("OUT_DIR"), "/commit.txt"));

fn main() {
    if Screen::is_cygwin() {
        println!("This executable does not support Cygwin.");
        return;
    }

    let args = match args::parse_args() {
        Some(args) => args,
        None => {
            process::exit(1);
        },
    };

    if args.help { return; }

    if args.version {
        const THREADS: &'static str = "multi-threaded";
        if COMMIT == "" {
            println!("heatseeker {} {} (built {} for {})", VERSION, THREADS, TIMESTAMP, TARGET);
        } else {
            println!("heatseeker {} {} ({}) (built {} for {})", VERSION, THREADS, COMMIT, TIMESTAMP, TARGET);
        }
        return;
    }

    let choices = read_choices();
    let initial_search = args.initial_search.clone();
    let choices = choices.iter().map(|x| &x[..]).collect::<Vec<&str>>();
    if args.use_first {
        let matches = matching::compute_matches(&choices, &initial_search, args.filter_only);
        println!("{}", matches.get(0).unwrap_or(&""));
        return;
    } else {
        let desired_rows = if args.full_screen { 999 } else { 20 };
        let selections = event_loop(desired_rows, &choices, &initial_search, args.filter_only);
        print!("{}", selections);
    }
}

fn event_loop(desired_rows: u16, choices: &[&str], initial_search: &str, filter_only: bool) -> String {
    let mut search = Search::new(choices, initial_search.to_string(), filter_only);
    let mut screen = Screen::open_screen(desired_rows);

    loop {
        search.recompute_matches();

        match search.state {
            InProgress => draw_screen(&mut screen, &search),
            _ => break,
        }

        let keys = screen.get_buffered_keys();
        for key in &keys {
            handle_key(&mut search, key, screen.visible_choices());
        }
    }

    screen.blank_screen();
    search.get_selections()
}

fn handle_key(search: &mut Search, key: &Key, visible_choices: u16) {
    match *key {
        Char(x) => search.append(x),
        Backspace |
        Control('h') => search.backspace(),
        Control('w') => search.delete_word(),
        Control('u') => search.clear_query(),
        Control('c') |
        Control('g') => search.cancel(),
        Control('t') => { search.toggle_selection(); search.down(visible_choices); },
        Control('p') |
        Up |
        ShiftTab => search.up(visible_choices),
        Control('n') |
        Down |
        Tab => search.down(visible_choices),
        Enter => search.done(),
        _ => {}
    }
}

struct Search<'a> {
    choices: &'a [&'a str],
    query: String,
    matches: Vec<&'a str>,
    stale: bool,
    index: usize,
    state: SearchState,
    selections: HashSet<String>,
    filter_only: bool,
}

#[derive(PartialEq, Eq)]
enum SearchState {
    InProgress,
    Done,
    Canceled,
}

impl<'a> Search<'a> {
    fn new(choices: &'a [&'a str], initial_search: String, filter_only: bool) -> Search<'a> {
        let matches = choices.to_vec();
        Search {
            choices: choices,
            query: initial_search,
            matches: matches,
            stale: true,
            index: 0,
            state: InProgress,
            selections: HashSet::new(),
            filter_only: filter_only,
        }
    }

    fn up(&mut self, visible_choices: u16) {
        let limit = min(visible_choices as usize - 1, self.matches.len() - 1);
        self.index = if self.index == 0 { limit } else { self.index - 1 };
    }

    fn down(&mut self, visible_choices: u16) {
        let limit = min(visible_choices as usize - 1, self.matches.len() - 1);
        self.index = if self.index == limit { 0 } else { self.index + 1 }
    }

    fn backspace(&mut self) {
        self.query.pop();
        self.stale = true;
        self.index = 0;
        self.matches = self.choices.to_vec();
    }

    fn delete_word(&mut self) {
        self.stale = true;
        delete_last_word(&mut self.query);
        self.matches = self.choices.to_vec();
    }

    fn append(&mut self, c: char) {
        self.query.push(c);
        self.stale = true;
        self.index = 0;
    }

    fn clear_query(&mut self) {
        self.query.clear();
        self.matches = self.choices.to_vec();
    }

    fn recompute_matches(&mut self) {
        if self.stale {
            self.matches = matching::compute_matches(&self.matches, &self.query, self.filter_only);
            self.stale = false;
        }
    }

    fn toggle_selection(&mut self) {
        self.recompute_matches();
        let selection = self.matches.get(self.index).unwrap_or(&"").to_string();
        if self.selections.contains(&selection) {
            self.selections.remove(&selection);
        } else {
            self.selections.insert(selection);
        }
    }

    fn get_selections(&mut self) -> String {
        let mut ret = String::new();
        if self.state != Canceled {
            for selection in &self.selections {
                ret.push_str(selection);
                ret.push_str(NEWLINE);
            }
            if ret.is_empty() {
                self.recompute_matches();
                let selection = self.matches.get(self.index).unwrap_or(&"").to_string();
                ret.push_str(&selection);
            }
        }
        ret
    }

    fn cancel(&mut self) {
        self.state = Canceled
    }

    fn done(&mut self) {
        self.state = Done
    }
}

fn draw_screen(screen: &mut Screen, search: &Search) {
    screen.hide_cursor();
    screen.blank_screen();
    screen.write(&format!("> {} ({}/{} choices){}", search.query, search.matches.len(), search.choices.len(), NEWLINE));

    print_matches(screen, &search.matches, &search.query, search.index, &search.selections);

    let query_str: &str = &search.query;
    screen.move_cursor_to_prompt_line(2 + UnicodeWidthStr::width(query_str) as u16);
    screen.show_cursor();
}

fn print_matches(screen: &mut Screen, matches: &[&str], query: &str, index: usize, selections: &HashSet<String>) {
    let mut i = 1;
    for choice in matches.iter() {
        let indices = matching::visual_score(choice, query);
        let max_width = screen.width();
        let mut annotated_choice = choice.to_string();
        if selections.contains(&annotated_choice) {
            annotated_choice.push(' ');
            if cfg!(windows) {
                annotated_choice.push('√');
            } else {
                annotated_choice.push('✓');
            }
        }
        print_match(&annotated_choice, &indices, max_width, &mut |s, highlight| {
            if i == index + 1 {
                if highlight { screen.write_red_inverted(s); } else { screen.write_inverted(s); }
            } else if highlight {
                screen.write_red(s);
            } else { screen.write(s); }
        });
        if i >= screen.visible_choices() as usize {
            return;
        }
        screen.write(NEWLINE);
        i += 1;
    }
}

fn print_match(choice: &str, indices: &[usize], max_width: u16, writer: &mut FnMut(&str, bool)) {
    #[cfg(windows)] const MARGIN: u16 = 1;
    #[cfg(not(windows))] const MARGIN: u16 = 0;
    let max_width = max_width - MARGIN;
    let chars_in_choice = choice.chars().count();
    let mut chars_to_draw = min(chars_in_choice, max_width as usize);
    while UnicodeWidthStr::width(slice_chars(choice, 0, chars_to_draw)) > max_width as usize {
        chars_to_draw -= 1;
    }
    let mut last_idx = 0;
    for &idx in indices {
        let idx = min(idx, chars_to_draw);
        if last_idx >= chars_to_draw {
            return;
        }
        writer(slice_chars(choice, last_idx, idx), false);
        if idx == chars_to_draw { return }
        writer(slice_chars(choice, idx, idx + 1), true);
        last_idx = idx + 1;
    }
    writer(slice_chars(choice, last_idx, chars_to_draw), false);
}

fn read_choices() -> Vec<String> {
    let stdin = stdin();
    let mut lines = Vec::new();

    let mut stdin = stdin.lock();
    loop {
        let mut s = String::new();
        stdin.read_line(&mut s).unwrap();
        if s.is_empty() { break; }
        trim(&mut s);
        lines.push(s);
    }

    lines
}

pub fn trim(s: &mut String) {
    while let Some(x) = s.pop() {
        if x != '\n' && x != '\r' {
            s.push(x);
            return;
        }
    }
}

fn delete_last_word(s: &mut String) {
    let mut deleted_something = false;
    while let Some(x) = s.pop() {
        if x == ' ' {
            if deleted_something {
                s.push(x);
                return;
            }
        } else {
            deleted_something = true;
        }
    }
}

// This is technically a standard library function, but it's plastered with
// stability warnings and therefore only available on the nightly channel.
fn slice_chars(s: &str, begin: usize, end: usize) -> &str {
    assert!(begin <= end);
    let mut count = 0;
    let mut begin_byte = None;
    let mut end_byte = None;

    // This could be even more efficient by not decoding,
    // only finding the char boundaries
    for (idx, _) in s.char_indices() {
        if count == begin { begin_byte = Some(idx); }
        if count == end { end_byte = Some(idx); break; }
        count += 1;
    }
    if begin_byte.is_none() && count == begin { begin_byte = Some(s.len()) }
    if end_byte.is_none() && count == end { end_byte = Some(s.len()) }

    match (begin_byte, end_byte) {
        (None, _) => panic!("slice_chars: `begin` is beyond end of string"),
        (_, None) => panic!("slice_chars: `end` is beyond end of string"),
        (Some(a), Some(b)) => unsafe { s.slice_unchecked(a, b) }
    }
}

#[cfg(test)]
mod tests {
    use super::{trim, delete_last_word};

    #[test]
    fn trim_test() {
        fn should_become(before: &str, after: &str) {
            let mut x = before.to_string();
            trim(&mut x);
            assert_eq!(after.to_string(), x);
        }
        should_become("", "");
        should_become("\n", "");
        should_become("\n\n", "");
        should_become("asdf", "asdf");
        should_become("asdf\n", "asdf");
        should_become("asdf\nasdf\n", "asdf\nasdf");
        should_become("asdf\r\n", "asdf");
    }

    #[test]
    fn delete_word_test() {
        fn should_become(before: &str, after: &str) {
            let mut x = before.to_string();
            delete_last_word(&mut x);
            assert_eq!(after.to_string(), x);
        }
        should_become("", "");
        should_become("a", "");
        should_become("asdf", "");
        should_become("asdf asdf asdf", "asdf asdf ");
        should_become("asdf asdf asdf ", "asdf asdf ");
        should_become("asdf asdf asdf  ", "asdf asdf ");
    }
}
<commit_msg>Replace call to deprecated slice_unchecked<commit_after>extern crate unicode_width;

mod args;
mod matching;
mod screen;
#[cfg(not(windows))] mod ansi;

use std::collections::HashSet;
use std::process;
use std::io::{stdin, BufRead};
use std::cmp::min;
use screen::Screen;
use screen::Key;
use screen::Key::*;
use self::SearchState::*;
use unicode_width::UnicodeWidthStr;

#[cfg(windows)] pub const NEWLINE: &'static str = "\r\n";
#[cfg(not(windows))] pub const NEWLINE: &'static str = "\n";

const VERSION: &'static str = include_str!(concat!(env!("OUT_DIR"), "/version.txt"));
const TIMESTAMP: &'static str = include_str!(concat!(env!("OUT_DIR"), "/timestamp.txt"));
const TARGET: &'static str = include_str!(concat!(env!("OUT_DIR"), "/target.txt"));
const COMMIT: &'static str = include_str!(concat!(env!("OUT_DIR"), "/commit.txt"));

fn main() {
    if Screen::is_cygwin() {
        println!("This executable does not support Cygwin.");
        return;
    }

    let args = match args::parse_args() {
        Some(args) => args,
        None => {
            process::exit(1);
        },
    };

    if args.help { return; }

    if args.version {
        const THREADS: &'static str = "multi-threaded";
        if COMMIT == "" {
            println!("heatseeker {} {} (built {} for {})", VERSION, THREADS, TIMESTAMP, TARGET);
        } else {
            println!("heatseeker {} {} ({}) (built {} for {})", VERSION, THREADS, COMMIT, TIMESTAMP, TARGET);
        }
        return;
    }

    let choices = read_choices();
    let initial_search = args.initial_search.clone();
    let choices = choices.iter().map(|x| &x[..]).collect::<Vec<&str>>();
    if args.use_first {
        let matches = matching::compute_matches(&choices, &initial_search, args.filter_only);
        println!("{}", matches.get(0).unwrap_or(&""));
        return;
    } else {
        let desired_rows = if args.full_screen { 999 } else { 20 };
        let selections = event_loop(desired_rows, &choices, &initial_search, args.filter_only);
        print!("{}", selections);
    }
}

fn event_loop(desired_rows: u16, choices: &[&str], initial_search: &str, filter_only: bool) -> String {
    let mut search = Search::new(choices, initial_search.to_string(), filter_only);
    let mut screen = Screen::open_screen(desired_rows);

    loop {
        search.recompute_matches();

        match search.state {
            InProgress => draw_screen(&mut screen, &search),
            _ => break,
        }

        let keys = screen.get_buffered_keys();
        for key in &keys {
            handle_key(&mut search, key, screen.visible_choices());
        }
    }

    screen.blank_screen();
    search.get_selections()
}

fn handle_key(search: &mut Search, key: &Key, visible_choices: u16) {
    match *key {
        Char(x) => search.append(x),
        Backspace |
        Control('h') => search.backspace(),
        Control('w') => search.delete_word(),
        Control('u') => search.clear_query(),
        Control('c') |
        Control('g') => search.cancel(),
        Control('t') => { search.toggle_selection(); search.down(visible_choices); },
        Control('p') |
        Up |
        ShiftTab => search.up(visible_choices),
        Control('n') |
        Down |
        Tab => search.down(visible_choices),
        Enter => search.done(),
        _ => {}
    }
}

struct Search<'a> {
    choices: &'a [&'a str],
    query: String,
    matches: Vec<&'a str>,
    stale: bool,
    index: usize,
    state: SearchState,
    selections: HashSet<String>,
    filter_only: bool,
}

#[derive(PartialEq, Eq)]
enum SearchState {
    InProgress,
    Done,
    Canceled,
}

impl<'a> Search<'a> {
    fn new(choices: &'a [&'a str], initial_search: String, filter_only: bool) -> Search<'a> {
        let matches = choices.to_vec();
        Search {
            choices: choices,
            query: initial_search,
            matches: matches,
            stale: true,
            index: 0,
            state: InProgress,
            selections: HashSet::new(),
            filter_only: filter_only,
        }
    }

    fn up(&mut self, visible_choices: u16) {
        let limit = min(visible_choices as usize - 1, self.matches.len() - 1);
        self.index = if self.index == 0 { limit } else { self.index - 1 };
    }

    fn down(&mut self, visible_choices: u16) {
        let limit = min(visible_choices as usize - 1, self.matches.len() - 1);
        self.index = if self.index == limit { 0 } else { self.index + 1 }
    }

    fn backspace(&mut self) {
        self.query.pop();
        self.stale = true;
        self.index = 0;
        self.matches = self.choices.to_vec();
    }

    fn delete_word(&mut self) {
        self.stale = true;
        delete_last_word(&mut self.query);
        self.matches = self.choices.to_vec();
    }

    fn append(&mut self, c: char) {
        self.query.push(c);
        self.stale = true;
        self.index = 0;
    }

    fn clear_query(&mut self) {
        self.query.clear();
        self.matches = self.choices.to_vec();
    }

    fn recompute_matches(&mut self) {
        if self.stale {
            self.matches = matching::compute_matches(&self.matches, &self.query, self.filter_only);
            self.stale = false;
        }
    }

    fn toggle_selection(&mut self) {
        self.recompute_matches();
        let selection = self.matches.get(self.index).unwrap_or(&"").to_string();
        if self.selections.contains(&selection) {
            self.selections.remove(&selection);
        } else {
            self.selections.insert(selection);
        }
    }

    fn get_selections(&mut self) -> String {
        let mut ret = String::new();
        if self.state != Canceled {
            for selection in &self.selections {
                ret.push_str(selection);
                ret.push_str(NEWLINE);
            }
            if ret.is_empty() {
                self.recompute_matches();
                let selection = self.matches.get(self.index).unwrap_or(&"").to_string();
                ret.push_str(&selection);
            }
        }
        ret
    }

    fn cancel(&mut self) {
        self.state = Canceled
    }

    fn done(&mut self) {
        self.state = Done
    }
}

fn draw_screen(screen: &mut Screen, search: &Search) {
    screen.hide_cursor();
    screen.blank_screen();
    screen.write(&format!("> {} ({}/{} choices){}", search.query, search.matches.len(), search.choices.len(), NEWLINE));

    print_matches(screen, &search.matches, &search.query, search.index, &search.selections);

    let query_str: &str = &search.query;
    screen.move_cursor_to_prompt_line(2 + UnicodeWidthStr::width(query_str) as u16);
    screen.show_cursor();
}

fn print_matches(screen: &mut Screen, matches: &[&str], query: &str, index: usize, selections: &HashSet<String>) {
    let mut i = 1;
    for choice in matches.iter() {
        let indices = matching::visual_score(choice, query);
        let max_width = screen.width();
        let mut annotated_choice = choice.to_string();
        if selections.contains(&annotated_choice) {
            annotated_choice.push(' ');
            if cfg!(windows) {
                annotated_choice.push('√');
            } else {
                annotated_choice.push('✓');
            }
        }
        print_match(&annotated_choice, &indices, max_width, &mut |s, highlight| {
            if i == index + 1 {
                if highlight { screen.write_red_inverted(s); } else { screen.write_inverted(s); }
            } else if highlight {
                screen.write_red(s);
            } else { screen.write(s); }
        });
        if i >= screen.visible_choices() as usize {
            return;
        }
        screen.write(NEWLINE);
        i += 1;
    }
}

fn print_match(choice: &str, indices: &[usize], max_width: u16, writer: &mut FnMut(&str, bool)) {
    #[cfg(windows)] const MARGIN: u16 = 1;
    #[cfg(not(windows))] const MARGIN: u16 = 0;
    let max_width = max_width - MARGIN;
    let chars_in_choice = choice.chars().count();
    let mut chars_to_draw = min(chars_in_choice, max_width as usize);
    while UnicodeWidthStr::width(slice_chars(choice, 0, chars_to_draw)) > max_width as usize {
        chars_to_draw -= 1;
    }
    let mut last_idx = 0;
    for &idx in indices {
        let idx = min(idx, chars_to_draw);
        if last_idx >= chars_to_draw {
            return;
        }
        writer(slice_chars(choice, last_idx, idx), false);
        if idx == chars_to_draw { return }
        writer(slice_chars(choice, idx, idx + 1), true);
        last_idx = idx + 1;
    }
    writer(slice_chars(choice, last_idx, chars_to_draw), false);
}

fn read_choices() -> Vec<String> {
    let stdin = stdin();
    let mut lines = Vec::new();

    let mut stdin = stdin.lock();
    loop {
        let mut s = String::new();
        stdin.read_line(&mut s).unwrap();
        if s.is_empty() { break; }
        trim(&mut s);
        lines.push(s);
    }

    lines
}

pub fn trim(s: &mut String) {
    while let Some(x) = s.pop() {
        if x != '\n' && x != '\r' {
            s.push(x);
            return;
        }
    }
}

fn delete_last_word(s: &mut String) {
    let mut deleted_something = false;
    while let Some(x) = s.pop() {
        if x == ' ' {
            if deleted_something {
                s.push(x);
                return;
            }
        } else {
            deleted_something = true;
        }
    }
}

// This is technically a standard library function, but it's plastered with
// stability warnings and therefore only available on the nightly channel.
fn slice_chars(s: &str, begin: usize, end: usize) -> &str {
    assert!(begin <= end);
    let mut count = 0;
    let mut begin_byte = None;
    let mut end_byte = None;

    // This could be even more efficient by not decoding,
    // only finding the char boundaries
    for (idx, _) in s.char_indices() {
        if count == begin { begin_byte = Some(idx); }
        if count == end { end_byte = Some(idx); break; }
        count += 1;
    }
    if begin_byte.is_none() && count == begin { begin_byte = Some(s.len()) }
    if end_byte.is_none() && count == end { end_byte = Some(s.len()) }

    match (begin_byte, end_byte) {
        (None, _) => panic!("slice_chars: `begin` is beyond end of string"),
        (_, None) => panic!("slice_chars: `end` is beyond end of string"),
        (Some(a), Some(b)) => unsafe { s.get_unchecked(a..b) }
    }
}

#[cfg(test)]
mod tests {
    use super::{trim, delete_last_word};

    #[test]
    fn trim_test() {
        fn should_become(before: &str, after: &str) {
            let mut x = before.to_string();
            trim(&mut x);
            assert_eq!(after.to_string(), x);
        }
        should_become("", "");
        should_become("\n", "");
        should_become("\n\n", "");
        should_become("asdf", "asdf");
        should_become("asdf\n", "asdf");
        should_become("asdf\nasdf\n", "asdf\nasdf");
        should_become("asdf\r\n", "asdf");
    }

    #[test]
    fn delete_word_test() {
        fn should_become(before: &str, after: &str) {
            let mut x = before.to_string();
            delete_last_word(&mut x);
            assert_eq!(after.to_string(), x);
        }
        should_become("", "");
        should_become("a", "");
        should_become("asdf", "");
        should_become("asdf asdf asdf", "asdf asdf ");
        should_become("asdf asdf asdf ", "asdf asdf ");
        should_become("asdf asdf asdf  ", "asdf asdf ");
    }
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![feature(scoped)]
#![plugin(quickcheck_macros)]
#![feature(convert)]
#[macro_use] extern crate log;
extern crate env_logger;
extern crate yak_client;
extern crate capnp;
extern crate log4rs;
#[cfg(test)]
extern crate quickcheck;

use std::default::Default;
use std::net::{TcpListener, TcpStream};
use std::thread;
use std::io::{self,Read,Write};
use std::fmt;
use std::sync::{Arc,Mutex};
use std::collections::HashMap;
use std::clone::Clone;
use std::error::Error;

use yak_client::{WireProtocol,Request,Response,Operation,Datum,YakError};

#[macro_use] mod store;
mod mem_store;

#[derive(Debug)]
enum ServerError {
  CapnpError(capnp::Error),
  CapnpNotInSchema(capnp::NotInSchema),
  IoError(std::io::Error),
  DownstreamError(YakError)
}

impl fmt::Display for ServerError {
  fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
    match self {
      &ServerError::CapnpError(ref e) => e.fmt(f),
      &ServerError::CapnpNotInSchema(ref e) => e.fmt(f),
      &ServerError::IoError(ref e) => e.fmt(f),
      &ServerError::DownstreamError(ref e) => e.fmt(f)
    }
  }
}

impl Error for ServerError {
  fn description(&self) -> &str {
    match self {
      &ServerError::CapnpError(ref e) => e.description(),
      &ServerError::CapnpNotInSchema(ref e) => e.description(),
      &ServerError::IoError(ref e) => e.description(),
      &ServerError::DownstreamError(ref e) => e.description()
    }
  }
}

struct DownStream<S: Read+Write> {
  protocol: Arc<Mutex<WireProtocol<S>>>,
}

impl <S: ::std::fmt::Debug + Read + Write> ::std::fmt::Debug for DownStream<S>
 where S: ::std::fmt::Debug + 'static {
    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        match self {
            &DownStream { protocol: ref proto } =>
            fmt.debug_struct("DownStream").field("protocol",
                                                     (proto)).finish(),
        }
    }
}

impl<S> Clone for DownStream<S> where S: Read+Write {
  fn clone(&self) -> DownStream<S> {
    DownStream { protocol: self.protocol.clone() }
  }
}

static LOG_FILE: &'static str = "log.toml";

pub fn main() {
  if let Err(e) = log4rs::init_file(LOG_FILE, Default::default()) {
    panic!("Could not init logger from file {}: {}", LOG_FILE, e);
  }

  match do_run() {
    Ok(()) => info!("Terminated normally"),
    Err(e) => panic!("Failed: {}", e),
  }
}

fn do_run() -> Result<(), ServerError> {
  let mut a = std::env::args().skip(1);
  let local : String = a.next().unwrap();
  let next = match a.next() {
      Some(ref addr) => Some(try!(DownStream::new(addr))),
      None => None
  };

  let listener = TcpListener::bind(local.as_str()).unwrap();
  info!("listening started on {}, ready to accept", local);
  let store = mem_store::MemStore::new();
  for stream in listener.incoming() {
    let next = next.clone();
    let store = store.clone();
    let sock = stream.unwrap();
    let peer = sock.peer_addr().unwrap();
    let _ = try!(thread::Builder::new().name(format!("client-{}", peer)).spawn(move || {
	debug!("Accept stream from {:?}", peer);
        match Session::new(peer, sock, store, next).process_requests() {
          Err(e) => report_errors(&e),
          _ => ()
        }
      }));
  }
  Ok(())
}

fn report_errors(error: &Error) {
  error!("Error: {}", error);
  while let Some(error) = error.cause() {
    error!("\tCaused by: {}", error);
  }
}

impl DownStream<TcpStream> {
  fn new(addr: &str) -> Result<DownStream<TcpStream>, ServerError> {
    debug!("Connect downstream: {:?}", addr);
    let proto = try!(WireProtocol::connect(addr));
    debug!("Connected downstream: {:?}", proto);

    Ok(DownStream { protocol: Arc::new(Mutex::new(proto)) })
  }

}
impl<S: Read+Write> DownStream<S> {
  fn handle(&self, msg: &Request) -> Result<Response, ServerError> {
    let mut wire = self.protocol.lock().unwrap();
    trace!("Downstream: -> {:?}", msg);
    try!(wire.send(msg));
    let resp = try!(wire.read::<Response>());
    trace!("Downstream: <- {:?}", resp);
    resp.map(Ok).unwrap_or(Err(ServerError::DownstreamError(YakError::ProtocolError)))
  }
}

struct Session<Id, S:Read+Write+'static, ST> {
  id: Id,
  protocol: WireProtocol<S>,
  store: ST,
  next: Option<DownStream<S>>
}

impl<Id: fmt::Display, S: Read+Write, ST:store::Store> Session<Id, S, ST> {
  fn new(id: Id, conn: S, store: ST, next: Option<DownStream<S>>) -> Session<Id, S, ST> {
    Session {
    	id: id,
	protocol: WireProtocol::new(conn),
	store: store,
	next: next
    }
  }

  fn process_requests(&mut self) -> Result<(), ServerError> {
    trace!("{}: Waiting for message", self.id);
    while let Some(msg) = try!(self.protocol.read::<Request>()) {
      try!(self.process_one(msg));
    }

    Ok(())
  }

  fn process_one(&mut self, msg: Request) -> Result<(), ServerError> {
    trace!("{}: Handle message: {:?}", self.id, msg);

    let resp = match msg.operation {
      Operation::Truncate => {
        let resp = try!(self.truncate(&msg.space));
        try!(self.send_downstream_or(&msg, resp))
      },
        Operation::Write { ref key, ref value } => {
          let resp = try!(self.write(&msg.space, &key, &value));
          try!(self.send_downstream_or(&msg, resp))
        },
        Operation::Read { key } =>
          try!(self.read(&msg.space, &key)),
      Operation::Subscribe => {
        try!(self.subscribe(&msg.space));
        Response::Okay
      },
    };

    trace!("Response: {:?}", resp);

    try!(self.protocol.send(&resp));
    Ok(())
  }

  fn send_downstream_or(&self, msg: &Request, default: Response) -> Result<Response, ServerError> {
    match self.next {
      Some(ref d) => d.handle(msg),
      None => Ok(default),
    }
  }

  fn truncate(&self, space: &str) -> Result<Response, ServerError> {
    trace!("{}/{:?}: truncate", self.id, space);
    self.store.truncate(space);
    Ok(Response::Okay)
  }

  fn read(&self, space: &str, key: &[u8]) -> Result<Response, ServerError> {
    let val = self.store.read(space, key);
    trace!("{}/{:?}: read:{:?}: -> {:?}", self.id, space, key, val);
    let data = val.iter().map(|c| Datum { key: Vec::new(), content: c.clone() }).collect();
    Ok(Response::OkayData(data))
  }

  fn write(&self, space: &str, key: &[u8], val: &[u8]) -> Result<Response, ServerError> {
    trace!("{}/{:?}: write:{:?} -> {:?}", self.id, space, key, val);
    self.store.write(space, key, val);
    Ok(Response::Okay)
  }
  fn subscribe(&mut self, space: &str) -> Result<(), ServerError> {
    try!(self.protocol.send(&Response::Okay));
    for d in self.store.subscribe(space) {
      try!(self.protocol.send(&Response::Delivery(d)));
    }
    Ok(())
  }
}

impl From<capnp::Error> for ServerError {
  fn from(err: capnp::Error) -> ServerError {
    ServerError::CapnpError(err)
  }
}

impl From<capnp::NotInSchema> for ServerError {
  fn from(err: capnp::NotInSchema) -> ServerError {
    ServerError::CapnpNotInSchema(err)
  }
}

impl From<io::Error> for ServerError {
  fn from(err: io::Error) -> ServerError {
    ServerError::IoError(err)
  }
}

impl From<YakError> for ServerError {
  fn from(err: YakError) -> ServerError {
    ServerError::DownstreamError(err)
  }
}
<commit_msg>Change thread name so that client ip fits in ps output.<commit_after>#![feature(plugin)]
#![feature(scoped)]
#![plugin(quickcheck_macros)]
#![feature(convert)]
#[macro_use] extern crate log;
extern crate env_logger;
extern crate yak_client;
extern crate capnp;
extern crate log4rs;
#[cfg(test)]
extern crate quickcheck;

use std::default::Default;
use std::net::{TcpListener, TcpStream};
use std::thread;
use std::io::{self,Read,Write};
use std::fmt;
use std::sync::{Arc,Mutex};
use std::collections::HashMap;
use std::clone::Clone;
use std::error::Error;

use yak_client::{WireProtocol,Request,Response,Operation,Datum,YakError};

#[macro_use] mod store;
mod mem_store;

#[derive(Debug)]
enum ServerError {
  CapnpError(capnp::Error),
  CapnpNotInSchema(capnp::NotInSchema),
  IoError(std::io::Error),
  DownstreamError(YakError)
}

impl fmt::Display for ServerError {
  fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
    match self {
      &ServerError::CapnpError(ref e) => e.fmt(f),
      &ServerError::CapnpNotInSchema(ref e) => e.fmt(f),
      &ServerError::IoError(ref e) => e.fmt(f),
      &ServerError::DownstreamError(ref e) => e.fmt(f)
    }
  }
}

impl Error for ServerError {
  fn description(&self) -> &str {
    match self {
      &ServerError::CapnpError(ref e) => e.description(),
      &ServerError::CapnpNotInSchema(ref e) => e.description(),
      &ServerError::IoError(ref e) => e.description(),
      &ServerError::DownstreamError(ref e) => e.description()
    }
  }
}

struct DownStream<S: Read+Write> {
  protocol: Arc<Mutex<WireProtocol<S>>>,
}

impl <S: ::std::fmt::Debug + Read + Write> ::std::fmt::Debug for DownStream<S>
 where S: ::std::fmt::Debug + 'static {
    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        match self {
            &DownStream { protocol: ref proto } =>
            fmt.debug_struct("DownStream").field("protocol",
                                                     (proto)).finish(),
        }
    }
}

impl<S> Clone for DownStream<S> where S: Read+Write {
  fn clone(&self) -> DownStream<S> {
    DownStream { protocol: self.protocol.clone() }
  }
}

static LOG_FILE: &'static str = "log.toml";

pub fn main() {
  if let Err(e) = log4rs::init_file(LOG_FILE, Default::default()) {
    panic!("Could not init logger from file {}: {}", LOG_FILE, e);
  }

  match do_run() {
    Ok(()) => info!("Terminated normally"),
    Err(e) => panic!("Failed: {}", e),
  }
}

fn do_run() -> Result<(), ServerError> {
  let mut a = std::env::args().skip(1);
  let local : String = a.next().unwrap();
  let next = match a.next() {
      Some(ref addr) => Some(try!(DownStream::new(addr))),
      None => None
  };

  let listener = TcpListener::bind(local.as_str()).unwrap();
  info!("listening started on {}, ready to accept", local);
  let store = mem_store::MemStore::new();
  for stream in listener.incoming() {
    let next = next.clone();
    let store = store.clone();
    let sock = stream.unwrap();
    let peer = sock.peer_addr().unwrap();
    let _ = try!(thread::Builder::new().name(format!("C{}", peer)).spawn(move || {
	debug!("Accept stream from {:?}", peer);
        match Session::new(peer, sock, store, next).process_requests() {
          Err(e) => report_errors(&e),
          _ => ()
        }
      }));
  }
  Ok(())
}

fn report_errors(error: &Error) {
  error!("Error: {}", error);
  while let Some(error) = error.cause() {
    error!("\tCaused by: {}", error);
  }
}

impl DownStream<TcpStream> {
  fn new(addr: &str) -> Result<DownStream<TcpStream>, ServerError> {
    debug!("Connect downstream: {:?}", addr);
    let proto = try!(WireProtocol::connect(addr));
    debug!("Connected downstream: {:?}", proto);

    Ok(DownStream { protocol: Arc::new(Mutex::new(proto)) })
  }

}
impl<S: Read+Write> DownStream<S> {
  fn handle(&self, msg: &Request) -> Result<Response, ServerError> {
    let mut wire = self.protocol.lock().unwrap();
    trace!("Downstream: -> {:?}", msg);
    try!(wire.send(msg));
    let resp = try!(wire.read::<Response>());
    trace!("Downstream: <- {:?}", resp);
    resp.map(Ok).unwrap_or(Err(ServerError::DownstreamError(YakError::ProtocolError)))
  }
}

struct Session<Id, S:Read+Write+'static, ST> {
  id: Id,
  protocol: WireProtocol<S>,
  store: ST,
  next: Option<DownStream<S>>
}

impl<Id: fmt::Display, S: Read+Write, ST:store::Store> Session<Id, S, ST> {
  fn new(id: Id, conn: S, store: ST, next: Option<DownStream<S>>) -> Session<Id, S, ST> {
    Session {
    	id: id,
	protocol: WireProtocol::new(conn),
	store: store,
	next: next
    }
  }

  fn process_requests(&mut self) -> Result<(), ServerError> {
    trace!("{}: Waiting for message", self.id);
    while let Some(msg) = try!(self.protocol.read::<Request>()) {
      try!(self.process_one(msg));
    }

    Ok(())
  }

  fn process_one(&mut self, msg: Request) -> Result<(), ServerError> {
    trace!("{}: Handle message: {:?}", self.id, msg);

    let resp = match msg.operation {
      Operation::Truncate => {
        let resp = try!(self.truncate(&msg.space));
        try!(self.send_downstream_or(&msg, resp))
      },
        Operation::Write { ref key, ref value } => {
          let resp = try!(self.write(&msg.space, &key, &value));
          try!(self.send_downstream_or(&msg, resp))
        },
        Operation::Read { key } =>
          try!(self.read(&msg.space, &key)),
      Operation::Subscribe => {
        try!(self.subscribe(&msg.space));
        Response::Okay
      },
    };

    trace!("Response: {:?}", resp);

    try!(self.protocol.send(&resp));
    Ok(())
  }

  fn send_downstream_or(&self, msg: &Request, default: Response) -> Result<Response, ServerError> {
    match self.next {
      Some(ref d) => d.handle(msg),
      None => Ok(default),
    }
  }

  fn truncate(&self, space: &str) -> Result<Response, ServerError> {
    trace!("{}/{:?}: truncate", self.id, space);
    self.store.truncate(space);
    Ok(Response::Okay)
  }

  fn read(&self, space: &str, key: &[u8]) -> Result<Response, ServerError> {
    let val = self.store.read(space, key);
    trace!("{}/{:?}: read:{:?}: -> {:?}", self.id, space, key, val);
    let data = val.iter().map(|c| Datum { key: Vec::new(), content: c.clone() }).collect();
    Ok(Response::OkayData(data))
  }

  fn write(&self, space: &str, key: &[u8], val: &[u8]) -> Result<Response, ServerError> {
    trace!("{}/{:?}: write:{:?} -> {:?}", self.id, space, key, val);
    self.store.write(space, key, val);
    Ok(Response::Okay)
  }
  fn subscribe(&mut self, space: &str) -> Result<(), ServerError> {
    try!(self.protocol.send(&Response::Okay));
    for d in self.store.subscribe(space) {
      try!(self.protocol.send(&Response::Delivery(d)));
    }
    Ok(())
  }
}

impl From<capnp::Error> for ServerError {
  fn from(err: capnp::Error) -> ServerError {
    ServerError::CapnpError(err)
  }
}

impl From<capnp::NotInSchema> for ServerError {
  fn from(err: capnp::NotInSchema) -> ServerError {
    ServerError::CapnpNotInSchema(err)
  }
}

impl From<io::Error> for ServerError {
  fn from(err: io::Error) -> ServerError {
    ServerError::IoError(err)
  }
}

impl From<YakError> for ServerError {
  fn from(err: YakError) -> ServerError {
    ServerError::DownstreamError(err)
  }
}
<|endoftext|>


<commit_before>use std::env;

fn multiply (a: f32, b: f32) -> f32 {
    return a * b;
}

fn add (a: f32, b: f32) -> f32 {
    return a + b;
}

fn divide (a: f32, b: f32) -> f32 {
    return a / b;
}

fn subtract (a: f32, b: f32) -> f32 {
    return a - b;
}

fn exponent (a: f32, b: f32) -> f32 {
    return a.powf(b);
}

fn main () {
    let args: Vec<_> = env::args().collect();
    let tokens: Vec<&str> = args[1].split(" ").collect();
    let mut output: Vec<i32> = vec![];
    let mut operator: Vec<_> = vec![];

    for i in 1..tokens.len() {
        let r = tokens[i].parse::<i32>();

        match r {
            Ok(_) => output.push(r.unwrap()),
            Err(_) => {
                if operator.len() > 0 {

                }
                operator.push(&tokens[i])
            }
        }
    }
}
<commit_msg>Change how we do operators<commit_after>use std::env;
use std::collections::HashMap;

struct Operator {
    precedence: i32,
    func: Box<Fn(f32, f32) -> f32>
}

fn main () {
    let args: Vec<_> = env::args().collect();
    let tokens: Vec<&str> = args[1].split(" ").collect();
    let mut output: Vec<i32> = vec![];
    let mut operator: Vec<_> = vec![];

    let multiply = Operator {
        precedence: 3,
        func: Box::new(move |a: f32, b:f32| a * b)
    };

    let divide = Operator {
        precedence: 3,
        func: Box::new(move |a: f32, b:f32| a / b)
    };

    let add = Operator {
        precedence: 4,
        func: Box::new(move |a: f32, b:f32| a + b)
    };

    let subtract = Operator {
        precedence: 4,
        func: Box::new(move |a: f32, b:f32| a - b)
    };

    let mut operators: HashMap<char, Operator> = HashMap::new();

    operators.insert('*', multiply);
    operators.insert('/', divide);
    operators.insert('+', add);
    operators.insert('-', subtract);

    for i in 1..tokens.len() {
        let r = tokens[i].parse::<i32>();

        match r {
            Ok(_) => output.push(r.unwrap()),
            Err(_) => {
                if operator.len() > 0 {

                }
                operator.push(&tokens[i])
            }
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate itertools;

extern crate argparse;
extern crate ansi_term;
extern crate time;

mod space;
mod identity;
mod motion;
mod life;
mod mind;

use std::io;
use std::io::Write;
use std::process;

use argparse::{ArgumentParser, Store};
use time::*;

use space::{Locale, Pinfield};
use identity::{Team, JobDescription, Agent};
use motion::{PONY_MOVEMENT_TABLE, FIGUREHEAD_MOVEMENT_TABLE};
use life::{WorldState, Patch, Commit};
use mind::kickoff;

fn the_end() {
    println!("THE END");
    process::exit(0);
}

fn main() {
    // Does argparse not offer a way to Store an argument (not a
    // hardcoded value) into an Option? Contribution opportunity if so??
    //
    // For now, use 0 like None.
    let mut lookahead_depth: u8 = 0;

    {
        let mut parser = ArgumentParser::new();
        parser.set_description("Leafline: an oppositional strategy game engine");
        parser.refer(&mut lookahead_depth).add_option(
            &["--lookahead"], Store,
            "rank moves using AI minimax lookahead this deep."
        );
        parser.parse_args_or_exit();
    }

    let mut world = WorldState::new();
    let mut premonitions: Vec<Commit>;
    loop {
        match lookahead_depth {
            // XXX can we unify the scored and unscored logic? Useful
            // not only on general DRYness principles, but perhaps also
            // toward supporting human vs. computer playish things rather
            // than just advising every movement
            0 => {
                premonitions = world.lookahead();
                if premonitions.len() == 0 {
                    // XXX distinguish between stalemate and
                    // checkm^H^H^H^H^H^Hultimate endangerment
                    the_end();
                }
                world.display();
                println!("");
                for (index, premonition) in premonitions.iter().enumerate() {
                    println!("{:>2}. {}", index, premonition)
                }
            },
            _ => {
                let start_thinking = time::get_time();
                let forecasts = kickoff(world, lookahead_depth);
                let stop_thinking = time::get_time();
                let thinking_time = stop_thinking - start_thinking;
                world.display();
                println!(
                    "(scoring alternatives {} levels deep took {} ms)",
                    lookahead_depth, thinking_time.num_milliseconds()
                 );
                for (index,
                     &(premonition, score)) in forecasts.iter().enumerate() {
                    println!("{:>2}. {} (score {})", index, premonition, score);
                }
                premonitions = forecasts.iter().map(|t| t.0).collect::<Vec<_>>();
                if premonitions.len() == 0 {
                    the_end();
                }
            }

        }
        loop {
            print!("\nSelect a move>> ");
            io::stdout().flush().ok().expect("couldn't flush stdout");
            let mut input_buffer = String::new();
            io::stdin()
                .read_line(&mut input_buffer)
                .ok().expect("couldn't read input");
            let choice: usize = match input_buffer.trim().parse() {
                Ok(i) => i,
                Err(e) => {
                    println!("Error parsing choice: {:?}. Try again.", e);
                    continue;
                }
            };
            if choice < premonitions.len() {
                world = premonitions[choice].tree;
                break;
            } else {
                println!("{} isn't among the choices. Try again.",
                         choice);
            }
        }
    }
}
<commit_msg>Allowing exiting a game w/ `quit`<commit_after>#[macro_use]
extern crate itertools;

extern crate argparse;
extern crate ansi_term;
extern crate time;

mod space;
mod identity;
mod motion;
mod life;
mod mind;

use std::io;
use std::io::Write;
use std::process;

use argparse::{ArgumentParser, Store};
use time::*;

use space::{Locale, Pinfield};
use identity::{Team, JobDescription, Agent};
use motion::{PONY_MOVEMENT_TABLE, FIGUREHEAD_MOVEMENT_TABLE};
use life::{WorldState, Patch, Commit};
use mind::kickoff;

fn the_end() {
    println!("THE END");
    process::exit(0);
}

fn main() {
    // Does argparse not offer a way to Store an argument (not a
    // hardcoded value) into an Option? Contribution opportunity if so??
    //
    // For now, use 0 like None.
    let mut lookahead_depth: u8 = 0;

    {
        let mut parser = ArgumentParser::new();
        parser.set_description("Leafline: an oppositional strategy game engine");
        parser.refer(&mut lookahead_depth).add_option(
            &["--lookahead"], Store,
            "rank moves using AI minimax lookahead this deep."
        );
        parser.parse_args_or_exit();
    }

    let mut world = WorldState::new();
    let mut premonitions: Vec<Commit>;
    loop {
        match lookahead_depth {
            // XXX can we unify the scored and unscored logic? Useful
            // not only on general DRYness principles, but perhaps also
            // toward supporting human vs. computer playish things rather
            // than just advising every movement
            0 => {
                premonitions = world.lookahead();
                if premonitions.len() == 0 {
                    // XXX distinguish between stalemate and
                    // checkm^H^H^H^H^H^Hultimate endangerment
                    the_end();
                }
                world.display();
                println!("");
                for (index, premonition) in premonitions.iter().enumerate() {
                    println!("{:>2}. {}", index, premonition)
                }
            },
            _ => {
                let start_thinking = time::get_time();
                let forecasts = kickoff(world, lookahead_depth);
                let stop_thinking = time::get_time();
                let thinking_time = stop_thinking - start_thinking;
                world.display();
                println!(
                    "(scoring alternatives {} levels deep took {} ms)",
                    lookahead_depth, thinking_time.num_milliseconds()
                 );
                for (index,
                     &(premonition, score)) in forecasts.iter().enumerate() {
                    println!("{:>2}. {} (score {})", index, premonition, score);
                }
                premonitions = forecasts.iter().map(|t| t.0).collect::<Vec<_>>();
                if premonitions.len() == 0 {
                    the_end();
                }
            }

        }
        loop {
            print!("\nSelect a move>> ");
            io::stdout().flush().ok().expect("couldn't flush stdout");
            let mut input_buffer = String::new();
            io::stdin()
                .read_line(&mut input_buffer)
                .ok().expect("couldn't read input");

            if input_buffer.trim() == "quit" {
                the_end();
            }

            let choice: usize = match input_buffer.trim().parse() {
                Ok(i) => i,
                Err(e) => {
                    println!("Error parsing choice: {:?}. Try again.", e);
                    continue;
                }
            };
            if choice < premonitions.len() {
                world = premonitions[choice].tree;
                break;
            } else {
                println!("{} isn't among the choices. Try again.",
                         choice);
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate rusqlite;
extern crate time;
extern crate rand;
extern crate regex;

use time::Timespec;
use rusqlite::Connection;
use std::io;
use std::path::Path;
use std::env;
use regex::Regex;

#[derive(Debug)]
struct Movie {
    id: i32,
    name: String,
    time_created: Timespec,
    opinion: String,
    rating: i32
}

impl Movie {
    fn new(id: i32, name: String, time_created: Timespec, opinion: String, rating: i32) -> Movie {
        Movie {
            id: id,
            name: name,
            time_created: time_created,
            opinion: opinion,
            rating: rating,
        }
    }

    fn get_name(self) -> String {
        self.name
    }

    fn get_opinion(self) -> String {
        self.opinion
    }

    fn get_id(self) -> i32 {
        self.id
    }

    fn get_rating(self) -> i32 {
        self.rating
    }

    fn get_time(self) -> Timespec {
        self.time_created
    }
}

fn main() {
    let conn = Connection::open(Path::new(".movies.db")).unwrap();

    conn.execute("CREATE TABLE IF NOT EXISTS movies (
        id INTEGER UNIQUE NOT NULL,
        name TEXT NOT NULL,
        time_created TEXT NOT NULL,
        opinion TEXT NOT NULL,
        rating INTEGER)", &[]).unwrap();
    let args: Vec<String> = env::args().collect();
    let length = args.len();

    if length == 1 {
        println!("for help, use \"mymdb help\"");
    }
    else if length == 2 {
        for i in &args {
            if i == "help" { print_help(); }
            else if i == "add" {
                let newMovie = new_movie();
                conn.execute("INSERT INTO movies VALUES ($1, $2, $3, $4, $5)",
                    &[&newMovie.id, &newMovie.name, &newMovie.time_created,
                    &newMovie.opinion, &newMovie.rating]).unwrap();
                println!("Your movie has been added. ID# {}", &newMovie.id);
            }
            else if i == "remove" {
                println!("ID of movie to be removed: (number)");
                let id: i32 = number_input();

                let mut stmt = conn.prepare("SELECT * FROM movies WHERE id=$1").unwrap();
                let mut movie_iter = stmt.query_map(&[&id,], |row| {
                    Movie {
                        id: row.get(0),
                        name: row.get(1),
                        time_created: row.get(2),
                        opinion: row.get(3),
                        rating: row.get(4)
                    }
                }).unwrap();

                let mut q = Movie::new(0, String::new(), time::get_time(), String::new(), 0);
                for i in movie_iter {
                    q = i.unwrap();
                }

                if q.name.is_empty() {
                    println!("Cannot find movie with ID of {}", id);
                    return
                }

                println!("Are you sure you want to remove {}?", q.name.trim());

                let resp1 = get_input();
                let resp2 = resp1.to_lowercase();
                let resp = resp2.trim();

                if resp == String::from("yes") {
                    conn.execute("DELETE FROM movies WHERE id=$1", &[&id,]).unwrap();
                    println!("{} has been removed from the database.", q.name.trim());
                } else if resp == String::from("y") {
                    conn.execute("DELETE FROM movies WHERE id=$1", &[&id,]).unwrap();
                    println!("{} has been removed from the database.", q.name.trim());
                } else {
                    println!("Movie will not be removed.");
                }
            }
            else if i == "show" {
                let mut stmt = conn.prepare("SELECT * FROM movies").unwrap();
                let mut movie_iter = stmt.query_map(&[], |row| {
                    Movie {
                        id: row.get(0),
                        name: row.get(1),
                        time_created: row.get(2),
                        opinion: row.get(3),
                        rating: row.get(4)
                    }
                }).unwrap();

                let mut count = 0;
                let mut movies: Vec<Movie> = vec![];
                for movie in movie_iter {
                    movies.push(movie.unwrap());
                    count = count + 1;
                }

                println!("Found {} movie(s)", count);

                for z in movies {
                    println!("Name:    {}\nOpinion: {}\nRating:  {}\nID:      {}\nTime:    {}\n",
                             z.name.trim(),
                             z.opinion.trim(),
                             z.rating,
                             z.id,
                             time(z.time_created));
                }
            }
            else {
                // TODO: make this not ridiculous
                let re = Regex::new(r"mymdb").unwrap();
                if !re.is_match(&i) {
                    println!("Not an option: {}", i);
                } else {
                    continue;
                }
            }
        }
    }
    else {
        let mut arg3: &String = &String::from("");
        let mut arg4: &String = &String::from("");
        let mut arg5: i32 = 0;
        if length >= 3 {
            arg3 = &args[2];
        }
        if length == 5 {
            arg4 = &args[3];
            arg5 = args[4].trim().parse().expect("3rd arg must be a number");
        }
        for i in &args {
            if i == "-a" {
                let id = rand::random::<i32>().abs() / 1000;
                conn.execute("INSERT INTO movies VALUES ($1, $2, $3, $4, $5)",
                    &[&id, arg3, &(time::get_time()),
                    arg4, &arg5]).unwrap();
                println!("Your movie has been added. ID# {}", id);
            }
            else if i == "-r" {
                let id: i32 = arg3.trim().parse().expect("arg must be a number");

                let mut stmt = conn.prepare("SELECT * FROM movies WHERE id=$1").unwrap();
                let mut movie_iter = stmt.query_map(&[&id,], |row| {
                    Movie {
                        id: row.get(0),
                        name: row.get(1),
                        time_created: row.get(2),
                        opinion: row.get(3),
                        rating: row.get(4)
                    }
                }).unwrap();

                let mut q = Movie::new(0, String::new(), time::get_time(), String::new(), 0);
                for i in movie_iter {
                    q = i.unwrap();
                }

                if q.name.is_empty() {
                    println!("Cannot find movie with ID of {}", id);
                    return
                }

                conn.execute("DELETE FROM movies WHERE id=$1", &[&id,]).unwrap();
                println!("{} has been removed from the database.", q.name.trim());
            }
        }
    }
}

fn new_movie() -> Movie {
    println!("Name of movie:");
    let name: String = get_input();

    println!("Thoughts:");
    let opinion: String = get_input();

    println!("Rating: (number)");
    let rating: i32 = number_input();

    Movie::new(rand::random::<i32>().abs() / 1000, name,
        time::get_time(), opinion, rating)
}

fn time(t: Timespec) -> String {
    let real_time = time::at(t);
    String::from(format!("{}-{}-{} {}:{}", (real_time.tm_year + 1900), real_time.tm_mon,
                 real_time.tm_mday, real_time.tm_hour, real_time.tm_min))
}

fn print_help() {
    println!("mymdb - personal movie database");
    println!("usage:");
    println!("mymdb <command> [options]");
    println!("commands:");
    println!("\tshow - lists movies in database");
    println!("\tadd - adds movie to database (interactively)");
    println!("\tremove - removes movie from database (interactively)");
    println!("options:");
    println!("\t-r <movie ID> - removes movie from database");
    println!("\t-a <movie name> <opinion> <rating>");
    println!("mymdb creates a movie database that the program is run in.");
    println!("It looks for a sqlite file called .movies.db, and if it does");
    println!("not exist, it is created automatically.");
}

fn number_input() -> i32 {
    let n = match get_input().trim().parse::<i32>() {
        Ok(n) => n,
        Err(e) => { println!("Not a number"); 0 },
    };

    n
}

fn get_input() -> String {
    let mut i = String::new();
    let handle = io::stdin();

    match handle.read_line(&mut i) {
        Ok(n) => {},
        Err(e) => println!("What's your problem?")
    }

    i
}
<commit_msg>add copyright notice to source file<commit_after>/* main.rs - Main source file for mymdb
 * (c) 2016 Zack Hixon under MIT license.
 * See LICENSE.txt for more details. */

extern crate rusqlite;
extern crate time;
extern crate rand;
extern crate regex;

use time::Timespec;
use rusqlite::Connection;
use std::io;
use std::path::Path;
use std::env;
use regex::Regex;

#[derive(Debug)]
struct Movie {
    id: i32,
    name: String,
    time_created: Timespec,
    opinion: String,
    rating: i32
}

impl Movie {
    fn new(id: i32, name: String, time_created: Timespec, opinion: String, rating: i32) -> Movie {
        Movie {
            id: id,
            name: name,
            time_created: time_created,
            opinion: opinion,
            rating: rating,
        }
    }

    fn get_name(self) -> String {
        self.name
    }

    fn get_opinion(self) -> String {
        self.opinion
    }

    fn get_id(self) -> i32 {
        self.id
    }

    fn get_rating(self) -> i32 {
        self.rating
    }

    fn get_time(self) -> Timespec {
        self.time_created
    }
}

fn main() {
    let conn = Connection::open(Path::new(".movies.db")).unwrap();

    conn.execute("CREATE TABLE IF NOT EXISTS movies (
        id INTEGER UNIQUE NOT NULL,
        name TEXT NOT NULL,
        time_created TEXT NOT NULL,
        opinion TEXT NOT NULL,
        rating INTEGER)", &[]).unwrap();
    let args: Vec<String> = env::args().collect();
    let length = args.len();

    if length == 1 {
        println!("for help, use \"mymdb help\"");
    }
    else if length == 2 {
        for i in &args {
            if i == "help" { print_help(); }
            else if i == "add" {
                let newMovie = new_movie();
                conn.execute("INSERT INTO movies VALUES ($1, $2, $3, $4, $5)",
                    &[&newMovie.id, &newMovie.name, &newMovie.time_created,
                    &newMovie.opinion, &newMovie.rating]).unwrap();
                println!("Your movie has been added. ID# {}", &newMovie.id);
            }
            else if i == "remove" {
                println!("ID of movie to be removed: (number)");
                let id: i32 = number_input();

                let mut stmt = conn.prepare("SELECT * FROM movies WHERE id=$1").unwrap();
                let mut movie_iter = stmt.query_map(&[&id,], |row| {
                    Movie {
                        id: row.get(0),
                        name: row.get(1),
                        time_created: row.get(2),
                        opinion: row.get(3),
                        rating: row.get(4)
                    }
                }).unwrap();

                let mut q = Movie::new(0, String::new(), time::get_time(), String::new(), 0);
                for i in movie_iter {
                    q = i.unwrap();
                }

                if q.name.is_empty() {
                    println!("Cannot find movie with ID of {}", id);
                    return
                }

                println!("Are you sure you want to remove {}?", q.name.trim());

                let resp1 = get_input();
                let resp2 = resp1.to_lowercase();
                let resp = resp2.trim();

                if resp == String::from("yes") {
                    conn.execute("DELETE FROM movies WHERE id=$1", &[&id,]).unwrap();
                    println!("{} has been removed from the database.", q.name.trim());
                } else if resp == String::from("y") {
                    conn.execute("DELETE FROM movies WHERE id=$1", &[&id,]).unwrap();
                    println!("{} has been removed from the database.", q.name.trim());
                } else {
                    println!("Movie will not be removed.");
                }
            }
            else if i == "show" {
                let mut stmt = conn.prepare("SELECT * FROM movies").unwrap();
                let mut movie_iter = stmt.query_map(&[], |row| {
                    Movie {
                        id: row.get(0),
                        name: row.get(1),
                        time_created: row.get(2),
                        opinion: row.get(3),
                        rating: row.get(4)
                    }
                }).unwrap();

                let mut count = 0;
                let mut movies: Vec<Movie> = vec![];
                for movie in movie_iter {
                    movies.push(movie.unwrap());
                    count = count + 1;
                }

                println!("Found {} movie(s)", count);

                for z in movies {
                    println!("Name:    {}\nOpinion: {}\nRating:  {}\nID:      {}\nTime:    {}\n",
                             z.name.trim(),
                             z.opinion.trim(),
                             z.rating,
                             z.id,
                             time(z.time_created));
                }
            }
            else {
                // TODO: make this not ridiculous
                let re = Regex::new(r"mymdb").unwrap();
                if !re.is_match(&i) {
                    println!("Not an option: {}", i);
                } else {
                    continue;
                }
            }
        }
    }
    else {
        let mut arg3: &String = &String::from("");
        let mut arg4: &String = &String::from("");
        let mut arg5: i32 = 0;
        if length >= 3 {
            arg3 = &args[2];
        }
        if length == 5 {
            arg4 = &args[3];
            arg5 = args[4].trim().parse().expect("3rd arg must be a number");
        }
        for i in &args {
            if i == "-a" {
                let id = rand::random::<i32>().abs() / 1000;
                conn.execute("INSERT INTO movies VALUES ($1, $2, $3, $4, $5)",
                    &[&id, arg3, &(time::get_time()),
                    arg4, &arg5]).unwrap();
                println!("Your movie has been added. ID# {}", id);
            }
            else if i == "-r" {
                let id: i32 = arg3.trim().parse().expect("arg must be a number");

                let mut stmt = conn.prepare("SELECT * FROM movies WHERE id=$1").unwrap();
                let mut movie_iter = stmt.query_map(&[&id,], |row| {
                    Movie {
                        id: row.get(0),
                        name: row.get(1),
                        time_created: row.get(2),
                        opinion: row.get(3),
                        rating: row.get(4)
                    }
                }).unwrap();

                let mut q = Movie::new(0, String::new(), time::get_time(), String::new(), 0);
                for i in movie_iter {
                    q = i.unwrap();
                }

                if q.name.is_empty() {
                    println!("Cannot find movie with ID of {}", id);
                    return
                }

                conn.execute("DELETE FROM movies WHERE id=$1", &[&id,]).unwrap();
                println!("{} has been removed from the database.", q.name.trim());
            }
        }
    }
}

fn new_movie() -> Movie {
    println!("Name of movie:");
    let name: String = get_input();

    println!("Thoughts:");
    let opinion: String = get_input();

    println!("Rating: (number)");
    let rating: i32 = number_input();

    Movie::new(rand::random::<i32>().abs() / 1000, name,
        time::get_time(), opinion, rating)
}

fn time(t: Timespec) -> String {
    let real_time = time::at(t);
    String::from(format!("{}-{}-{} {}:{}", (real_time.tm_year + 1900), real_time.tm_mon,
                 real_time.tm_mday, real_time.tm_hour, real_time.tm_min))
}

fn print_help() {
    println!("mymdb - personal movie database");
    println!("usage:");
    println!("mymdb <command> [options]");
    println!("commands:");
    println!("\tshow - lists movies in database");
    println!("\tadd - adds movie to database (interactively)");
    println!("\tremove - removes movie from database (interactively)");
    println!("options:");
    println!("\t-r <movie ID> - removes movie from database");
    println!("\t-a <movie name> <opinion> <rating>");
    println!("mymdb creates a movie database that the program is run in.");
    println!("It looks for a sqlite file called .movies.db, and if it does");
    println!("not exist, it is created automatically.");
}

fn number_input() -> i32 {
    let n = match get_input().trim().parse::<i32>() {
        Ok(n) => n,
        Err(e) => { println!("Not a number"); 0 },
    };

    n
}

fn get_input() -> String {
    let mut i = String::new();
    let handle = io::stdin();

    match handle.read_line(&mut i) {
        Ok(n) => {},
        Err(e) => println!("What's your problem?")
    }

    i
}
<|endoftext|>


<commit_before>// Copyright (C) 2016 Mark Lee

// 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 env_logger;
extern crate futures;
extern crate hyper;
#[macro_use]
extern crate log;
extern crate redis;
extern crate regex;
extern crate reqwest;
extern crate rquery;
extern crate semver;
extern crate serde;
extern crate serde_json;

use hyper::{Get, StatusCode};
use hyper::header::{Accept, ContentType};
use hyper::server::{Http, Request, Response, Service};
use redis::{Commands, RedisError, RedisResult};
use regex::Regex;
use rquery::Document;
use semver::Version;
use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io;
use std::io::Read;

const DEFAULT_SERVER_PORT: u32 = 9000;
const DEFAULT_MIN_BUNDLER_VERSION: &'static str = "1.12.0";
const RUBY_LANGPACK_RELEASES_URL: &'static str = "https://github.\
                                                  com/heroku/heroku-buildpack-ruby/releases.atom";

fn download_url(url: &str) -> io::Result<String> {
    let mut resp = reqwest::get(url).expect("Could not send HTTP request");
    let mut body = String::new();
    match resp.read_to_string(&mut body) {
        Err(error) => Err(error),
        _ => Ok(body),
    }
}

fn download_latest_buildpack_release() -> String {
    let xml = download_url(RUBY_LANGPACK_RELEASES_URL).expect("Could not download Atom releases!");
    let atom_doc = Document::new_from_xml_string(&xml[..]).expect("Could not parse Atom releases!");
    let latest_tag = atom_doc.select("entry title").expect(
        "Could not find latest buildpack tag!",
    );
    latest_tag.text().clone()
}

fn redis_cache_value(redis: &redis::Connection, key: &str, value: &str) -> String {
    let set_result: RedisResult<()> = redis.set_ex(key, value, 3600);
    if set_result.is_err() {
        warn!("Cannot set {} in Redis, ignoring", key);
    }
    value.to_owned()
}

fn redis_cache_hash_value(redis: &redis::Connection, hash_name: &str, key: &str, value: &str) {
    let set_result: RedisResult<()> = redis.hset_nx(hash_name, key, value);
    if set_result.is_err() {
        warn!("Cannot set {} in Redis, ignoring", key);
    }
}

fn latest_buildpack_release(redis_result: &RedisResult<redis::Connection>) -> String {
    if let Ok(ref redis) = *redis_result {
        if let Ok(buildpack_release) = redis.get("latest_buildpack_release") {
            buildpack_release
        } else {
            let buildpack_release = download_latest_buildpack_release();
            redis_cache_value(redis, "latest_buildpack_release", &buildpack_release[..])
        }
    } else {
        download_latest_buildpack_release()
    }
}

fn cached_version_from_buildpack_release(
    buildpack_release: &str,
    redis_result: &RedisResult<redis::Connection>,
) -> Option<String> {
    if let Ok(ref redis) = *redis_result {
        if let Ok(version) = redis.hget("bundler_version", buildpack_release) {
            Some(version)
        } else {
            None
        }
    } else {
        None
    }
}

fn bundler_version_from_ruby_buildpack(
    redis_result: &RedisResult<redis::Connection>,
) -> Option<String> {
    let buildpack_release = latest_buildpack_release(redis_result);
    if let Some(cached_version) =
        cached_version_from_buildpack_release(&buildpack_release[..], redis_result)
    {
        return Some(cached_version);
    }
    let ruby_langpack_url = format!(
        "https://raw.githubusercontent.com/\
                                     heroku/heroku-buildpack-ruby/{}/lib/language_pack/\
                                     ruby.rb",
        buildpack_release
    );
    let ruby_file = &download_url(&ruby_langpack_url[..]).expect("Could not download ruby.rb!")[..];
    let regex = Regex::new(r#"BUNDLER_VERSION += "(.+?)""#).expect("Invalid regular expression!");
    if regex.is_match(ruby_file) {
        let captures = regex.captures(ruby_file).expect("Could not match?!");
        let version_match = captures.get(1).expect("Capture not found?!");
        let version = version_match.as_str();
        if let Ok(ref redis) = *redis_result {
            redis_cache_hash_value(redis, "bundler_version", &buildpack_release[..], version);
        }
        Some(version.to_owned())
    } else {
        None
    }
}

fn is_bundler_upgraded(redis_result: &RedisResult<redis::Connection>) -> bool {
    let bundler_version_result = bundler_version_from_ruby_buildpack(redis_result);
    if let Some(buildpack_bundler_version_str) = bundler_version_result {
        let min_version =
            Version::parse(&min_bundler_version()[..]).expect("Could not parse min version!");
        let new_version = Version::parse(&buildpack_bundler_version_str[..]).expect(
            "Could not parse new version!",
        );
        min_version < new_version
    } else {
        false
    }
}

fn determine_content_type(headers: &hyper::Headers) -> ContentType {
    use std::ops::Deref;
    if headers.has::<Accept>() {
        let accept = headers
            .get::<Accept>()
            .expect("Accept header not found?!")
            .deref();
        let use_json = accept.into_iter().any(
            |qitem| qitem.item == "application/json",
        );

        if use_json {
            ContentType::json()
        } else {
            ContentType::html()
        }
    } else {
        ContentType::html()
    }
}

fn result_to_json(result: bool) -> String {
    let mut map = HashMap::new();
    map.insert("result".to_owned(), result);
    serde_json::to_string(&map).expect("Could not serialize result!")
}

fn result_to_html(result: bool) -> String {
    let result_str = if result {
        r#"
Yes
"#
    } else {
        r#"
No
"#
    };
    match File::open("index.html") {
        Ok(mut html_file) => {
            let mut html = String::new();
            html_file.read_to_string(&mut html).expect(
                "Could not read HTML file!",
            );
            html.replace("{{ is_bundler_upgraded }}", result_str)
                .replace("{{ MIN_BUNDLER_VERSION }}", &min_bundler_version()[..])
        }
        Err(error) => format!("HTML NOT FOUND: {}", error),
    }
}

fn min_bundler_version() -> String {
    match env::var("MIN_BUNDLER_VERSION") {
        Ok(version) => version,
        _ => String::from(DEFAULT_MIN_BUNDLER_VERSION),
    }
}

fn server_port() -> String {
    match env::var("PORT") {
        Ok(port) => port,
        _ => format!("{}", DEFAULT_SERVER_PORT),
    }
}

fn connect_to_redis() -> RedisResult<redis::Connection> {
    if let Ok(redis_url) = env::var("REDIS_URL") {
        let client = redis::Client::open(&redis_url[..]).expect("Cannot connect to Redis");
        client.get_connection()
    } else {
        Err(RedisError::from(
            io::Error::new(io::ErrorKind::Other, "REDIS_URL not found"),
        ))
    }
}

struct HBBUYServer;

impl Service for HBBUYServer {
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    type Future = futures::future::FutureResult<Self::Response, Self::Error>;

    fn call(&self, req: Request) -> Self::Future {
        let response = match (req.uri().path(), req.method()) {
            ("/", &Get) => {
                let redis = connect_to_redis();
                let result = is_bundler_upgraded(&redis);
                let content_type = determine_content_type(req.headers());
                let data = match &format!("{}", content_type)[..] {
                    "application/json; charset=utf-8" => result_to_json(result),
                    _ => result_to_html(result),
                };

                Response::new().with_header(content_type).with_body(data)
            }
            (_, &Get) => Response::new().with_status(StatusCode::NotFound),
            (_, _) => Response::new().with_status(StatusCode::MethodNotAllowed),
        };

        futures::future::ok(response)
    }
}

fn main() {
    env_logger::init().expect("Could not initialize env_logger!");
    let addr = format!("0.0.0.0:{}", server_port()).parse().expect(
        "Could not parse address/port",
    );
    let server = Http::new().bind(&addr, || Ok(HBBUYServer)).expect(
        "Could not create server!",
    );
    server.run().expect(
        "Could not set up HTTP request handler!",
    );
}
<commit_msg>[Rust] Bump copyright year<commit_after>// Copyright (C) 2016, 2017 Mark Lee

// 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 env_logger;
extern crate futures;
extern crate hyper;
#[macro_use]
extern crate log;
extern crate redis;
extern crate regex;
extern crate reqwest;
extern crate rquery;
extern crate semver;
extern crate serde;
extern crate serde_json;

use hyper::{Get, StatusCode};
use hyper::header::{Accept, ContentType};
use hyper::server::{Http, Request, Response, Service};
use redis::{Commands, RedisError, RedisResult};
use regex::Regex;
use rquery::Document;
use semver::Version;
use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io;
use std::io::Read;

const DEFAULT_SERVER_PORT: u32 = 9000;
const DEFAULT_MIN_BUNDLER_VERSION: &'static str = "1.12.0";
const RUBY_LANGPACK_RELEASES_URL: &'static str = "https://github.\
                                                  com/heroku/heroku-buildpack-ruby/releases.atom";

fn download_url(url: &str) -> io::Result<String> {
    let mut resp = reqwest::get(url).expect("Could not send HTTP request");
    let mut body = String::new();
    match resp.read_to_string(&mut body) {
        Err(error) => Err(error),
        _ => Ok(body),
    }
}

fn download_latest_buildpack_release() -> String {
    let xml = download_url(RUBY_LANGPACK_RELEASES_URL).expect("Could not download Atom releases!");
    let atom_doc = Document::new_from_xml_string(&xml[..]).expect("Could not parse Atom releases!");
    let latest_tag = atom_doc.select("entry title").expect(
        "Could not find latest buildpack tag!",
    );
    latest_tag.text().clone()
}

fn redis_cache_value(redis: &redis::Connection, key: &str, value: &str) -> String {
    let set_result: RedisResult<()> = redis.set_ex(key, value, 3600);
    if set_result.is_err() {
        warn!("Cannot set {} in Redis, ignoring", key);
    }
    value.to_owned()
}

fn redis_cache_hash_value(redis: &redis::Connection, hash_name: &str, key: &str, value: &str) {
    let set_result: RedisResult<()> = redis.hset_nx(hash_name, key, value);
    if set_result.is_err() {
        warn!("Cannot set {} in Redis, ignoring", key);
    }
}

fn latest_buildpack_release(redis_result: &RedisResult<redis::Connection>) -> String {
    if let Ok(ref redis) = *redis_result {
        if let Ok(buildpack_release) = redis.get("latest_buildpack_release") {
            buildpack_release
        } else {
            let buildpack_release = download_latest_buildpack_release();
            redis_cache_value(redis, "latest_buildpack_release", &buildpack_release[..])
        }
    } else {
        download_latest_buildpack_release()
    }
}

fn cached_version_from_buildpack_release(
    buildpack_release: &str,
    redis_result: &RedisResult<redis::Connection>,
) -> Option<String> {
    if let Ok(ref redis) = *redis_result {
        if let Ok(version) = redis.hget("bundler_version", buildpack_release) {
            Some(version)
        } else {
            None
        }
    } else {
        None
    }
}

fn bundler_version_from_ruby_buildpack(
    redis_result: &RedisResult<redis::Connection>,
) -> Option<String> {
    let buildpack_release = latest_buildpack_release(redis_result);
    if let Some(cached_version) =
        cached_version_from_buildpack_release(&buildpack_release[..], redis_result)
    {
        return Some(cached_version);
    }
    let ruby_langpack_url = format!(
        "https://raw.githubusercontent.com/\
                                     heroku/heroku-buildpack-ruby/{}/lib/language_pack/\
                                     ruby.rb",
        buildpack_release
    );
    let ruby_file = &download_url(&ruby_langpack_url[..]).expect("Could not download ruby.rb!")[..];
    let regex = Regex::new(r#"BUNDLER_VERSION += "(.+?)""#).expect("Invalid regular expression!");
    if regex.is_match(ruby_file) {
        let captures = regex.captures(ruby_file).expect("Could not match?!");
        let version_match = captures.get(1).expect("Capture not found?!");
        let version = version_match.as_str();
        if let Ok(ref redis) = *redis_result {
            redis_cache_hash_value(redis, "bundler_version", &buildpack_release[..], version);
        }
        Some(version.to_owned())
    } else {
        None
    }
}

fn is_bundler_upgraded(redis_result: &RedisResult<redis::Connection>) -> bool {
    let bundler_version_result = bundler_version_from_ruby_buildpack(redis_result);
    if let Some(buildpack_bundler_version_str) = bundler_version_result {
        let min_version =
            Version::parse(&min_bundler_version()[..]).expect("Could not parse min version!");
        let new_version = Version::parse(&buildpack_bundler_version_str[..]).expect(
            "Could not parse new version!",
        );
        min_version < new_version
    } else {
        false
    }
}

fn determine_content_type(headers: &hyper::Headers) -> ContentType {
    use std::ops::Deref;
    if headers.has::<Accept>() {
        let accept = headers.get::<Accept>().expect("Accept header not found?!").deref();
        let use_json = accept.into_iter().any(|qitem| {
            qitem.item == "application/json"
        });

        if use_json {
            ContentType::json()
        } else {
            ContentType::html()
        }
    } else {
        ContentType::html()
    }
}

fn result_to_json(result: bool) -> String {
    let mut map = HashMap::new();
    map.insert("result".to_owned(), result);
    serde_json::to_string(&map).expect("Could not serialize result!")
}

fn result_to_html(result: bool) -> String {
    let result_str = if result {
        r#"
Yes
"#
    } else {
        r#"
No
"#
    };
    match File::open("index.html") {
        Ok(mut html_file) => {
            let mut html = String::new();
            html_file.read_to_string(&mut html).expect(
                "Could not read HTML file!",
            );
            html.replace("{{ is_bundler_upgraded }}", result_str)
                .replace("{{ MIN_BUNDLER_VERSION }}", &min_bundler_version()[..])
        }
        Err(error) => format!("HTML NOT FOUND: {}", error),
    }
}

fn min_bundler_version() -> String {
    match env::var("MIN_BUNDLER_VERSION") {
        Ok(version) => version,
        _ => String::from(DEFAULT_MIN_BUNDLER_VERSION),
    }
}

fn server_port() -> String {
    match env::var("PORT") {
        Ok(port) => port,
        _ => format!("{}", DEFAULT_SERVER_PORT),
    }
}

fn connect_to_redis() -> RedisResult<redis::Connection> {
    if let Ok(redis_url) = env::var("REDIS_URL") {
        let client = redis::Client::open(&redis_url[..]).expect("Cannot connect to Redis");
        client.get_connection()
    } else {
        Err(RedisError::from(
            io::Error::new(io::ErrorKind::Other, "REDIS_URL not found"),
        ))
    }
}

struct HBBUYServer;

impl Service for HBBUYServer {
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    type Future = futures::future::FutureResult<Self::Response, Self::Error>;

    fn call(&self, req: Request) -> Self::Future {
        let response = match (req.uri().path(), req.method()) {
            ("/", &Get) => {
                let redis = connect_to_redis();
                let result = is_bundler_upgraded(&redis);
                let content_type = determine_content_type(req.headers());
                let data = match &format!("{}", content_type)[..] {
                    "application/json; charset=utf-8" => result_to_json(result),
                    _ => result_to_html(result),
                };

                Response::new()
                    .with_header(content_type)
                    .with_body(data)
            },
            (_, &Get) => Response::new().with_status(StatusCode::NotFound),
            (_, _) => Response::new().with_status(StatusCode::MethodNotAllowed),
        };

        futures::future::ok(response)
    }
}

fn main() {
    env_logger::init().expect("Could not initialize env_logger!");
    let addr = format!("0.0.0.0:{}", server_port()).parse().expect("Could not parse address/port");
    let server = Http::new().bind(&addr, || Ok(HBBUYServer))
        .expect("Could not create server!");
    server.run().expect(
        "Could not set up HTTP request handler!",
    );
}
<|endoftext|>


<commit_before>fn main() {
    println!("Hello, world!");
}
<commit_msg>Add initial ricing functionality<commit_after>use std::error::Error;
use std::io::prelude::*;
use std::fs::File;
use std::path::Path;
use std::env;
use std::string::String;

fn main() {
    let args: Vec<String> = env::args().collect();
    let path = Path::new(&args[1]);
    let display = path.display();
    let mut file = match File::create(&path) {
        Err(why) => panic!("couldn't create {}: {}",
                           display,
                           Error::description(&why)),
        Ok(file) => file,
    };
    let _ = file.write_all(b"# generated by mpv-rice\n");
    let _ = file.write_all(b"vo=opengl-hq\n");
}
<|endoftext|>