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

use clap::{Arg, App, AppSettings};

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

use gif::SetParameter;

// (frame_no, (pixel_index, num_changes))
type Frames = Vec<(u32, Vec<(u32, u16)>)>;

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_magnitude(&self, magnitude: Option<u32>) -> u8 {
        match magnitude {
            None => 0,
            Some(magnitude) => {
                if magnitude > 255 {
                    1
                } else {
                    (255 - magnitude) as u8
                }
            },
            //Some(age) => match self.steps.iter().position(|&(x, _)| x == age) {
            //    None => 0,
            //    Some(i) => (i+1) as u8,
            //}
        }
    }
}

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

    let mut results: HashMap<u32, HashMap<u32, u16>> = 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;

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

    let mut num_nodes: u64 = 0;
    for node in node_reader {
        if let (Some(lat), Some(lon)) = (node.lat, node.lon) {

            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);
            if let Some(pixel_idx) = pixel_func(lat, lon) {
                let curr_val = results.entry(frame_no).or_insert(HashMap::new()).entry(pixel_idx).or_insert(0);
                if *curr_val < std::u16::MAX {
                    *curr_val += 1;
                }
            }

            num_nodes += 1;
            if num_nodes % 50_000_000 == 0 {
                println!("Done {} million points", num_nodes/1_000_000);
            }
        }
    }
    println!("Done {} points", 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, height: u32, sec_per_frame: u32, bbox: &[f32; 4]) {
    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;

    let mut file = BufWriter::new(fs::File::create(&filename).unwrap());

    writeln!(file, "metadata version {}", env!("CARGO_PKG_VERSION")).expect("Couldn't write metadata");
    writeln!(file, "metadata height {}", height).expect("Couldn't write metadata");
    writeln!(file, "metadata width {}", width).expect("Couldn't write metadata");
    writeln!(file, "metadata sec_per_frame {}", sec_per_frame).expect("Couldn't write metadata");
    writeln!(file, "metadata left {}", left).expect("Couldn't write metadata");
    writeln!(file, "metadata bottom {}", bottom).expect("Couldn't write metadata");
    writeln!(file, "metadata right {}", right).expect("Couldn't write metadata");
    writeln!(file, "metadata top {}", top).expect("Couldn't write metadata");
    writeln!(file, "").expect("Couldn't write metadata");

    for (frame_no, pixels) in frames.into_iter() {
        write!(file, "{}", frame_no).unwrap();
        for p in pixels {
            write!(file, ",{},{}", p.0, p.1).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();

    //let metadata: Vec<(String, String)> = file.lines().filter_map(|x| x.ok()).take_while(|x| x.len() > 0).map(|x| { let words: Vec<_> = x.split(" ").skip(1).take(2).collect(); (words[0].clone(), words[1].clone())}).collect();

    for line in file.lines().filter_map(|x| x.ok()).skip_while(|x| x.starts_with("metadata ") || x.len() == 0) {
        let frame_no = line.split(",").nth(0).unwrap().parse().unwrap();
        let pixels: Vec<(u32, u16)> = line.split(",").skip(1).collect::<Vec<_>>().chunks(2).map(|pair| (pair[0].parse().unwrap(), pair[1].parse().unwrap())).collect();
        results.push((frame_no, pixels))
    }

    results
}

fn latlon_to_pixel_index(lat: f32, lon: f32, width: u32, height: u32, bbox: &[f32; 4]) -> Option<u32> {
    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;

    // FIXME should be able to do non-equals but it fails for point at south pole
    if lat >= top || lat <= bottom || lon >= right || lon <= left {
        return None;
    }

    let lat0 = top - lat;
    let lon0 = lon - left;

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

    let i = y * width + x;

    assert!(i < width*height, "{} L{}, lat = {} lon = {} width = {} height = {} bbox = {:?} x = {} y = {} i = {}", file!(), line!(), lat, lon, width, height, bbox, x, y, i);

    Some(i)
}

fn create_gif(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, &colour_ramp.palette()).expect("Couldn't create encoder");
    encoder.set(gif::Repeat::Infinite).expect("Couldn't get inf repeat");

    // TODO have a global palette

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

    for (frame_no, pixels) in frames.into_iter() {

        for i in 0..image.len() {
            if image[i].is_some() && image[i].unwrap() > 0. {
                image[i] = image[i].map(|x| x*0.95);
            }
        }

        for (i, magnitude) in pixels {
            // FIXME sometimes the value is invalid
            //assert!(i < width*height, "{} L{}, width = {} height = {} i = {}", file!(), line!(), width, height, i);
            if i < width*height {
                let new_value= image[i as usize].unwrap_or(0f32) + (magnitude as f32);
                image[i as usize] = Some(new_value);
            }
        }

        let mut pixels = Vec::with_capacity(image.len() * 4);
        for p in image.iter().cloned() {
            let index = colour_ramp.index_for_magnitude(p.map(|x| x.round() as u32));
            pixels.push(index);
        }

        let mut frame = gif::Frame::from_indexed_pixels(width as u16, height as u16, pixels.as_mut_slice(), None);
        // 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);
        }

    }

}

enum Projection { Ortho, Equirect, }

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").takes_value(true).short("b"))
                          .arg(Arg::with_name("ortho").long("ortho"))
                          .arg(Arg::with_name("equirect").long("equirect"))
                          .setting(AppSettings::AllowLeadingHyphen)
                          .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 sec_per_frame: 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 centre = ((bbox[0] + bbox[2])/2., (bbox[1] - bbox[3])/2.);

    let projection = if matches.is_present("ortho") {
        Projection::Ortho
    } else if matches.is_present("equirect") {
        Projection::Equirect
    } else {
        Projection::Equirect
    };

    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;

    let pixel_func = match projection {
        Projection::Ortho => { unreachable!() },
        Projection::Equirect => { |lat, lon| latlon_to_pixel_index(lat, lon, width, height, &bbox) },
    };

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

    if matches.is_present("save-intermediate") {
        println!("Saving frame details to {}", output_filename);
        write_frames(frames, &output_filename, height, sec_per_frame, &bbox);
    } else {
        let colour_ramp = ColourRamp::new_from_filename(matches.value_of("colour_ramp").unwrap());
        println!("Creating image {}", output_filename);
        create_gif(frames, &output_filename, height, &bbox, &colour_ramp);
    }
    println!("\nFinished");
}
<commit_msg>clean up<commit_after>extern crate osmio;
extern crate image;
extern crate gif;
extern crate clap;

use clap::{Arg, App, AppSettings};

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

use gif::SetParameter;

// (frame_no, (pixel_index, num_changes))
type Frames = Vec<(u32, Vec<(u32, u16)>)>;

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_magnitude(&self, magnitude: Option<u32>) -> u8 {
        match magnitude {
            None => 0,
            Some(magnitude) => {
                if magnitude > 255 {
                    1
                } else {
                    (255 - magnitude) as u8
                }
            },
        }
    }
}

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

    let mut results: HashMap<u32, HashMap<u32, u16>> = 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;

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

    let mut num_nodes: u64 = 0;
    for node in node_reader {
        if let (Some(lat), Some(lon)) = (node.lat, node.lon) {

            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);
            if let Some(pixel_idx) = pixel_func(lat, lon) {
                let curr_val = results.entry(frame_no).or_insert(HashMap::new()).entry(pixel_idx).or_insert(0);
                if *curr_val < std::u16::MAX {
                    *curr_val += 1;
                }
            }

            num_nodes += 1;
            if num_nodes % 50_000_000 == 0 {
                println!("Done {} million points", num_nodes/1_000_000);
            }
        }
    }
    println!("Done {} points", 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, height: u32, sec_per_frame: u32, bbox: &[f32; 4]) {
    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;

    let mut file = BufWriter::new(fs::File::create(&filename).unwrap());

    writeln!(file, "metadata version {}", env!("CARGO_PKG_VERSION")).expect("Couldn't write metadata");
    writeln!(file, "metadata height {}", height).expect("Couldn't write metadata");
    writeln!(file, "metadata width {}", width).expect("Couldn't write metadata");
    writeln!(file, "metadata sec_per_frame {}", sec_per_frame).expect("Couldn't write metadata");
    writeln!(file, "metadata left {}", left).expect("Couldn't write metadata");
    writeln!(file, "metadata bottom {}", bottom).expect("Couldn't write metadata");
    writeln!(file, "metadata right {}", right).expect("Couldn't write metadata");
    writeln!(file, "metadata top {}", top).expect("Couldn't write metadata");
    writeln!(file, "").expect("Couldn't write metadata");

    for (frame_no, pixels) in frames.into_iter() {
        write!(file, "{}", frame_no).unwrap();
        for p in pixels {
            write!(file, ",{},{}", p.0, p.1).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();

    //let metadata: Vec<(String, String)> = file.lines().filter_map(|x| x.ok()).take_while(|x| x.len() > 0).map(|x| { let words: Vec<_> = x.split(" ").skip(1).take(2).collect(); (words[0].clone(), words[1].clone())}).collect();

    for line in file.lines().filter_map(|x| x.ok()).skip_while(|x| x.starts_with("metadata ") || x.len() == 0) {
        let frame_no = line.split(",").nth(0).unwrap().parse().unwrap();
        let pixels: Vec<(u32, u16)> = line.split(",").skip(1).collect::<Vec<_>>().chunks(2).map(|pair| (pair[0].parse().unwrap(), pair[1].parse().unwrap())).collect();
        results.push((frame_no, pixels))
    }

    results
}

fn latlon_to_pixel_index(lat: f32, lon: f32, width: u32, height: u32, bbox: &[f32; 4]) -> Option<u32> {
    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;

    // FIXME should be able to do non-equals but it fails for point at south pole
    if lat >= top || lat <= bottom || lon >= right || lon <= left {
        return None;
    }

    let lat0 = top - lat;
    let lon0 = lon - left;

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

    let i = y * width + x;

    assert!(i < width*height, "{} L{}, lat = {} lon = {} width = {} height = {} bbox = {:?} x = {} y = {} i = {}", file!(), line!(), lat, lon, width, height, bbox, x, y, i);

    Some(i)
}

fn create_gif(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, &colour_ramp.palette()).expect("Couldn't create encoder");
    encoder.set(gif::Repeat::Infinite).expect("Couldn't get inf repeat");

    // TODO have a global palette

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

    for (frame_no, pixels) in frames.into_iter() {

        for i in 0..image.len() {
            if image[i].is_some() && image[i].unwrap() > 0. {
                image[i] = image[i].map(|x| x*0.95);
            }
        }

        for (i, magnitude) in pixels {
            // FIXME sometimes the value is invalid
            //assert!(i < width*height, "{} L{}, width = {} height = {} i = {}", file!(), line!(), width, height, i);
            if i < width*height {
                let new_value= image[i as usize].unwrap_or(0f32) + (magnitude as f32);
                image[i as usize] = Some(new_value);
            }
        }

        let mut pixels = Vec::with_capacity(image.len() * 4);
        for p in image.iter().cloned() {
            let index = colour_ramp.index_for_magnitude(p.map(|x| x.round() as u32));
            pixels.push(index);
        }

        let mut frame = gif::Frame::from_indexed_pixels(width as u16, height as u16, pixels.as_mut_slice(), None);
        // 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);
        }

    }

}

enum Projection { Ortho, Equirect, }

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").takes_value(true).short("b"))
                          .arg(Arg::with_name("ortho").long("ortho"))
                          .arg(Arg::with_name("equirect").long("equirect"))
                          .setting(AppSettings::AllowLeadingHyphen)
                          .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 sec_per_frame: 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 centre = ((bbox[0] + bbox[2])/2., (bbox[1] - bbox[3])/2.);

    let projection = if matches.is_present("ortho") {
        Projection::Ortho
    } else if matches.is_present("equirect") {
        Projection::Equirect
    } else {
        Projection::Equirect
    };

    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;

    let pixel_func = match projection {
        Projection::Ortho => { unreachable!() },
        Projection::Equirect => { |lat, lon| latlon_to_pixel_index(lat, lon, width, height, &bbox) },
    };

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

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


<commit_before>extern crate chrono;
extern crate clap;
extern crate libc;
extern crate multirust;
extern crate rust_install;

extern crate rustc_bisect;

use std::process;

use chrono::{Datelike, NaiveDate};
use clap::{App, AppSettings, Arg};

use rustc_bisect::{Cmd, Error, Result, ToolchainSpec, bisect};

fn run_rust_bisect() -> Result<i32> {
    let matches = App::new("rustc-bisect")
                      .author("Kamal Marhubi <kamal@marhubi.com>")
                      .setting(AppSettings::TrailingVarArg)
                      .arg(Arg::with_name("good")
                               .long("good")
                               .takes_value(true)
                               .value_name("TOOLCHAIN")
                               .required(true))
                      .arg(Arg::with_name("bad")
                               .long("bad")
                               .takes_value(true)
                               .value_name("TOOLCHAIN")
                               .required(true))
                      .arg(Arg::with_name("COMMAND")
                               .multiple(true)
                               .required(true))
                      .get_matches();

    let cfg = try!(multirust::Cfg::from_env(rust_install::notify::SharedNotifyHandler::none()));

    use std::str::FromStr;

    let good = matches.value_of("good").expect("good");
    let good_spec = try!(ToolchainSpec::from_str(good));

    let bad = matches.value_of("bad").expect("bad");
    let bad_spec = try!(ToolchainSpec::from_str(bad));

    fn get_nightly_date(spec: ToolchainSpec) -> Result<NaiveDate> {
        match spec {
            ToolchainSpec::Nightly(date) => Ok(date),
            _ => Err(Error::from("only nightlies for now")),
        }
    }

    let good_date = try!(get_nightly_date(good_spec));
    let bad_date = try!(get_nightly_date(bad_spec));

    let cmd: Vec<_> = matches.values_of_os("COMMAND").expect("COMMAND").collect();
    let cmd = Cmd::from(&cmd[..]);

    let range = good_date.num_days_from_ce()..bad_date.num_days_from_ce();

    let res = bisect(range, |num_days| {
        let spec = ToolchainSpec::Nightly(NaiveDate::from_num_days_from_ce(num_days));
        let toolchain = cfg.get_toolchain(&spec.to_string(), false).expect("get_toolchain");

        if toolchain.install_from_dist_if_not_installed().is_err() {
            return None;
        }

        let res = cmd.succeeds_with(&toolchain).expect("run command");

        println!("command {} at {}", if res { "succeeded" } else { "failed" }, spec);
        Some(!res)
    });

    if let Some(num_days) = res {
        println!("first failing nightly: {}",
                 ToolchainSpec::Nightly(NaiveDate::from_num_days_from_ce(num_days)));
        Ok(libc::EXIT_SUCCESS)
    } else {
        println!("bisect failed");
        Ok(libc::EXIT_FAILURE)
    }
}

fn main() {
    process::exit(run_rust_bisect().expect("something went wrong"));
}
<commit_msg>style: Run rustfmt<commit_after>extern crate chrono;
extern crate clap;
extern crate libc;
extern crate multirust;
extern crate rust_install;

extern crate rustc_bisect;

use std::process;

use chrono::{Datelike, NaiveDate};
use clap::{App, AppSettings, Arg};

use rustc_bisect::{Cmd, Error, Result, ToolchainSpec, bisect};

fn run_rust_bisect() -> Result<i32> {
    let matches = App::new("rustc-bisect")
                      .author("Kamal Marhubi <kamal@marhubi.com>")
                      .setting(AppSettings::TrailingVarArg)
                      .arg(Arg::with_name("good")
                               .long("good")
                               .takes_value(true)
                               .value_name("TOOLCHAIN")
                               .required(true))
                      .arg(Arg::with_name("bad")
                               .long("bad")
                               .takes_value(true)
                               .value_name("TOOLCHAIN")
                               .required(true))
                      .arg(Arg::with_name("COMMAND")
                               .multiple(true)
                               .required(true))
                      .get_matches();

    let cfg = try!(multirust::Cfg::from_env(rust_install::notify::SharedNotifyHandler::none()));

    use std::str::FromStr;

    let good = matches.value_of("good").expect("good");
    let good_spec = try!(ToolchainSpec::from_str(good));

    let bad = matches.value_of("bad").expect("bad");
    let bad_spec = try!(ToolchainSpec::from_str(bad));

    fn get_nightly_date(spec: ToolchainSpec) -> Result<NaiveDate> {
        match spec {
            ToolchainSpec::Nightly(date) => Ok(date),
            _ => Err(Error::from("only nightlies for now")),
        }
    }

    let good_date = try!(get_nightly_date(good_spec));
    let bad_date = try!(get_nightly_date(bad_spec));

    let cmd: Vec<_> = matches.values_of_os("COMMAND").expect("COMMAND").collect();
    let cmd = Cmd::from(&cmd[..]);

    let range = good_date.num_days_from_ce()..bad_date.num_days_from_ce();

    let res = bisect(range, |num_days| {
        let spec = ToolchainSpec::Nightly(NaiveDate::from_num_days_from_ce(num_days));
        let toolchain = cfg.get_toolchain(&spec.to_string(), false).expect("get_toolchain");

        if toolchain.install_from_dist_if_not_installed().is_err() {
            return None;
        }

        let res = cmd.succeeds_with(&toolchain).expect("run command");

        println!("command {} at {}",
                 if res {
                     "succeeded"
                 } else {
                     "failed"
                 },
                 spec);
        Some(!res)
    });

    if let Some(num_days) = res {
        println!("first failing nightly: {}",
                 ToolchainSpec::Nightly(NaiveDate::from_num_days_from_ce(num_days)));
        Ok(libc::EXIT_SUCCESS)
    } else {
        println!("bisect failed");
        Ok(libc::EXIT_FAILURE)
    }
}

fn main() {
    process::exit(run_rust_bisect().expect("something went wrong"));
}
<|endoftext|>


<commit_before>extern crate image;
extern crate rand;
extern crate docopt;
extern crate rustc_serialize as rustc_serialize;
extern crate threadpool;
extern crate num_cpus;
extern crate tray_rust;

use std::vec::Vec;
use std::sync::{Arc};
use std::sync::mpsc::{self, Sender, Receiver};
use std::path::Path;

use threadpool::ThreadPool;
use rand::StdRng;
use docopt::Docopt;

use tray_rust::film;
use tray_rust::geometry::Geometry;
use tray_rust::sampler::{self, Sampler};
use tray_rust::scene;
use tray_rust::integrator::Integrator;

static WIDTH: usize = 800;
static HEIGHT: usize = 600;
static USAGE: &'static str = "
Usage: tray_rust [options]

Options:
  -o <file>     Specify the output file to save the image. Supported formats are
                PNG, JPG and PPM. Default is 'out.png'.
  -n <number>   Specify the number of threads to use for rendering. Defaults to the number of cores
                on the system.
  -h, --help    Show this message.
";

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_o: Option<String>,
    flag_n: Option<usize>,
}

/// Threads are each sent a sender end of the channel that is
/// read from by the render target thread which then saves the
/// values recieved to the render target
fn thread_work(tx: Sender<(f32, f32, film::Colorf)>, queue: Arc<sampler::BlockQueue>,
               scene: Arc<scene::Scene>) {
    let mut sampler = sampler::LowDiscrepancy::new(queue.block_dim(), 64);
    let mut samples = Vec::with_capacity(sampler.max_spp());
    let mut sample_pos = Vec::with_capacity(sampler.max_spp());
    let mut rng = match StdRng::new() {
        Ok(r) => r,
        Err(e) => { println!("Failed to get StdRng, {}", e); return }
    };
    // Grab a block from the queue and start working on it, submitting samples
    // to the render target thread after each pixel
    for b in queue.iter() {
        sampler.select_block(b);
        while sampler.has_samples() {
            // Get samples for a pixel and render them
            sampler.get_samples(&mut sample_pos, &mut rng);
            for s in sample_pos.iter() {
                let mut ray = scene.camera.generate_ray(s);
                if let Some(hit) = scene.intersect(&mut ray) {
                    let c = scene.integrator.illumination(&*scene, &ray, &hit, &mut sampler, &mut rng).clamp();
                    samples.push((s.0, s.1, c));
                }
            }
            for s in samples.iter() {
                if let Err(e) = tx.send(*s) {
                    println!("Worker thread exiting with send error {:?}", e);
                    return;
                }
            }
            samples.clear();
        }
    }
}

/// Spawn `n` worker threads to render the scene in parallel. Returns the receive end
/// of the channel where the threads will write their samples so that the receiver
/// can write these samples to the render target
fn spawn_workers(pool: &ThreadPool, n: usize, scene: Arc<scene::Scene>) -> Receiver<(f32, f32, film::Colorf)> {
    let (tx, rx) = mpsc::channel();
    let block_queue = Arc::new(sampler::BlockQueue::new((WIDTH as u32, HEIGHT as u32), (8, 8)));
    for _ in 0..n {
        let q = block_queue.clone();
        let t = tx.clone();
        let s = scene.clone();
        pool.execute(move || {
            thread_work(t, q, s);
        });
    }
    rx
}

/// Render the scene in parallel to the render target
fn render_parallel(rt: &mut film::RenderTarget, n: usize){
    let scene = Arc::new(scene::Scene::new(WIDTH, HEIGHT));
    let pool = ThreadPool::new(n);
    let rx = spawn_workers(&pool, n, scene);
    for m in rx.iter() {
        rt.write(m.0, m.1, &m.2);
    }
}

fn main() {
    let args: Args = Docopt::new(USAGE).and_then(|d| d.decode()).unwrap_or_else(|e| e.exit());

    let mut rt = film::RenderTarget::new(WIDTH, HEIGHT);
    let n = match args.flag_n {
        Some(n) => n,
        None => num_cpus::get(),
    };
    println!("Rendering using {} threads", n);
    render_parallel(&mut rt, n);
    // TODO: Migrate to the new duration API that landed
    // See: https://github.com/rust-lang/rust/pull/24920
    //let d = std::time::duration::Duration::span(|| render_parallel(&mut rt, n));
    //println!("Rendering took {}ms", d.num_milliseconds());
    let img = rt.get_render();
    let out_file = match args.flag_o {
        Some(f) => f,
        None => "out.png".to_string(),
    };
    match image::save_buffer(&Path::new(&out_file), &img[..], WIDTH as u32, HEIGHT as u32, image::RGB(8)) {
        Ok(_) => {},
        Err(e) => println!("Error saving image, {}", e),
    };
}

<commit_msg>Migrate to new duration lib on 1.2 nightly<commit_after>#![feature(duration)]
#![feature(duration_span)]

extern crate image;
extern crate rand;
extern crate docopt;
extern crate rustc_serialize as rustc_serialize;
extern crate threadpool;
extern crate num_cpus;
extern crate tray_rust;

use std::vec::Vec;
use std::sync::{Arc};
use std::sync::mpsc::{self, Sender, Receiver};
use std::path::Path;
use std::time::Duration;

use threadpool::ThreadPool;
use rand::StdRng;
use docopt::Docopt;

use tray_rust::film;
use tray_rust::geometry::Geometry;
use tray_rust::sampler::{self, Sampler};
use tray_rust::scene;
use tray_rust::integrator::Integrator;

static WIDTH: usize = 800;
static HEIGHT: usize = 600;
static USAGE: &'static str = "
Usage: tray_rust [options]

Options:
  -o <file>     Specify the output file to save the image. Supported formats are
                PNG, JPG and PPM. Default is 'out.png'.
  -n <number>   Specify the number of threads to use for rendering. Defaults to the number of cores
                on the system.
  -h, --help    Show this message.
";

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_o: Option<String>,
    flag_n: Option<usize>,
}

// TODO: Area lights notes:
// - They should be intersectable so they're like wierd instances.
// - What if point lights were also instances that just always returned None
//   for intersection tests?
// - Then each thread would build a list of &Instance that refer to the emissive
//   instances in the scene and we'd pass this around for the various lighting calculations.
//   It's a bit ugly but maybe cleaner than what was done previously in tray

/// Threads are each sent a sender end of the channel that is
/// read from by the render target thread which then saves the
/// values recieved to the render target
fn thread_work(tx: Sender<(f32, f32, film::Colorf)>, queue: Arc<sampler::BlockQueue>,
               scene: Arc<scene::Scene>) {
    let mut sampler = sampler::LowDiscrepancy::new(queue.block_dim(), 4);
    let mut samples = Vec::with_capacity(sampler.max_spp());
    let mut sample_pos = Vec::with_capacity(sampler.max_spp());
    let mut rng = match StdRng::new() {
        Ok(r) => r,
        Err(e) => { println!("Failed to get StdRng, {}", e); return }
    };
    // Grab a block from the queue and start working on it, submitting samples
    // to the render target thread after each pixel
    for b in queue.iter() {
        sampler.select_block(b);
        while sampler.has_samples() {
            // Get samples for a pixel and render them
            sampler.get_samples(&mut sample_pos, &mut rng);
            for s in sample_pos.iter() {
                let mut ray = scene.camera.generate_ray(s);
                if let Some(hit) = scene.intersect(&mut ray) {
                    let c = scene.integrator.illumination(&*scene, &ray, &hit, &mut sampler, &mut rng).clamp();
                    samples.push((s.0, s.1, c));
                }
            }
            for s in samples.iter() {
                if let Err(e) = tx.send(*s) {
                    println!("Worker thread exiting with send error {:?}", e);
                    return;
                }
            }
            samples.clear();
        }
    }
}

/// Spawn `n` worker threads to render the scene in parallel. Returns the receive end
/// of the channel where the threads will write their samples so that the receiver
/// can write these samples to the render target
fn spawn_workers(pool: &ThreadPool, n: usize, scene: Arc<scene::Scene>) -> Receiver<(f32, f32, film::Colorf)> {
    let (tx, rx) = mpsc::channel();
    let block_queue = Arc::new(sampler::BlockQueue::new((WIDTH as u32, HEIGHT as u32), (8, 8)));
    for _ in 0..n {
        let q = block_queue.clone();
        let t = tx.clone();
        let s = scene.clone();
        pool.execute(move || {
            thread_work(t, q, s);
        });
    }
    rx
}

/// Render the scene in parallel to the render target
fn render_parallel(rt: &mut film::RenderTarget, n: usize){
    let scene = Arc::new(scene::Scene::new(WIDTH, HEIGHT));
    let pool = ThreadPool::new(n);
    let rx = spawn_workers(&pool, n, scene);
    for m in rx.iter() {
        rt.write(m.0, m.1, &m.2);
    }
}

fn main() {
    let args: Args = Docopt::new(USAGE).and_then(|d| d.decode()).unwrap_or_else(|e| e.exit());

    let mut rt = film::RenderTarget::new(WIDTH, HEIGHT);
    let n = match args.flag_n {
        Some(n) => n,
        None => num_cpus::get(),
    };
    println!("Rendering using {} threads", n);
    let d = Duration::span(|| render_parallel(&mut rt, n));
    println!("Rendering took {}", d);
    let img = rt.get_render();
    let out_file = match args.flag_o {
        Some(f) => f,
        None => "out.png".to_string(),
    };
    match image::save_buffer(&Path::new(&out_file), &img[..], WIDTH as u32, HEIGHT as u32, image::RGB(8)) {
        Ok(_) => {},
        Err(e) => println!("Error saving image, {}", e),
    };
}

<|endoftext|>


<commit_before>use entities::{ EntitiesState, EntityID, ComponentID, NativeComponentType };
use std::collections::{ HashSet, HashMap };
use std::cell::RefCell;
use std::rc::Rc;
use nalgebra::na::{ Norm, Translation, Vec2 };
use ncollide::geom::geom::Geom;
use nphysics::world::World;
use nphysics::object::{ RigidBody };

pub struct PhysicsSystem {
	world: World,
	bodies: HashMap<EntityID, Rc<RefCell<RigidBody>>>
}

impl PhysicsSystem {
	pub fn new(_: &EntitiesState)
		-> PhysicsSystem
	{
		let mut world = World::new();
		world.set_gravity(Vec2::new(0.0f32, 0.0));

		let shape = ::ncollide::geom::Plane::new(Vec2::new(0.0f32, 1.0));
		let body = Rc::new(RefCell::new(RigidBody::new_static(shape, 0.3, 0.6)));
		world.add_body(body);

		PhysicsSystem {
			world: world,
			bodies: HashMap::new()
		}
	}

	pub fn process(&mut self, state: &mut EntitiesState, elapsed: &u64)
	{
		// getting the list of all entities that have physics activated
		let listOfEntities: HashSet<EntityID> = state.get_components_iter()
            .filter(|c| state.is_component_visible(*c).unwrap())
			.filter(|c| match state.get_type(*c) { Ok(NativeComponentType(t)) => t.as_slice() == "physics", _ => false })
			.filter(|c| match state.get(*c, "activated") { Ok(&::entities::Boolean(ref b)) => *b, _ => false })
			.map(|c| state.get_owner(c).unwrap())
			.collect();

		// removing from the world the elements that have disappeared
		{
			let toRemove: Vec<EntityID> = self.bodies.keys().filter(|e| !listOfEntities.contains(e.clone())).map(|e| e.clone()).collect();
			for e in toRemove.move_iter() {
				//self.bodies.find(&e).		// TODO: remove body from the world
				self.bodies.remove(&e);
			}
		}

		// adding elements that are not yet in the world
		{
			let toCreate: Vec<EntityID> = listOfEntities.iter().filter(|e| !self.bodies.contains_key(e.clone())).map(|e| e.clone()).collect();
			for e in toCreate.move_iter() {
				let shape = ::ncollide::geom::Cuboid::new(Vec2::new(0.5f32, 0.5f32));
				let body = Rc::new(RefCell::new(RigidBody::new_dynamic(shape, 1.0, 0.5, 0.0)));

				// initializing body with current position and movement
				body.borrow_mut().set_translation(PhysicsSystem::get_position(state, &e));
				body.borrow_mut().set_lin_vel(PhysicsSystem::get_movement(state, &e));

				self.bodies.insert(e.clone(), body.clone());
				self.world.add_body(body.clone());
			}
		}

		// setting all positions and movements
		for (entity, body) in self.bodies.iter() {
			let position = PhysicsSystem::get_position(state, entity);
			let movement = PhysicsSystem::get_movement(state, entity);
			let requestedMovement = PhysicsSystem::get_movement(state, entity);

			let mut borrowedBody = body.borrow_mut();
			borrowedBody.set_translation(position);
			borrowedBody.set_lin_vel(movement);
		}

		// step
		self.world.step((*elapsed as f32) / 1000.0);

		//
		for (entity, body) in self.bodies.iter() {
			PhysicsSystem::set_position(state, entity, &body.borrow().translation());
			PhysicsSystem::set_movement(state, entity, &body.borrow().lin_vel());
		}
	}

	/// returns the position of an entity
	fn get_position(state: &EntitiesState, id: &EntityID)
		-> Vec2<f32>
	{
		state
			.get_components_iter()

			// take only the components owned by the entity
			.filter(|c| state.get_owner(*c).unwrap() == *id)

			// take only the "position" components
			.filter(|c| match state.get_type(*c) { Ok(NativeComponentType(t)) => t.as_slice() == "position", _ => false })

			// build a vector from each of the component
			.filter_map(|cmp| match (state.get(cmp, "x"), state.get(cmp, "y"), state.get(cmp, "z")) {
				(Ok(&::entities::Number(ref x)), Ok(&::entities::Number(ref y)), _)
					=> Some(Vec2::new(*x as f32, *y as f32)),
				_ => None
			})

			// add all the elements together
			.fold(Vec2::new(0.0, 0.0), |vec, a| Vec2::new(vec.x + a.x, vec.y + a.y))
	}

	/// returns the total movement of an entity
	fn get_movement(state: &EntitiesState, id: &EntityID)
		-> Vec2<f32>
	{
		state
			.get_components_iter()

			// take only the components owned by the entity
			.filter(|c| state.get_owner(*c).unwrap() == *id)

			// take only the "position" components
			.filter(|c| match state.get_type(*c) { Ok(NativeComponentType(t)) => t.as_slice() == "movement", _ => false })

			// build a vector from each of the component
			.filter_map(|cmp| match (state.get(cmp, "x"), state.get(cmp, "y"), state.get(cmp, "z")) {
				(Ok(&::entities::Number(ref x)), Ok(&::entities::Number(ref y)), _)
					=> Some(Vec2::new(*x as f32, *y as f32)),
				_ => None
			})

			// add all the elements together
			.fold(Vec2::new(0.0, 0.0), |vec, a| Vec2::new(vec.x + a.x, vec.y + a.y))
	}

	/// changes the position of an entity
	fn set_position(state: &mut EntitiesState, id: &EntityID, pos: &Vec2<f32>)
	{
		let list: Vec<ComponentID> = state
			.get_components_iter()
			// take only the components owned by the entity
			.filter(|c| state.get_owner(*c).unwrap() == *id)
			// take only the "position" components
			.filter(|c| match state.get_type(*c) { Ok(NativeComponentType(t)) => t.as_slice() == "position", _ => false })
			.map(|c| c.clone()).collect();

		for cmp in list.iter()
		{
			state.set(cmp, "x", ::entities::Number(pos.x as f64));
			state.set(cmp, "y", ::entities::Number(pos.y as f64));
		}
	}

	/// changes the movement of an entity
	fn set_movement(state: &mut EntitiesState, id: &EntityID, pos: &Vec2<f32>)
	{
		let list: Vec<ComponentID> = state
			.get_components_iter()
			// take only the components owned by the entity
			.filter(|c| state.get_owner(*c).unwrap() == *id)
			// take only the "position" components
			.filter(|c| match state.get_type(*c) { Ok(NativeComponentType(t)) => t.as_slice() == "movement", _ => false })
			.map(|c| c.clone()).collect();

		for cmp in list.iter()
		{
			state.set(cmp, "x", ::entities::Number(pos.x as f64));
			state.set(cmp, "y", ::entities::Number(pos.y as f64));
		}
	}
}
<commit_msg>Add requested movement system<commit_after>use entities::{ EntitiesState, EntityID, ComponentID, NativeComponentType };
use std::collections::{ HashSet, HashMap };
use std::cell::RefCell;
use std::rc::Rc;
use nalgebra::na::{ Norm, Translation, Vec2 };
use ncollide::geom::geom::Geom;
use nphysics::world::World;
use nphysics::object::{ RigidBody };

pub struct PhysicsSystem {
	world: World,
	bodies: HashMap<EntityID, Rc<RefCell<RigidBody>>>
}

impl PhysicsSystem {
	pub fn new(_: &EntitiesState)
		-> PhysicsSystem
	{
		let mut world = World::new();
		world.set_gravity(Vec2::new(0.0f32, -9.8));

		let shape = ::ncollide::geom::Plane::new(Vec2::new(0.0f32, 1.0));
		let body = Rc::new(RefCell::new(RigidBody::new_static(shape, 0.3, 0.6)));
		world.add_body(body);

		PhysicsSystem {
			world: world,
			bodies: HashMap::new()
		}
	}

	pub fn process(&mut self, state: &mut EntitiesState, elapsed: &u64)
	{
		// getting the list of all entities that have physics activated
		let listOfEntities: HashSet<EntityID> = state.get_components_iter()
            .filter(|c| state.is_component_visible(*c).unwrap())
			.filter(|c| match state.get_type(*c) { Ok(NativeComponentType(t)) => t.as_slice() == "physics", _ => false })
			.filter(|c| match state.get(*c, "activated") { Ok(&::entities::Boolean(ref b)) => *b, _ => false })
			.map(|c| state.get_owner(c).unwrap())
			.collect();

		// removing from the world the elements that have disappeared
		{
			let toRemove: Vec<EntityID> = self.bodies.keys().filter(|e| !listOfEntities.contains(e.clone())).map(|e| e.clone()).collect();
			for e in toRemove.move_iter() {
				//self.bodies.find(&e).		// TODO: remove body from the world
				self.bodies.remove(&e);
			}
		}

		// adding elements that are not yet in the world
		{
			let toCreate: Vec<EntityID> = listOfEntities.iter().filter(|e| !self.bodies.contains_key(e.clone())).map(|e| e.clone()).collect();
			for e in toCreate.move_iter() {
				let shape = ::ncollide::geom::Cuboid::new(Vec2::new(0.5f32, 0.5f32));
				let body = Rc::new(RefCell::new(RigidBody::new_dynamic(shape, 1.0, 0.5, 0.0)));

				// initializing body with current position and movement
				body.borrow_mut().set_translation(PhysicsSystem::get_position(state, &e));
				body.borrow_mut().set_lin_vel(PhysicsSystem::get_movement(state, &e));

				self.bodies.insert(e.clone(), body.clone());
				self.world.add_body(body.clone());
			}
		}

		// setting all positions and movements
		for (entity, body) in self.bodies.iter() {
			let position = PhysicsSystem::get_position(state, entity);
			let movement = PhysicsSystem::get_movement(state, entity);
			let requestedMovement = PhysicsSystem::get_requested_movement(state, entity);
			let acceleration = Norm::normalize_cpy(&(requestedMovement - movement)) * 5.0f32;

			let mut borrowedBody = body.borrow_mut();
			borrowedBody.set_translation(position);
			borrowedBody.set_lin_vel(movement);
			borrowedBody.set_lin_acc(acceleration);
		}

		// step
		self.world.step((*elapsed as f32) / 1000.0);

		//
		for (entity, body) in self.bodies.iter() {
			PhysicsSystem::set_position(state, entity, &body.borrow().translation());
			PhysicsSystem::set_movement(state, entity, &body.borrow().lin_vel());
		}
	}

	/// returns the position of an entity
	fn get_position(state: &EntitiesState, id: &EntityID)
		-> Vec2<f32>
	{
		state
			.get_components_iter()

			// take only the components owned by the entity
			.filter(|c| state.get_owner(*c).unwrap() == *id)

			// take only the "position" components
			.filter(|c| match state.get_type(*c) { Ok(NativeComponentType(t)) => t.as_slice() == "position", _ => false })

			// build a vector from each of the component
			.filter_map(|cmp| match (state.get(cmp, "x"), state.get(cmp, "y"), state.get(cmp, "z")) {
				(Ok(&::entities::Number(ref x)), Ok(&::entities::Number(ref y)), _)
					=> Some(Vec2::new(*x as f32, *y as f32)),
				_ => None
			})

			// add all the elements together
			.fold(Vec2::new(0.0, 0.0), |vec, a| Vec2::new(vec.x + a.x, vec.y + a.y))
	}

	/// returns the total movement of an entity
	fn get_movement(state: &EntitiesState, id: &EntityID)
		-> Vec2<f32>
	{
		state
			.get_components_iter()

			// take only the components owned by the entity
			.filter(|c| state.get_owner(*c).unwrap() == *id)

			// take only the "position" components
			.filter(|c| match state.get_type(*c) { Ok(NativeComponentType(t)) => t.as_slice() == "movement", _ => false })

			// build a vector from each of the component
			.filter_map(|cmp| match (state.get(cmp, "x"), state.get(cmp, "y"), state.get(cmp, "z")) {
				(Ok(&::entities::Number(ref x)), Ok(&::entities::Number(ref y)), _)
					=> Some(Vec2::new(*x as f32, *y as f32)),
				_ => None
			})

			// add all the elements together
			.fold(Vec2::new(0.0, 0.0), |vec, a| Vec2::new(vec.x + a.x, vec.y + a.y))
	}

	/// returns the total requested movement of an entity
	fn get_requested_movement(state: &EntitiesState, id: &EntityID)
		-> Vec2<f32>
	{
		state
			.get_components_iter()

			// take only the components owned by the entity
			.filter(|c| state.get_owner(*c).unwrap() == *id)

			// take only the "position" components
			.filter(|c| match state.get_type(*c) { Ok(NativeComponentType(t)) => t.as_slice() == "requestedMovement", _ => false })

			// build a vector from each of the component
			.filter_map(|cmp| match (state.get(cmp, "x"), state.get(cmp, "y"), state.get(cmp, "z")) {
				(Ok(&::entities::Number(ref x)), Ok(&::entities::Number(ref y)), _)
					=> Some(Vec2::new(*x as f32, *y as f32)),
				_ => None
			})

			// add all the elements together
			.fold(Vec2::new(0.0, 0.0), |vec, a| Vec2::new(vec.x + a.x, vec.y + a.y))
	}

	/// changes the position of an entity
	fn set_position(state: &mut EntitiesState, id: &EntityID, pos: &Vec2<f32>)
	{
		let list: Vec<ComponentID> = state
			.get_components_iter()
			// take only the components owned by the entity
			.filter(|c| state.get_owner(*c).unwrap() == *id)
			// take only the "position" components
			.filter(|c| match state.get_type(*c) { Ok(NativeComponentType(t)) => t.as_slice() == "position", _ => false })
			.map(|c| c.clone()).collect();

		for cmp in list.iter()
		{
			state.set(cmp, "x", ::entities::Number(pos.x as f64));
			state.set(cmp, "y", ::entities::Number(pos.y as f64));
		}
	}

	/// changes the movement of an entity
	fn set_movement(state: &mut EntitiesState, id: &EntityID, pos: &Vec2<f32>)
	{
		let list: Vec<ComponentID> = state
			.get_components_iter()
			// take only the components owned by the entity
			.filter(|c| state.get_owner(*c).unwrap() == *id)
			// take only the "position" components
			.filter(|c| match state.get_type(*c) { Ok(NativeComponentType(t)) => t.as_slice() == "movement", _ => false })
			.map(|c| c.clone()).collect();

		for cmp in list.iter()
		{
			state.set(cmp, "x", ::entities::Number(pos.x as f64));
			state.set(cmp, "y", ::entities::Number(pos.y as f64));
		}
	}
}
<|endoftext|>


<commit_before>extern crate iron;
extern crate openssl;
extern crate router;
extern crate serde_json;
extern crate rustc_serialize;

use std::io::BufReader;
use std::fs::File;
use iron::prelude::*;
use iron::status;
use iron::middleware::Handler;
use openssl::bn::BigNum;
use openssl::crypto::pkey::PKey;
use iron::headers::ContentType;
use router::Router;
use serde_json::builder::ObjectBuilder;
use serde_json::value::Value;
use rustc_serialize::base64::{self, ToBase64};

const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const SELF_BASE: &'static str = "http://xavamedia.nl:8000";

fn json_response(obj: &Value) -> IronResult<Response> {
	let content = serde_json::to_string(&obj).unwrap();
	let mut rsp = Response::with((status::Ok, content));
	rsp.headers.set(ContentType::json());
    return Ok(rsp);
}

fn welcome(_: &mut Request) -> IronResult<Response> {
	return json_response(&ObjectBuilder::new()
	    .insert("ladaemon", "Welcome")
	    .insert("version", VERSION)
	    .unwrap());
}

fn oid_config(_: &mut Request) -> IronResult<Response> {
    return json_response(&ObjectBuilder::new()
        .insert("issuer", SELF_BASE)
        .insert("authorization_endpoint", format!("{}/auth", SELF_BASE))
        .insert("jwks_uri", format!("{}/keys.json", SELF_BASE))
        .insert("scopes_supported", vec!["openid", "email"])
        .insert("claims_supported", vec!["aud", "email", "email_verified", "exp", "iat", "iss", "sub"])
        .insert("response_types_supported", vec!["id_token"])
        .insert("response_modes_supported", vec!["form_post"])
        .insert("grant_types_supported", vec!["implicit"])
        .insert("subject_types_supported", vec!["public"])
        .insert("id_token_signing_alg_values_supported", vec!["RS256"])
        .unwrap());
}

fn json_big_num(n: &BigNum) -> String {
    return n.to_vec().to_base64(base64::URL_SAFE);
}

struct PrivKey {
    priv_key: PKey,
}

impl PrivKey {
    fn new(priv_key: PKey) -> PrivKey {
        PrivKey { priv_key: priv_key }
    }
}

impl Handler for PrivKey {
    fn handle(&self, _: &mut Request) -> IronResult<Response> {
        let rsa = self.priv_key.get_rsa();
        return json_response(&ObjectBuilder::new()
            .insert_array("keys", |builder| {
                builder.push_object(|builder| {
                    builder
                        .insert("kty", "RSA")
                        .insert("alg", "RS256")
                        .insert("use", "sig")
                        .insert("kid", "base")
                        .insert("n", json_big_num(&rsa.n().unwrap()))
                        .insert("e", json_big_num(&rsa.e().unwrap()))
            })
        }).unwrap());
    }
}

fn main() {

    let priv_key_file = File::open("private.pem").unwrap();
    let mut reader = BufReader::new(priv_key_file);
    let priv_key = PrivKey::new(PKey::private_key_from_pem(&mut reader).unwrap());

    let mut router = Router::new();
    router.get("/", welcome);
    router.get("/.well-known/openid-configuration", oid_config);
    router.get("/keys.json", priv_key);
    Iron::new(router).http("0.0.0.0:8000").unwrap();

}
<commit_msg>Put use statements in alphabetical order<commit_after>extern crate iron;
extern crate openssl;
extern crate router;
extern crate serde_json;
extern crate rustc_serialize;

use iron::headers::ContentType;
use iron::middleware::Handler;
use iron::prelude::*;
use iron::status;
use openssl::bn::BigNum;
use openssl::crypto::pkey::PKey;
use serde_json::builder::ObjectBuilder;
use serde_json::value::Value;
use router::Router;
use rustc_serialize::base64::{self, ToBase64};
use std::fs::File;
use std::io::BufReader;

const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const SELF_BASE: &'static str = "http://xavamedia.nl:8000";

fn json_response(obj: &Value) -> IronResult<Response> {
	let content = serde_json::to_string(&obj).unwrap();
	let mut rsp = Response::with((status::Ok, content));
	rsp.headers.set(ContentType::json());
    return Ok(rsp);
}

fn welcome(_: &mut Request) -> IronResult<Response> {
	return json_response(&ObjectBuilder::new()
	    .insert("ladaemon", "Welcome")
	    .insert("version", VERSION)
	    .unwrap());
}

fn oid_config(_: &mut Request) -> IronResult<Response> {
    return json_response(&ObjectBuilder::new()
        .insert("issuer", SELF_BASE)
        .insert("authorization_endpoint", format!("{}/auth", SELF_BASE))
        .insert("jwks_uri", format!("{}/keys.json", SELF_BASE))
        .insert("scopes_supported", vec!["openid", "email"])
        .insert("claims_supported", vec!["aud", "email", "email_verified", "exp", "iat", "iss", "sub"])
        .insert("response_types_supported", vec!["id_token"])
        .insert("response_modes_supported", vec!["form_post"])
        .insert("grant_types_supported", vec!["implicit"])
        .insert("subject_types_supported", vec!["public"])
        .insert("id_token_signing_alg_values_supported", vec!["RS256"])
        .unwrap());
}

fn json_big_num(n: &BigNum) -> String {
    return n.to_vec().to_base64(base64::URL_SAFE);
}

struct PrivKey {
    priv_key: PKey,
}

impl PrivKey {
    fn new(priv_key: PKey) -> PrivKey {
        PrivKey { priv_key: priv_key }
    }
}

impl Handler for PrivKey {
    fn handle(&self, _: &mut Request) -> IronResult<Response> {
        let rsa = self.priv_key.get_rsa();
        return json_response(&ObjectBuilder::new()
            .insert_array("keys", |builder| {
                builder.push_object(|builder| {
                    builder
                        .insert("kty", "RSA")
                        .insert("alg", "RS256")
                        .insert("use", "sig")
                        .insert("kid", "base")
                        .insert("n", json_big_num(&rsa.n().unwrap()))
                        .insert("e", json_big_num(&rsa.e().unwrap()))
            })
        }).unwrap());
    }
}

fn main() {

    let priv_key_file = File::open("private.pem").unwrap();
    let mut reader = BufReader::new(priv_key_file);
    let priv_key = PrivKey::new(PKey::private_key_from_pem(&mut reader).unwrap());

    let mut router = Router::new();
    router.get("/", welcome);
    router.get("/.well-known/openid-configuration", oid_config);
    router.get("/keys.json", priv_key);
    Iron::new(router).http("0.0.0.0:8000").unwrap();

}
<|endoftext|>


<commit_before>fn main() {
    loop {
        let mut line = String::new();
        match std::io::stdin().read_line(&mut line) {
            Ok(0) => break,
            Ok(_) => print!("{}", line),
            Err(error) => print!("{}", error),
        }
    }
}
<commit_msg>Add repl prompt<commit_after>use std::io::Write;

fn main() {
    loop {
        print!("{}", "bf> ");
        std::io::stdout().flush().unwrap();

        let mut line = String::new();
        match std::io::stdin().read_line(&mut line) {
            Ok(0) => break,
            Ok(_) => print!("{}", line),
            Err(error) => print!("{}", error),
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use] extern crate log;
extern crate env_logger;
#[macro_use] extern crate futures;
#[macro_use] extern crate tokio_core;

// pub mod for now until the entire API is used internally
pub mod pool;
mod pipe;

use std::env;
use std::io::{Error, ErrorKind};
use std::net::SocketAddr;
use std::time::Duration;

use futures::{Future};
use futures::stream::Stream;
use tokio_core::reactor::{Core, Timeout};
use tokio_core::net::{TcpListener, TcpStream};
use pool::Pool;

fn main() {
    env_logger::init().unwrap();

    let addr = env::args().nth(1).unwrap_or("127.0.0.1:8080".to_string());
    let addr = addr.parse::<SocketAddr>().unwrap();

    let backend = env::args().nth(2).unwrap_or("127.0.0.1:12345".to_string());
    let mut pool = Pool::new(vec![backend]).unwrap();

    // Create the event loop that will drive this server
    let mut lp = Core::new().unwrap();
    let handle = lp.handle();
    let h2 = handle.clone();
    let h3 = handle.clone();

    // Create a TCP listener which will listen for incoming connections
    let listener = TcpListener::bind(&addr, &handle.clone()).expect("Failed to bind to socket");

    info!("Listening on: {}", addr);

    let proxy = listener.incoming().for_each(|(sock, addr)| {
        debug!("Incoming connection on {}", addr);

        let timeout = match Timeout::new(Duration::from_millis(500), &h3) {
            Ok(t) => t,
            Err(e) => {
                error!("Failed to create connection timeout - {}", e);
                return Ok(())
            }
        };

        // create a timeout future and map it to Err
        // this gives us future that will map to std::result::Result<_, Timeout>
        let connect_timer = futures::finished(timeout).map(Err);

        // TODO turn this into a pool managed by raft
        let backend = pool.get().unwrap();
        let pipe = TcpStream::connect(&backend, &h2)
            // create a stream connect future and map it to Ok
            // this gives us future that will map to std::result::Result<TcpStream, _>
            .map(Ok)

            // this now reads: "A TcpStream future calling select on a Timeout future". the select
            // combinator will return whichever future finishes first _and_ the future that has
            // not finished in the form of a tuple.
            //
            // if we had not wrapped the TcpStream in Ok and the Timeout future in Err, the
            // compiler would have complained that we were trying to return two different types.
            // instead, the select combinator can return the same result enum of
            // Ok((Result<TcpStream, Timeout>, OtherFuture)) or Err((Result<TcpStream, Timeout>, TcpStreamFuture))
            .select(connect_timer)

            // stay with me here. TcpStream itself returns io::Result, so we first need to deal
            // with TcpStream returning Ok. If it does return Ok, then we either have a TcpStream
            // or a Timeout.
            .map(|(res, _)| {
                res
                    .map(|tcp| tcp)
                    .map_err(|_timeout| {
                        Error::new(ErrorKind::TimedOut, "Pool connection timeout")
                    })
            }).map_err(|(e, _)| {
                // this is taking our `(io:Error, Timeout future)` tuple and mapping it to only be
                // `io::Error`. we do this to have a consistent type in `Err` from here on out
                e
            }).and_then(|tcp| {
                // we use this `and_then` to flatten out our result. our call to `.map` above
                // returned either `Ok` or `Err`. we want to chain the ``Ok(TcpStream)` to the next
                // step and send the `Err` down to the `map_err` at the bottom.
                //
                // if we did not do this, then our next `and_then` would have to match on the
                // result and chain the error to the next `and_then` where we could chain the error
                // again. this defeats the purpose of combinators/railroad style dev/etc
                tcp
            }).and_then(move |server| {

                // Pipe implements future. The `Pipe` is hiding away a state machine that is
                // managing non-blocking reads and writes between a client and server.
                //
                // Note: this is a bi-directional pipe. I should probably change the name so I do
                // not confuse people who assume this is a conventional uni-directional pipe.
                pipe::Pipe::new(
                    addr,
                    sock,
                    backend,
                    server
                )

            }).map(|()| {
                // the above `Pipe` implements `Future` with `Item=()`, so that is the value passed
                // to our closure. we could have also returned the total bytes proxied, the time it
                // took, etc

                debug!("Finished proxying");

                // we have to return `()`, which will create a `Future<Item=(), Error=_>` in order
                // for `handle.spawn` to work
                //
                // You can elide `()` as functions return `()` by default. Note: _elide_ is what
                // really smart CS PhD people use to confuse the general masses. The word _elide_
                // means to omit. It is used all over Rust documentation, so now you know.
                ()
            }).map_err(|e| {
                error!("Error trying proxy - {:?}", e);

                // we have to return `()`, which will create a `Future<Item=_, Error=()>` in order
                // for `handle.spawn` to work
                //
                // You can elide `()` as functions return `()` by default. Note: _elide_ is what
                // really smart CS PhD people use to confuse the general masses. The word _elide_
                // means to omit. It is used all over Rust documentation, so now you know.
                ()
            });

        // spawn expects Future<Item=(), Error=()>
        //
        // The `spawn` method adds a future to the event pool. There is no threading going on here.
        // If you are familiar with mio/epoll/kqueue, this is registering with the event loop. G
        handle.spawn(pipe);

        // The `Stream::for_each` combinator will continue passing new connections as long as we
        // return an `Ok(())`. If we return `Err`, then we will abort the loop and our error will
        // show up in the below call to `lp.run(proxy)`
        Ok(())
    });

    // The run method runs a future on the _main_ `Task`. In our case, we are running a Stream that
    // calls the `for_each` combinator. The `for_each` combinator will loop forever until it
    // receives an error. Thus, `lp.run` will only return if it receives an error.
    //
    // If you are wondering where the `Task` was introduced, calling `lp.run` creates one. You can
    // think of a task as a container for one or more futures.
    //
    // Questions:
    // * What does it mean for a future to be pinned to a stack frame? I believe it means the
    // future is owned by the run method.
    // * Based on the above, what does it mean for a non-reference to have `'static` bounds?
    lp.run(proxy).expect("Unexpected error while proxying connection");
}
<commit_msg>Use tokio_timer for connection timeout<commit_after>#[macro_use] extern crate log;
extern crate env_logger;
#[macro_use] extern crate futures;
#[macro_use] extern crate tokio_core;
extern crate tokio_timer;

// pub mod for now until the entire API is used internally
pub mod pool;
mod pipe;

use std::env;
use std::io::{Error, ErrorKind};
use std::net::SocketAddr;
use std::time::Duration;

use futures::{Future};
use futures::stream::Stream;
use tokio_core::reactor::{Core, Timeout};
use tokio_core::net::{TcpListener, TcpStream};
use pool::Pool;

fn main() {
    env_logger::init().unwrap();

    let addr = env::args().nth(1).unwrap_or("127.0.0.1:8080".to_string());
    let addr = addr.parse::<SocketAddr>().unwrap();

    let backend = env::args().nth(2).unwrap_or("127.0.0.1:12345".to_string());
    let mut pool = Pool::new(vec![backend]).unwrap();

    // Create the event loop that will drive this server
    let mut lp = Core::new().unwrap();
    let handle = lp.handle();
    let h2 = handle.clone();
    let h3 = handle.clone();

    // Create a TCP listener which will listen for incoming connections
    let listener = TcpListener::bind(&addr, &handle.clone()).expect("Failed to bind to socket");

    info!("Listening on: {}", addr);

    let proxy = listener.incoming().for_each(|(sock, addr)| {
        debug!("Incoming connection on {}", addr);

        let timeout = match Timeout::new(Duration::from_millis(500), &h3) {
            Ok(t) => t,
            Err(e) => {
                error!("Failed to create connection timeout - {}", e);
                return Ok(())
            }
        };

        // create a timeout future and map it to Err
        // this gives us future that will map to std::result::Result<_, Timeout>
        let connect_timer = timeout.map(Err);

        // TODO turn this into a pool managed by raft
        let backend = pool.get().unwrap();
        let pipe = TcpStream::connect(&backend, &h2)
            // create a stream connect future and map it to Ok
            // this gives us future that will map to std::result::Result<TcpStream, _>
            .map(Ok)

            // this now reads: "A TcpStream future calling select on a Timeout future". the select
            // combinator will return whichever future finishes first _and_ the future that has
            // not finished in the form of a tuple.
            //
            // if we had not wrapped the TcpStream in Ok and the Timeout future in Err, the
            // compiler would have complained that we were trying to return two different types.
            // instead, the select combinator can return the same result enum of
            // Ok((Result<TcpStream, Timeout>, OtherFuture)) or Err((Result<TcpStream, Timeout>, TcpStreamFuture))
            .select(connect_timer)

            // stay with me here. TcpStream itself returns io::Result, so we first need to deal
            // with TcpStream returning Ok. If it does return Ok, then we either have a TcpStream
            // or a Timeout.
            .map(|(res, _)| {
                res
                    .map(|tcp| tcp)
                    .map_err(|_timeout| {
                        Error::new(ErrorKind::TimedOut, "Pool connection timeout")
                    })
            }).map_err(|(e, _)| {
                // this is taking our `(io:Error, Timeout future)` tuple and mapping it to only be
                // `io::Error`. we do this to have a consistent type in `Err` from here on out
                e
            }).and_then(|tcp| {
                // we use this `and_then` to flatten out our result. our call to `.map` above
                // returned either `Ok` or `Err`. we want to chain the ``Ok(TcpStream)` to the next
                // step and send the `Err` down to the `map_err` at the bottom.
                //
                // if we did not do this, then our next `and_then` would have to match on the
                // result and chain the error to the next `and_then` where we could chain the error
                // again. this defeats the purpose of combinators/railroad style dev/etc
                tcp
            }).and_then(move |server| {

                // Pipe implements future. The `Pipe` is hiding away a state machine that is
                // managing non-blocking reads and writes between a client and server.
                //
                // Note: this is a bi-directional pipe. I should probably change the name so I do
                // not confuse people who assume this is a conventional uni-directional pipe.
                pipe::Pipe::new(
                    addr,
                    sock,
                    backend,
                    server
                )

            }).map(|()| {
                // the above `Pipe` implements `Future` with `Item=()`, so that is the value passed
                // to our closure. we could have also returned the total bytes proxied, the time it
                // took, etc

                debug!("Finished proxying");

                // we have to return `()`, which will create a `Future<Item=(), Error=_>` in order
                // for `handle.spawn` to work
                //
                // You can elide `()` as functions return `()` by default. Note: _elide_ is what
                // really smart CS PhD people use to confuse the general masses. The word _elide_
                // means to omit. It is used all over Rust documentation, so now you know.
                ()
            }).map_err(|e| {
                error!("Error trying proxy - {:?}", e);

                // we have to return `()`, which will create a `Future<Item=_, Error=()>` in order
                // for `handle.spawn` to work
                //
                // You can elide `()` as functions return `()` by default. Note: _elide_ is what
                // really smart CS PhD people use to confuse the general masses. The word _elide_
                // means to omit. It is used all over Rust documentation, so now you know.
                ()
            });

        // spawn expects Future<Item=(), Error=()>
        //
        // The `spawn` method adds a future to the event pool. There is no threading going on here.
        // If you are familiar with mio/epoll/kqueue, this is registering with the event loop. G
        handle.spawn(pipe);

        // The `Stream::for_each` combinator will continue passing new connections as long as we
        // return an `Ok(())`. If we return `Err`, then we will abort the loop and our error will
        // show up in the below call to `lp.run(proxy)`
        Ok(())
    });

    // The run method runs a future on the _main_ `Task`. In our case, we are running a Stream that
    // calls the `for_each` combinator. The `for_each` combinator will loop forever until it
    // receives an error. Thus, `lp.run` will only return if it receives an error.
    //
    // If you are wondering where the `Task` was introduced, calling `lp.run` creates one. You can
    // think of a task as a container for one or more futures.
    //
    // Questions:
    // * What does it mean for a future to be pinned to a stack frame? I believe it means the
    // future is owned by the run method.
    // * Based on the above, what does it mean for a non-reference to have `'static` bounds?
    lp.run(proxy).expect("Unexpected error while proxying connection");
}
<|endoftext|>


<commit_before>use self::binary::{builtins, InteractiveShell};
use atty::Stream;
use ion_shell::{BackgroundEvent, BuiltinMap, IonError, PipelineError, Shell, Value};
use liner::KeyBindings;
use nix::{
    sys::signal::{self, SaFlags, SigAction, SigHandler, SigSet, Signal},
    unistd,
};
use std::{
    fs,
    io::{stdin, BufReader},
    process,
    sync::Arc,
};

#[cfg(not(feature = "advanced_arg_parsing"))]
use crate::binary::MAN_ION;
#[cfg(not(feature = "advanced_arg_parsing"))]
use std::env;
#[cfg(feature = "advanced_arg_parsing")]
use std::str::FromStr;
#[cfg(feature = "advanced_arg_parsing")]
use structopt::StructOpt;

mod binary;

struct KeyBindingsWrapper(KeyBindings);

#[cfg(feature = "advanced_arg_parsing")]
impl FromStr for KeyBindingsWrapper {
    type Err = String;

    fn from_str(input: &str) -> Result<Self, Self::Err> {
        match input {
            "vi" => Ok(KeyBindingsWrapper(KeyBindings::Vi)),
            "emacs" => Ok(KeyBindingsWrapper(KeyBindings::Emacs)),
            _ => Err("unknown key bindings".to_string()),
        }
    }
}

/// The fast, safe, modern rust shell.
/// Ion is a commandline shell created to be a faster and easier to use
/// alternative to the currently available shells. It is not POSIX compliant.
#[cfg_attr(feature = "advanced_arg_parsing", derive(StructOpt))]
#[cfg_attr(feature = "advanced_arg_parsing", structopt(name = "Ion"))]
struct CommandLineArgs {
    /// Shortcut layout. Valid options: "vi", "emacs"
    #[cfg_attr(feature = "advanced_arg_parsing", structopt(short = "-o"))]
    key_bindings:     Option<KeyBindingsWrapper>,
    /// Print commands before execution
    #[cfg_attr(feature = "advanced_arg_parsing", structopt(short = "-x"))]
    print_commands:   bool,
    /// Use a fake interactive mode, where errors don't exit the shell
    #[cfg_attr(
        feature = "advanced_arg_parsing",
        structopt(short = "-f", long = "--fake-interactive")
    )]
    fake_interactive: bool,
    /// Force interactive mode
    #[cfg_attr(feature = "advanced_arg_parsing", structopt(short = "-i", long = "--interactive"))]
    interactive:      bool,
    /// Do not execute any commands, perform only syntax checking
    #[cfg_attr(feature = "advanced_arg_parsing", structopt(short = "-n", long = "--no-execute"))]
    no_execute:       bool,
    /// Evaluate given commands instead of reading from the commandline
    #[cfg_attr(feature = "advanced_arg_parsing", structopt(short = "-c"))]
    command:          Option<String>,
    /// Print the version, platform and revision of Ion then exit
    #[cfg_attr(feature = "advanced_arg_parsing", structopt(short = "-v", long = "--version"))]
    version:          bool,
    /// Script arguments (@args). If the -c option is not specified,
    /// the first parameter is taken as a filename to execute
    #[cfg_attr(feature = "advanced_arg_parsing", structopt())]
    args:             Vec<String>,
}

fn version() -> String { include!(concat!(env!("OUT_DIR"), "/version_string")).to_string() }

#[cfg(feature = "advanced_arg_parsing")]
fn parse_args() -> CommandLineArgs { CommandLineArgs::from_args() }

#[cfg(not(feature = "advanced_arg_parsing"))]
fn parse_args() -> CommandLineArgs {
    let mut args = env::args().skip(1);
    let mut command = None;
    let mut key_bindings = None;
    let mut no_execute = false;
    let mut print_commands = false;
    let mut interactive = false;
    let mut fake_interactive = false;
    let mut version = false;
    let mut additional_arguments = Vec::new();

    while let Some(arg) = args.next() {
        match arg.as_str() {
            "-o" => {
                key_bindings = match args.next().as_ref().map(|s| s.as_str()) {
                    Some("vi") => Some(KeyBindingsWrapper(KeyBindings::Vi)),
                    Some("emacs") => Some(KeyBindingsWrapper(KeyBindings::Emacs)),
                    Some(_) => {
                        eprintln!("ion: invalid option for option -o");
                        process::exit(1);
                    }
                    None => {
                        eprintln!("ion: no option given for option -o");
                        process::exit(1);
                    }
                }
            }
            "-x" => print_commands = true,
            "-n" | "--no-execute" => no_execute = true,
            "-c" => command = args.next(),
            "-v" | "--version" => version = true,
            "-h" | "--help" => {
                println!("{}", MAN_ION);
                process::exit(0);
            }
            "-i" | "--interactive" => interactive = true,
            "-f" | "--fake-interactive" => fake_interactive = true,
            _ => {
                additional_arguments.push(arg);
            }
        }
    }
    CommandLineArgs {
        key_bindings,
        print_commands,
        interactive,
        fake_interactive,
        no_execute,
        command,
        version,
        args: additional_arguments,
    }
}

fn set_unique_pid() -> nix::Result<()> {
    let pgid = unistd::getpid();
    if pgid != unistd::getpgrp() {
        unistd::setpgid(pgid, pgid)?;
    }
    if pgid != unistd::tcgetpgrp(nix::libc::STDIN_FILENO)? {
        unsafe { signal::signal(Signal::SIGTTOU, SigHandler::SigIgn) }?;
        unistd::tcsetpgrp(nix::libc::STDIN_FILENO, pgid)?;
    }
    Ok(())
}

fn main() {
    let command_line_args = parse_args();

    if command_line_args.version {
        println!("{}", version());
        return;
    }

    let mut builtins = BuiltinMap::default();
    builtins
        .with_unsafe()
        .add("debug", &builtins::builtin_debug, "Toggle debug mode (print commands on exec)")
        .add("exec", &builtins::builtin_exec, "Replace the shell with the given command.")
        .add("exit", &builtins::builtin_exit, "Exits the current session")
        .add("suspend", &builtins::builtin_suspend, "Suspends the shell with a SIGTSTOP signal");

    let stdin_is_a_tty = atty::is(Stream::Stdin);
    let mut shell = Shell::with_builtins(builtins);

    if stdin_is_a_tty {
        if let Err(err) = set_unique_pid() {
            println!("ion: could not bring shell to foreground: {}", err);
        }
    }

    shell.set_background_event(Some(Arc::new(|njob, pid, kind| match kind {
        BackgroundEvent::Added => eprintln!("ion: bg [{}] {}", njob, pid),
        BackgroundEvent::Stopped => eprintln!("ion: ([{}] {}) Stopped", njob, pid),
        BackgroundEvent::Resumed => eprintln!("ion: ([{}] {}) Running", njob, pid),
        BackgroundEvent::Exited(status) => {
            eprintln!("ion: ([{}] {}) exited with {}", njob, pid, status)
        }
        BackgroundEvent::Errored(error) => {
            eprintln!("ion: ([{}] {}) errored: {}", njob, pid, error)
        }
    })));

    shell.opts_mut().no_exec = command_line_args.no_execute;
    shell.opts_mut().grab_tty = stdin_is_a_tty;
    if command_line_args.print_commands {
        shell.set_pre_command(Some(Box::new(|_shell, pipeline| {
            // A string representing the command is stored here.
            eprintln!("> {}", pipeline);
        })));
    }

    let script_path = command_line_args.args.get(0).cloned();
    shell.variables_mut().set(
        "args",
        Value::Array(
            if script_path.is_some() {
                command_line_args.args
            } else {
                vec![std::env::args().next().unwrap()]
            }
            .into_iter()
            .map(|arg| Value::Str(arg.into()))
            .collect(),
        ),
    );

    let err = if let Some(command) = command_line_args.command {
        shell.execute_command(command.as_bytes())
    } else if let Some(path) = script_path {
        match fs::File::open(&path) {
            Ok(script) => shell.execute_command(std::io::BufReader::new(script)),
            Err(cause) => {
                println!("ion: could not execute '{}': {}", path, cause);
                process::exit(1);
            }
        }
    } else if stdin_is_a_tty || command_line_args.interactive {
        let mut interactive = InteractiveShell::new(shell);
        if let Some(key_bindings) = command_line_args.key_bindings {
            interactive.set_keybindings(key_bindings.0);
        }
        interactive.add_callbacks();
        interactive.execute_interactive();
    } else if command_line_args.fake_interactive {
        let mut reader = BufReader::new(stdin());
        loop {
            if let Err(err) = shell.execute_command(&mut reader) {
                eprintln!("ion: {}", err);
            }
        }
    } else {
        shell.execute_command(BufReader::new(stdin()))
    }
    .and_then(|_| shell.wait_for_background().map_err(Into::into));
    if let Err(IonError::PipelineExecutionError(PipelineError::Interrupted(_, signal))) = err {
        // When the job was aborted because of an interrupt signal, abort with this same signal
        let action = SigAction::new(SigHandler::SigDfl, SaFlags::empty(), SigSet::empty());
        let _ = unsafe { nix::sys::signal::sigaction(signal, &action) };
        let _ = nix::sys::signal::raise(signal);
    }
    if let Err(why) = err {
        eprintln!("ion: {}", why);
        process::exit(1);
    }
    process::exit(shell.previous_status().as_os_code());
}
<commit_msg>fix: tests with structopt<commit_after>use self::binary::{builtins, InteractiveShell};
use atty::Stream;
use ion_shell::{BackgroundEvent, BuiltinMap, IonError, PipelineError, Shell, Value};
use liner::KeyBindings;
use nix::{
    sys::signal::{self, SaFlags, SigAction, SigHandler, SigSet, Signal},
    unistd,
};
use std::{
    fs,
    io::{stdin, BufReader},
    process,
    sync::Arc,
};

#[cfg(not(feature = "advanced_arg_parsing"))]
use crate::binary::MAN_ION;
#[cfg(not(feature = "advanced_arg_parsing"))]
use std::env;
#[cfg(feature = "advanced_arg_parsing")]
use std::str::FromStr;
#[cfg(feature = "advanced_arg_parsing")]
use structopt::StructOpt;

mod binary;

struct KeyBindingsWrapper(KeyBindings);

#[cfg(feature = "advanced_arg_parsing")]
impl FromStr for KeyBindingsWrapper {
    type Err = String;

    fn from_str(input: &str) -> Result<Self, Self::Err> {
        match input {
            "vi" => Ok(KeyBindingsWrapper(KeyBindings::Vi)),
            "emacs" => Ok(KeyBindingsWrapper(KeyBindings::Emacs)),
            _ => Err("unknown key bindings".to_string()),
        }
    }
}

/// The fast, safe, modern rust shell.
/// Ion is a commandline shell created to be a faster and easier to use
/// alternative to the currently available shells. It is not POSIX compliant.
#[cfg_attr(feature = "advanced_arg_parsing", derive(StructOpt))]
#[cfg_attr(feature = "advanced_arg_parsing", structopt(name = "ion"))]
struct CommandLineArgs {
    /// Shortcut layout. Valid options: "vi", "emacs"
    #[cfg_attr(feature = "advanced_arg_parsing", structopt(short = "-o"))]
    key_bindings:     Option<KeyBindingsWrapper>,
    /// Print commands before execution
    #[cfg_attr(feature = "advanced_arg_parsing", structopt(short = "-x"))]
    print_commands:   bool,
    /// Use a fake interactive mode, where errors don't exit the shell
    #[cfg_attr(
        feature = "advanced_arg_parsing",
        structopt(short = "-f", long = "--fake-interactive")
    )]
    fake_interactive: bool,
    /// Force interactive mode
    #[cfg_attr(feature = "advanced_arg_parsing", structopt(short = "-i", long = "--interactive"))]
    interactive:      bool,
    /// Do not execute any commands, perform only syntax checking
    #[cfg_attr(feature = "advanced_arg_parsing", structopt(short = "-n", long = "--no-execute"))]
    no_execute:       bool,
    /// Evaluate given commands instead of reading from the commandline
    #[cfg_attr(feature = "advanced_arg_parsing", structopt(short = "-c"))]
    command:          Option<String>,
    /// Print the version, platform and revision of Ion then exit
    #[cfg_attr(feature = "advanced_arg_parsing", structopt(short = "-v", long = "--version"))]
    version:          bool,
    /// Script arguments (@args). If the -c option is not specified,
    /// the first parameter is taken as a filename to execute
    #[cfg_attr(feature = "advanced_arg_parsing", structopt())]
    args:             Vec<String>,
}

fn version() -> String { include!(concat!(env!("OUT_DIR"), "/version_string")).to_string() }

#[cfg(feature = "advanced_arg_parsing")]
fn parse_args() -> CommandLineArgs { CommandLineArgs::from_args() }

#[cfg(not(feature = "advanced_arg_parsing"))]
fn parse_args() -> CommandLineArgs {
    let mut args = env::args().skip(1);
    let mut command = None;
    let mut key_bindings = None;
    let mut no_execute = false;
    let mut print_commands = false;
    let mut interactive = false;
    let mut fake_interactive = false;
    let mut version = false;
    let mut additional_arguments = Vec::new();

    while let Some(arg) = args.next() {
        match arg.as_str() {
            "-o" => {
                key_bindings = match args.next().as_ref().map(|s| s.as_str()) {
                    Some("vi") => Some(KeyBindingsWrapper(KeyBindings::Vi)),
                    Some("emacs") => Some(KeyBindingsWrapper(KeyBindings::Emacs)),
                    Some(_) => {
                        eprintln!("ion: invalid option for option -o");
                        process::exit(1);
                    }
                    None => {
                        eprintln!("ion: no option given for option -o");
                        process::exit(1);
                    }
                }
            }
            "-x" => print_commands = true,
            "-n" | "--no-execute" => no_execute = true,
            "-c" => command = args.next(),
            "-v" | "--version" => version = true,
            "-h" | "--help" => {
                println!("{}", MAN_ION);
                process::exit(0);
            }
            "-i" | "--interactive" => interactive = true,
            "-f" | "--fake-interactive" => fake_interactive = true,
            _ => {
                additional_arguments.push(arg);
            }
        }
    }
    CommandLineArgs {
        key_bindings,
        print_commands,
        interactive,
        fake_interactive,
        no_execute,
        command,
        version,
        args: additional_arguments,
    }
}

fn set_unique_pid() -> nix::Result<()> {
    let pgid = unistd::getpid();
    if pgid != unistd::getpgrp() {
        unistd::setpgid(pgid, pgid)?;
    }
    if pgid != unistd::tcgetpgrp(nix::libc::STDIN_FILENO)? {
        unsafe { signal::signal(Signal::SIGTTOU, SigHandler::SigIgn) }?;
        unistd::tcsetpgrp(nix::libc::STDIN_FILENO, pgid)?;
    }
    Ok(())
}

fn main() {
    let command_line_args = parse_args();

    if command_line_args.version {
        println!("{}", version());
        return;
    }

    let mut builtins = BuiltinMap::default();
    builtins
        .with_unsafe()
        .add("debug", &builtins::builtin_debug, "Toggle debug mode (print commands on exec)")
        .add("exec", &builtins::builtin_exec, "Replace the shell with the given command.")
        .add("exit", &builtins::builtin_exit, "Exits the current session")
        .add("suspend", &builtins::builtin_suspend, "Suspends the shell with a SIGTSTOP signal");

    let stdin_is_a_tty = atty::is(Stream::Stdin);
    let mut shell = Shell::with_builtins(builtins);

    if stdin_is_a_tty {
        if let Err(err) = set_unique_pid() {
            println!("ion: could not bring shell to foreground: {}", err);
        }
    }

    shell.set_background_event(Some(Arc::new(|njob, pid, kind| match kind {
        BackgroundEvent::Added => eprintln!("ion: bg [{}] {}", njob, pid),
        BackgroundEvent::Stopped => eprintln!("ion: ([{}] {}) Stopped", njob, pid),
        BackgroundEvent::Resumed => eprintln!("ion: ([{}] {}) Running", njob, pid),
        BackgroundEvent::Exited(status) => {
            eprintln!("ion: ([{}] {}) exited with {}", njob, pid, status)
        }
        BackgroundEvent::Errored(error) => {
            eprintln!("ion: ([{}] {}) errored: {}", njob, pid, error)
        }
    })));

    shell.opts_mut().no_exec = command_line_args.no_execute;
    shell.opts_mut().grab_tty = stdin_is_a_tty;
    if command_line_args.print_commands {
        shell.set_pre_command(Some(Box::new(|_shell, pipeline| {
            // A string representing the command is stored here.
            eprintln!("> {}", pipeline);
        })));
    }

    let script_path = command_line_args.args.get(0).cloned();
    shell.variables_mut().set(
        "args",
        Value::Array(
            if script_path.is_some() {
                command_line_args.args
            } else {
                vec![std::env::args().next().unwrap()]
            }
            .into_iter()
            .map(|arg| Value::Str(arg.into()))
            .collect(),
        ),
    );

    let err = if let Some(command) = command_line_args.command {
        shell.execute_command(command.as_bytes())
    } else if let Some(path) = script_path {
        match fs::File::open(&path) {
            Ok(script) => shell.execute_command(std::io::BufReader::new(script)),
            Err(cause) => {
                println!("ion: could not execute '{}': {}", path, cause);
                process::exit(1);
            }
        }
    } else if stdin_is_a_tty || command_line_args.interactive {
        let mut interactive = InteractiveShell::new(shell);
        if let Some(key_bindings) = command_line_args.key_bindings {
            interactive.set_keybindings(key_bindings.0);
        }
        interactive.add_callbacks();
        interactive.execute_interactive();
    } else if command_line_args.fake_interactive {
        let mut reader = BufReader::new(stdin());
        loop {
            if let Err(err) = shell.execute_command(&mut reader) {
                eprintln!("ion: {}", err);
            }
        }
    } else {
        shell.execute_command(BufReader::new(stdin()))
    }
    .and_then(|_| shell.wait_for_background().map_err(Into::into));
    if let Err(IonError::PipelineExecutionError(PipelineError::Interrupted(_, signal))) = err {
        // When the job was aborted because of an interrupt signal, abort with this same signal
        let action = SigAction::new(SigHandler::SigDfl, SaFlags::empty(), SigSet::empty());
        let _ = unsafe { nix::sys::signal::sigaction(signal, &action) };
        let _ = nix::sys::signal::raise(signal);
    }
    if let Err(why) = err {
        eprintln!("ion: {}", why);
        process::exit(1);
    }
    process::exit(shell.previous_status().as_os_code());
}
<|endoftext|>