<commit_before>extern crate env_logger;
extern crate getopts;
extern crate iron;
extern crate mote;
extern crate rgb;
extern crate router;
extern crate scroll_phat_hd;
extern crate serde_json;
extern crate staticfile;
extern crate unicase;
extern crate url;

#[macro_use]
extern crate log;

#[macro_use]
extern crate serde_derive;

#[macro_use]
extern crate maplit;

use std::env;
use std::io::Read;
use std::sync::{Arc, Mutex};
use std::thread;
use std::time;

use getopts::Options;
use iron::headers::{AccessControlAllowHeaders, AccessControlAllowOrigin, ContentType};
use iron::middleware::Handler;
use iron::prelude::{IronResult, Request, Response};
use iron::prelude::*;
use iron::status;
use router::Router;
use unicase::UniCase;

mod google_actions;
use google_actions::{ActionRequest, ExecuteResponse, ExecuteResponsePayload, QueryResponse,
                     QueryResponsePayload, SyncResponse, SyncResponsePayload};

mod light;
use light::{Light, LightMode, LightStatus, LightType};

mod thermostat;
use thermostat::{TemperatureUnit, Thermostat, ThermostatMode, ThermostatStatus};

mod scene;
use scene::Scene;

mod device;
use device::Device;

mod color;

mod oauth;

const BLACK: rgb::RGB8 = rgb::RGB8 { r: 0, g: 0, b: 0 };

struct Hub {
    devices: Vec<Arc<Mutex<Device>>>,
}

impl Handler for Hub {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        info!("hub handler");
        let mut body = String::new();
        req.body.read_to_string(&mut body).unwrap();
        let action_request: ActionRequest = serde_json::from_str(&body).unwrap();

        info!("action_request: {:?}", action_request);

        for input in action_request.inputs {
            match input.intent.as_ref() {
                "action.devices.SYNC" => {
                    let mut response = SyncResponse {
                        request_id: action_request.request_id.clone(),
                        payload: SyncResponsePayload {
                            agent_user_id: "1111".to_string(),
                            devices: vec![],
                        },
                    };

                    for device in &self.devices {
                        let device = device.lock().unwrap();
                        response.payload.devices.push(device.sync().unwrap());
                    }

                    let res = serde_json::to_string(&response).unwrap_or("".to_string());
                    debug!("action_response: {:?}", res);
                    let mut rsp = Response::with((status::Ok, res));
                    rsp.headers.set(ContentType::json());
                    // For browser access.
                    rsp.headers.set(AccessControlAllowOrigin::Any);
                    return Ok(rsp);
                }
                "action.devices.QUERY" => {
                    let mut response = QueryResponse {
                        request_id: action_request.request_id.clone(),
                        payload: QueryResponsePayload {
                            devices: btreemap!{},
                        },
                    };

                    if let Some(payload) = input.payload {
                        for request_device in payload.devices {
                            for device in &self.devices {
                                let device = device.lock().unwrap();
                                if request_device.id == device.id() {
                                    response
                                        .payload
                                        .devices
                                        .insert(device.id(), device.query().unwrap());
                                }
                            }
                            // TODO: Always send to all proxies.
                        }
                    }

                    let res = serde_json::to_string(&response).unwrap_or("".to_string());
                    debug!("action_response: {:?}", res);
                    let mut rsp = Response::with((status::Ok, res));
                    rsp.headers.set(ContentType::json());
                    // For browser access.
                    rsp.headers.set(AccessControlAllowOrigin::Any);
                    return Ok(rsp);
                }
                "action.devices.EXECUTE" => {
                    let mut response = ExecuteResponse {
                        request_id: action_request.request_id.clone(),
                        payload: ExecuteResponsePayload {
                            error_code: None,
                            debug_string: None,
                            commands: vec![],
                        },
                    };

                    if let Some(ref p) = input.payload {
                        for command in &p.commands {
                            debug!("command: {:?}", command);
                            for execution in &command.execution {
                                debug!("execution: {:?}", execution);
                                for request_device in &command.devices {
                                    debug!("request_device: {:?}", request_device);
                                    for device in &self.devices {
                                        let mut device = device.lock().unwrap();
                                        if request_device.id == device.id() {
                                            response
                                                .payload
                                                .commands
                                                .push(device.execute(&execution.params).unwrap());
                                        }
                                    }
                                    // TODO: Always send to all proxies.
                                }
                            }
                        }
                    }

                    let res = serde_json::to_string(&response).unwrap_or("".to_string());
                    debug!("action_response: {:?}", res);
                    let mut rsp = Response::with((status::Ok, res));
                    rsp.headers.set(ContentType::json());
                    // For browser access.
                    rsp.headers.set(AccessControlAllowOrigin::Any);
                    return Ok(rsp);
                }
                i => {
                    debug!("unsupported intent: {:?}", i);
                }
            }
        }

        let mut rsp = Response::with((status::Ok, "ACTION"));
        rsp.headers.set(ContentType::json());
        // For browser access.
        rsp.headers.set(AccessControlAllowOrigin::Any);
        Ok(rsp)
    }
}

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

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

    let mut opts = Options::new();
    opts.optopt("", "http_address", "HTTP address to listen on", "ADDRESS");
    opts.optopt("", "index", "file to serve as index", "FILE");
    opts.optopt("", "mote_dev", "Serial port connecting to Mote", "FILE");
    opts.optopt("", "display_i2c", "I2C port to use as display", "N");

    debug!("parsing args");
    let matches = opts.parse(&args[1..]).unwrap();
    let http_address = matches
        .opt_str("http_address")
        .unwrap_or("0.0.0.0:1234".to_string());
    let index = matches.opt_str("index").unwrap_or("/dev/null".to_string());
    let mote_dev = matches
        .opt_str("mote_dev")
        .unwrap_or("/dev/ttyACM0".to_string());
    let display_i2c = matches.opt_str("display_i2c").unwrap_or("".to_string());
    debug!("args parsed");

    let bedroom_lights = Arc::new(Mutex::new(Light {
        id: "111".to_string(),
        name: "Bedroom lights".to_string(),
        status: LightStatus::default(),
        type_: LightType::Light,
        available_light_modes: vec![
            LightMode::OnOff,
            LightMode::Brightness,
            LightMode::ColorSpectrum,
        ],
        color_func: Box::new(color::SolidColor { c: BLACK }),
    }));

    let kitchen_lights = Arc::new(Mutex::new(Light {
        id: "222".to_string(),
        name: "Kitchen lights".to_string(),
        status: LightStatus::default(),
        type_: LightType::Light,
        available_light_modes: vec![
            LightMode::OnOff,
            LightMode::Brightness,
            LightMode::ColorSpectrum,
        ],
        color_func: Box::new(color::SolidColor { c: BLACK }),
    }));

    let bathroom_lights = Arc::new(Mutex::new(Light {
        id: "333".to_string(),
        name: "Bathroom lights".to_string(),
        status: LightStatus::default(),
        type_: LightType::Light,
        available_light_modes: vec![
            LightMode::OnOff,
            LightMode::Brightness,
            LightMode::ColorSpectrum,
        ],
        color_func: Box::new(color::SolidColor { c: BLACK }),
    }));

    let living_room_lights = Arc::new(Mutex::new(Light {
        id: "444".to_string(),
        name: "Living Room lights".to_string(),
        status: LightStatus::default(),
        type_: LightType::Light,
        available_light_modes: vec![
            LightMode::OnOff,
            LightMode::Brightness,
            LightMode::ColorSpectrum,
        ],
        color_func: Box::new(color::SolidColor { c: BLACK }),
    }));

    let all_lights = vec![
        bedroom_lights.clone(),
        kitchen_lights.clone(),
        bathroom_lights.clone(),
        living_room_lights.clone(),
    ];

    let party_mode = Arc::new(Mutex::new(Scene {
        id: "1001".to_string(),
        name: "Party mode".to_string(),
        reversible: true,
        lights: all_lights.clone(),
    }));

    let italian_mode = Arc::new(Mutex::new(Scene {
        id: "1002".to_string(),
        name: "Italian Mode".to_string(),
        reversible: true,
        lights: all_lights.clone(),
    }));

    let night_mode = Arc::new(Mutex::new(Scene {
        id: "1003".to_string(),
        name: "Night Mode".to_string(),
        reversible: true,
        lights: all_lights.clone(),
    }));

    let strobe_mode = Arc::new(Mutex::new(Scene {
        id: "1004".to_string(),
        name: "Strobe Mode".to_string(),
        reversible: true,
        lights: all_lights.clone(),
    }));

    let thermostat = Arc::new(Mutex::new(Thermostat {
        id: "66".to_string(),
        name: "Thermostat".to_string(),
        available_thermostat_modes: vec![ThermostatMode::Off, ThermostatMode::Heat],
        thermostat_temperature_unit: TemperatureUnit::C,
        status: ThermostatStatus {
            mode: ThermostatMode::Off,
            temperature_setpoint: 21.0,
            temperature_ambient: 20.0,
            temperature_setpoint_low: 10.0,
            temperature_setpoint_high: 30.0,
            humidity_ambient: 50.0,
        },
    }));

    let hub = Hub {
        devices: vec![
            bedroom_lights.clone(),
            kitchen_lights.clone(),
            bathroom_lights.clone(),
            living_room_lights.clone(),
            party_mode.clone(),
            italian_mode.clone(),
            night_mode.clone(),
            strobe_mode.clone(),
            thermostat.clone(),
        ],
    };

    thread::spawn(move || {
        let mut mote = mote::Mote::new(&mote_dev, true);

        let mut pixels = [BLACK; 16 * 4];
        let mut t = 0u64;

        fn update_lights(
            pixels: &mut [rgb::RGB8; 16 * 4],
            t: u64,
            lights: &Arc<Mutex<Light>>,
            offset: usize,
        ) {
            match lights.lock() {
                Ok(lights) => for i in 0..16 {
                    let b0 = &pixels.clone()[offset..offset + 16];
                    let b1 = lights.color_func.step(t, b0);
                    pixels[i + offset] = b1[i];
                },
                Err(err) => error!("could not lock light mutex: {:?}", err),
            }
        }

        loop {
            update_lights(&mut pixels, t, &bedroom_lights, 0);
            update_lights(&mut pixels, t, &kitchen_lights, 16);
            update_lights(&mut pixels, t, &bathroom_lights, 32);
            update_lights(&mut pixels, t, &living_room_lights, 48);
            mote.write(&pixels);

            thread::sleep(time::Duration::from_millis(10));
            t += 1;
        }
    });

    thread::spawn(move || {
        let mut display: Box<scroll_phat_hd::display::Display> = if display_i2c == "" {
            Box::new(scroll_phat_hd::display::UnicodeDisplay::new())
        } else {
            // TODO: Parse I2C port.
            Box::new(scroll_phat_hd::display::I2CDisplay::new(1))
        };

        let mut scroller = scroll_phat_hd::scroller::Scroller::new(&mut *display);

        loop {
            {
                match thermostat.lock() {
                    Ok(thermostat) => {
                        match thermostat.status.mode {
                            thermostat::ThermostatMode::Off => {
                                scroller.set_text("--°C");
                                scroller.show();
                            }
                            _ => {
                                scroller.set_text(&format!(
                                    "{}°C",
                                    thermostat.status.temperature_setpoint
                                ));
                                scroller.show();
                            }
                        };
                    }
                    Err(err) => {
                        error!("could not lock thermostat mutex: {:?}", err);
                    }
                };
            }

            thread::sleep(time::Duration::from_millis(100));
        }
    });

    let oauth = oauth::OAuth::new();
    let mut control = Router::new();
    control
        .get("/auth", oauth.auth, "auth")
        .post("/token", oauth.token, "token")
        .get("/login", oauth.login, "login")
        .post("/action", hub, "post action")
        .get("/action", get_action_handler, "get action")
        .options("/action", options_action_handler, "get action")
        .get("/", staticfile::Static::new(index), "index");
    info!("Listening on {}", http_address);
    Iron::new(control).http(http_address).unwrap();
}

fn get_action_handler(_: &mut Request) -> IronResult<Response> {
    Ok(Response::with((status::Ok, "get action")))
}

fn options_action_handler(_: &mut Request) -> IronResult<Response> {
    let mut rsp = Response::with((status::Ok, "options"));
    rsp.headers.set(AccessControlAllowOrigin::Any);
    rsp.headers.set(AccessControlAllowHeaders(vec![
        UniCase("Content-Type".to_string()),
    ]));
    Ok(rsp)
}
<commit_msg>Simplify loop<commit_after>extern crate env_logger;
extern crate getopts;
extern crate iron;
extern crate mote;
extern crate rgb;
extern crate router;
extern crate scroll_phat_hd;
extern crate serde_json;
extern crate staticfile;
extern crate unicase;
extern crate url;

#[macro_use]
extern crate log;

#[macro_use]
extern crate serde_derive;

#[macro_use]
extern crate maplit;

use std::env;
use std::io::Read;
use std::sync::{Arc, Mutex};
use std::thread;
use std::time;

use getopts::Options;
use iron::headers::{AccessControlAllowHeaders, AccessControlAllowOrigin, ContentType};
use iron::middleware::Handler;
use iron::prelude::{IronResult, Request, Response};
use iron::prelude::*;
use iron::status;
use router::Router;
use unicase::UniCase;

mod google_actions;
use google_actions::{ActionRequest, ExecuteResponse, ExecuteResponsePayload, QueryResponse,
                     QueryResponsePayload, SyncResponse, SyncResponsePayload};

mod light;
use light::{Light, LightMode, LightStatus, LightType};

mod thermostat;
use thermostat::{TemperatureUnit, Thermostat, ThermostatMode, ThermostatStatus};

mod scene;
use scene::Scene;

mod device;
use device::Device;

mod color;

mod oauth;

const BLACK: rgb::RGB8 = rgb::RGB8 { r: 0, g: 0, b: 0 };

struct Hub {
    devices: Vec<Arc<Mutex<Device>>>,
}

impl Handler for Hub {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        info!("hub handler");
        let mut body = String::new();
        req.body.read_to_string(&mut body).unwrap();
        let action_request: ActionRequest = serde_json::from_str(&body).unwrap();

        info!("action_request: {:?}", action_request);

        for input in action_request.inputs {
            match input.intent.as_ref() {
                "action.devices.SYNC" => {
                    let mut response = SyncResponse {
                        request_id: action_request.request_id.clone(),
                        payload: SyncResponsePayload {
                            agent_user_id: "1111".to_string(),
                            devices: vec![],
                        },
                    };

                    for device in &self.devices {
                        let device = device.lock().unwrap();
                        response.payload.devices.push(device.sync().unwrap());
                    }

                    let res = serde_json::to_string(&response).unwrap_or("".to_string());
                    debug!("action_response: {:?}", res);
                    let mut rsp = Response::with((status::Ok, res));
                    rsp.headers.set(ContentType::json());
                    // For browser access.
                    rsp.headers.set(AccessControlAllowOrigin::Any);
                    return Ok(rsp);
                }
                "action.devices.QUERY" => {
                    let mut response = QueryResponse {
                        request_id: action_request.request_id.clone(),
                        payload: QueryResponsePayload {
                            devices: btreemap!{},
                        },
                    };

                    if let Some(payload) = input.payload {
                        for request_device in payload.devices {
                            for device in &self.devices {
                                let device = device.lock().unwrap();
                                if request_device.id == device.id() {
                                    response
                                        .payload
                                        .devices
                                        .insert(device.id(), device.query().unwrap());
                                }
                            }
                            // TODO: Always send to all proxies.
                        }
                    }

                    let res = serde_json::to_string(&response).unwrap_or("".to_string());
                    debug!("action_response: {:?}", res);
                    let mut rsp = Response::with((status::Ok, res));
                    rsp.headers.set(ContentType::json());
                    // For browser access.
                    rsp.headers.set(AccessControlAllowOrigin::Any);
                    return Ok(rsp);
                }
                "action.devices.EXECUTE" => {
                    let mut response = ExecuteResponse {
                        request_id: action_request.request_id.clone(),
                        payload: ExecuteResponsePayload {
                            error_code: None,
                            debug_string: None,
                            commands: vec![],
                        },
                    };

                    if let Some(ref p) = input.payload {
                        for command in &p.commands {
                            debug!("command: {:?}", command);
                            for execution in &command.execution {
                                debug!("execution: {:?}", execution);
                                for request_device in &command.devices {
                                    debug!("request_device: {:?}", request_device);
                                    for device in &self.devices {
                                        let mut device = device.lock().unwrap();
                                        if request_device.id == device.id() {
                                            response
                                                .payload
                                                .commands
                                                .push(device.execute(&execution.params).unwrap());
                                        }
                                    }
                                    // TODO: Always send to all proxies.
                                }
                            }
                        }
                    }

                    let res = serde_json::to_string(&response).unwrap_or("".to_string());
                    debug!("action_response: {:?}", res);
                    let mut rsp = Response::with((status::Ok, res));
                    rsp.headers.set(ContentType::json());
                    // For browser access.
                    rsp.headers.set(AccessControlAllowOrigin::Any);
                    return Ok(rsp);
                }
                i => {
                    debug!("unsupported intent: {:?}", i);
                }
            }
        }

        let mut rsp = Response::with((status::Ok, "ACTION"));
        rsp.headers.set(ContentType::json());
        // For browser access.
        rsp.headers.set(AccessControlAllowOrigin::Any);
        Ok(rsp)
    }
}

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

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

    let mut opts = Options::new();
    opts.optopt("", "http_address", "HTTP address to listen on", "ADDRESS");
    opts.optopt("", "index", "file to serve as index", "FILE");
    opts.optopt("", "mote_dev", "Serial port connecting to Mote", "FILE");
    opts.optopt("", "display_i2c", "I2C port to use as display", "N");

    debug!("parsing args");
    let matches = opts.parse(&args[1..]).unwrap();
    let http_address = matches
        .opt_str("http_address")
        .unwrap_or("0.0.0.0:1234".to_string());
    let index = matches.opt_str("index").unwrap_or("/dev/null".to_string());
    let mote_dev = matches
        .opt_str("mote_dev")
        .unwrap_or("/dev/ttyACM0".to_string());
    let display_i2c = matches.opt_str("display_i2c").unwrap_or("".to_string());
    debug!("args parsed");

    let bedroom_lights = Arc::new(Mutex::new(Light {
        id: "111".to_string(),
        name: "Bedroom lights".to_string(),
        status: LightStatus::default(),
        type_: LightType::Light,
        available_light_modes: vec![
            LightMode::OnOff,
            LightMode::Brightness,
            LightMode::ColorSpectrum,
        ],
        color_func: Box::new(color::SolidColor { c: BLACK }),
    }));

    let kitchen_lights = Arc::new(Mutex::new(Light {
        id: "222".to_string(),
        name: "Kitchen lights".to_string(),
        status: LightStatus::default(),
        type_: LightType::Light,
        available_light_modes: vec![
            LightMode::OnOff,
            LightMode::Brightness,
            LightMode::ColorSpectrum,
        ],
        color_func: Box::new(color::SolidColor { c: BLACK }),
    }));

    let bathroom_lights = Arc::new(Mutex::new(Light {
        id: "333".to_string(),
        name: "Bathroom lights".to_string(),
        status: LightStatus::default(),
        type_: LightType::Light,
        available_light_modes: vec![
            LightMode::OnOff,
            LightMode::Brightness,
            LightMode::ColorSpectrum,
        ],
        color_func: Box::new(color::SolidColor { c: BLACK }),
    }));

    let living_room_lights = Arc::new(Mutex::new(Light {
        id: "444".to_string(),
        name: "Living Room lights".to_string(),
        status: LightStatus::default(),
        type_: LightType::Light,
        available_light_modes: vec![
            LightMode::OnOff,
            LightMode::Brightness,
            LightMode::ColorSpectrum,
        ],
        color_func: Box::new(color::SolidColor { c: BLACK }),
    }));

    let all_lights = vec![
        bedroom_lights.clone(),
        kitchen_lights.clone(),
        bathroom_lights.clone(),
        living_room_lights.clone(),
    ];

    let party_mode = Arc::new(Mutex::new(Scene {
        id: "1001".to_string(),
        name: "Party mode".to_string(),
        reversible: true,
        lights: all_lights.clone(),
    }));

    let italian_mode = Arc::new(Mutex::new(Scene {
        id: "1002".to_string(),
        name: "Italian Mode".to_string(),
        reversible: true,
        lights: all_lights.clone(),
    }));

    let night_mode = Arc::new(Mutex::new(Scene {
        id: "1003".to_string(),
        name: "Night Mode".to_string(),
        reversible: true,
        lights: all_lights.clone(),
    }));

    let strobe_mode = Arc::new(Mutex::new(Scene {
        id: "1004".to_string(),
        name: "Strobe Mode".to_string(),
        reversible: true,
        lights: all_lights.clone(),
    }));

    let thermostat = Arc::new(Mutex::new(Thermostat {
        id: "66".to_string(),
        name: "Thermostat".to_string(),
        available_thermostat_modes: vec![ThermostatMode::Off, ThermostatMode::Heat],
        thermostat_temperature_unit: TemperatureUnit::C,
        status: ThermostatStatus {
            mode: ThermostatMode::Off,
            temperature_setpoint: 21.0,
            temperature_ambient: 20.0,
            temperature_setpoint_low: 10.0,
            temperature_setpoint_high: 30.0,
            humidity_ambient: 50.0,
        },
    }));

    let hub = Hub {
        devices: vec![
            bedroom_lights.clone(),
            kitchen_lights.clone(),
            bathroom_lights.clone(),
            living_room_lights.clone(),
            party_mode.clone(),
            italian_mode.clone(),
            night_mode.clone(),
            strobe_mode.clone(),
            thermostat.clone(),
        ],
    };

    thread::spawn(move || {
        let mut mote = mote::Mote::new(&mote_dev, true);

        let mut pixels = [BLACK; 16 * 4];
        let mut t = 0u64;

        fn update_lights(
            pixels: &mut [rgb::RGB8; 16 * 4],
            t: u64,
            lights: &Arc<Mutex<Light>>,
            offset: usize,
        ) {
            match lights.lock() {
                Ok(lights) => for i in 0..16 {
                    let b0 = &pixels.clone()[offset..offset + 16];
                    let b1 = lights.color_func.step(t, b0);
                    pixels[i + offset] = b1[i];
                },
                Err(err) => error!("could not lock light mutex: {:?}", err),
            }
        }

        loop {
            update_lights(&mut pixels, t, &bedroom_lights, 0);
            update_lights(&mut pixels, t, &kitchen_lights, 16);
            update_lights(&mut pixels, t, &bathroom_lights, 32);
            update_lights(&mut pixels, t, &living_room_lights, 48);
            mote.write(&pixels);

            thread::sleep(time::Duration::from_millis(10));
            t += 1;
        }
    });

    thread::spawn(move || {
        let mut display: Box<scroll_phat_hd::display::Display> = if display_i2c == "" {
            Box::new(scroll_phat_hd::display::UnicodeDisplay::new())
        } else {
            // TODO: Parse I2C port.
            Box::new(scroll_phat_hd::display::I2CDisplay::new(1))
        };

        let mut scroller = scroll_phat_hd::scroller::Scroller::new(&mut *display);

        loop {
            match thermostat.lock() {
                Ok(thermostat) => {
                    match thermostat.status.mode {
                        thermostat::ThermostatMode::Off => {
                            scroller.set_text("--°C");
                            scroller.show();
                        }
                        _ => {
                            scroller.set_text(&format!(
                                "{}°C",
                                thermostat.status.temperature_setpoint
                            ));
                            scroller.show();
                        }
                    };
                }
                Err(err) => {
                    error!("could not lock thermostat mutex: {:?}", err);
                }
            };

            thread::sleep(time::Duration::from_millis(100));
        }
    });

    let oauth = oauth::OAuth::new();
    let mut control = Router::new();
    control
        .get("/auth", oauth.auth, "auth")
        .post("/token", oauth.token, "token")
        .get("/login", oauth.login, "login")
        .post("/action", hub, "post action")
        .get("/action", get_action_handler, "get action")
        .options("/action", options_action_handler, "get action")
        .get("/", staticfile::Static::new(index), "index");
    info!("Listening on {}", http_address);
    Iron::new(control).http(http_address).unwrap();
}

fn get_action_handler(_: &mut Request) -> IronResult<Response> {
    Ok(Response::with((status::Ok, "get action")))
}

fn options_action_handler(_: &mut Request) -> IronResult<Response> {
    let mut rsp = Response::with((status::Ok, "options"));
    rsp.headers.set(AccessControlAllowOrigin::Any);
    rsp.headers.set(AccessControlAllowHeaders(vec![
        UniCase("Content-Type".to_string()),
    ]));
    Ok(rsp)
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate rusqlite;
#[macro_use]

extern crate rustc_serialize;

mod loader;
mod db;
mod dbFsDirType;
mod dbFsDir;
mod dbFsFile;
mod dbProvider;
mod dbJob;
mod dbJobProvide;
mod dbJobDepend;
mod dbVariableName;
mod dbJobRequireVariable;
mod dbVariablePair;
mod dbJobRequireVariablePair;
mod json_loader_elephant;
mod cli_clap;
mod jobs_load;
mod elephant;
mod dbSession;
mod dbEnviroment;

fn main() {
    let conn = db::connect();
    db::create_tables(&conn);

    let clp_matches = cli_clap::cli_clap(&conn);
    loader::deligate(&conn, clp_matches);

    jobs_load::load(&conn);
}
<commit_msg>reorganise<commit_after>extern crate clap;
extern crate rusqlite;
#[macro_use]

extern crate rustc_serialize;

mod loader;
mod db;
mod dbFsDirType;
mod dbFsDir;
mod dbFsFile;
mod dbProvider;
mod dbJob;
mod dbJobProvide;
mod dbJobDepend;
mod dbVariableName;
mod dbJobRequireVariable;
mod dbVariablePair;
mod dbJobRequireVariablePair;
mod json_loader_elephant;
mod cli_clap;
mod jobs_load;
mod elephant;
mod dbSession;
mod dbEnviroment;

fn main() {
    let conn = db::connect();
    let session_uuid = "".to_string();
    db::create_tables(&conn);

    let some_value = 10;
    let clp_matches = cli_clap::cli_clap(&some_value);
    loader::deligate(&conn, clp_matches.clone());
    let pk_session = elephant::elephant_session(&conn, &session_uuid);
    loader::enviroment(&conn, pk_session, clp_matches);
    jobs_load::load(&conn);
}
<|endoftext|>


<commit_before>extern crate walkdir;

use std::ffi::OsString;
use std::env;
use std::path::PathBuf;
use std::process::Command;
use walkdir::{DirEntry, WalkDir, WalkDirIterator};

struct MultiCmd {
    command: Command,
    banner: String,
    top_directory: PathBuf,
    directories: Vec<PathBuf>,
}

impl MultiCmd {
    fn new(cmd: &str, args: Vec<String>) -> Self {

        let mut command = Command::new(cmd);
        let mut banner = String::from("Executing ");
        banner.push_str(cmd);
        for arg in args {
            command.arg(OsString::from(&arg));
            banner = banner + " " + &arg;
        }

        MultiCmd {
            command: command,
            banner: banner,
            top_directory: PathBuf::new(),
            directories: Vec::new(),
        }
    }

    fn set_top_dir(&mut self, dir: PathBuf) -> &mut Self {
        self.top_directory = dir;
        self
    }

    fn collect_crate_candidates(&mut self) -> &mut Self {
        self.directories = WalkDir::new(&self.top_directory)
                               .min_depth(1)
                               .max_depth(1)
                               .into_iter()
                               .filter_entry(|e| is_crate(e))
                               .map(|e| e.ok().unwrap().path().to_path_buf())
                               .collect::<Vec<_>>();
        self
    }

    fn announce(&self) -> &Self {
        let mut line = String::new();
        for _ in 0..self.banner.len() {
            line.push('-');
        }
        println!("{}", line);
        println!("{}", self.banner);
        println!("{}", line);
        self
    }

    fn dispatch(&mut self) -> &Self {
        for dir in &self.directories {
            println!("{}:", dir.display());
            let out = self.command
                          .current_dir(dir)
                          .output()
                          .unwrap_or_else(|e| panic!("failed to execute process: {}", e));
            if out.status.success() {
                print_ident(out.stdout);
            } else {
                print_ident(out.stderr);
            }
            println!("");
        }
        self
    }
}

fn print_ident(buf: Vec<u8>)
{
    // ::<'a>(v: &'a [u8])
    for line in String::from_utf8_lossy(&buf[..]).lines() {
        println!("        {}", line);
    }
}

fn is_crate(entry: &DirEntry) -> bool {
    entry.path().join("Cargo.toml").exists()
}

fn main() {
    let args = env::args().skip(2).collect();
    let cwd = env::current_dir().unwrap();
    let mut multi = MultiCmd::new("cargo", args);

    multi.set_top_dir(cwd);
    multi.collect_crate_candidates();
    multi.announce();
    multi.dispatch();
}
<commit_msg>Small optimization<commit_after>extern crate walkdir;

use std::ffi::OsString;
use std::env;
use std::path::PathBuf;
use std::process::Command;
use walkdir::{DirEntry, WalkDir, WalkDirIterator};

struct MultiCmd {
    command: Command,
    banner: String,
    top_directory: PathBuf,
    directories: Vec<PathBuf>,
}

impl MultiCmd {
    fn new(cmd: &str, args: Vec<String>) -> Self {

        let mut command = Command::new(cmd);
        let mut banner = String::from("Executing ") + &cmd ;
        for arg in args {
            command.arg(OsString::from(&arg));
            banner = banner + " " + &arg;
        }

        MultiCmd {
            command: command,
            banner: banner,
            top_directory: PathBuf::new(),
            directories: Vec::new(),
        }
    }

    fn set_top_dir(&mut self, dir: PathBuf) -> &mut Self {
        self.top_directory = dir;
        self
    }

    fn collect_crate_candidates(&mut self) -> &mut Self {
        self.directories = WalkDir::new(&self.top_directory)
                               .min_depth(1)
                               .max_depth(1)
                               .into_iter()
                               .filter_entry(|e| is_crate(e))
                               .map(|e| e.ok().unwrap().path().to_path_buf())
                               .collect::<Vec<_>>();
        self
    }

    fn announce(&self) -> &Self {
        let mut line = String::new();
        for _ in 0..self.banner.len() {
            line.push('-');
        }
        println!("{}", line);
        println!("{}", self.banner);
        println!("{}", line);
        self
    }

    fn dispatch(&mut self) -> &Self {
        for dir in &self.directories {
            println!("{}:", dir.display());
            let out = self.command
                          .current_dir(dir)
                          .output()
                          .unwrap_or_else(|e| panic!("failed to execute process: {}", e));
            if out.status.success() {
                print_ident(out.stdout);
            } else {
                print_ident(out.stderr);
            }
            println!("");
        }
        self
    }
}

fn print_ident(buf: Vec<u8>)
{
    // ::<'a>(v: &'a [u8])
    for line in String::from_utf8_lossy(&buf[..]).lines() {
        println!("        {}", line);
    }
}

fn is_crate(entry: &DirEntry) -> bool {
    entry.path().join("Cargo.toml").exists()
}

fn main() {
    let args = env::args().skip(2).collect();
    let cwd = env::current_dir().unwrap();
    let mut multi = MultiCmd::new("cargo", args);

    multi.set_top_dir(cwd);
    multi.collect_crate_candidates();
    multi.announce();
    multi.dispatch();
}
<|endoftext|>


<commit_before>extern crate ar;
extern crate clap;
extern crate libflate;
extern crate tar;
extern crate tempfile;
extern crate time as crates_time;
extern crate xz2;
extern crate zip;

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

use std::rc::Rc;
use std::vec::Vec;

use clap::{Arg, App};

use libflate::gzip;
use tempfile::tempfile;

// magic:
use std::io::Seek;
use std::io::Write;

#[derive(Debug)]
struct Node<T> {
    next: Option<Rc<Node<T>>>,
    value: T,
}

impl<T: Clone> Node<T> {
    fn head(obj: T) -> Rc<Node<T>> {
        Rc::new(Node {
            next: None,
            value: obj,
        })
    }

    fn plus(what: &Rc<Node<T>>, obj: T) -> Rc<Node<T>> {
        Rc::new(Node {
            next: Some(what.clone()),
            value: obj
        })
    }

    fn to_vec(&self) -> Vec<T> {
        let mut ret = Vec::new();
        let mut val = self;
        loop {
            ret.push(val.value.clone());
            if let Some(ref next) = val.next {
                val = next;
            } else {
                break;
            }
        }
        ret.reverse();
        ret
    }
}

struct OutputTo {
    path: Rc<Node<String>>,
    size: u64,
    atime: u64,
    mtime: u64,
    ctime: u64,
    btime: u64,
}

impl OutputTo {
    fn warn(&self, msg: String) {
        writeln!(io::stderr(), "TODO: {}", msg).expect("stderr");
    }

    fn raw<F: io::Read>(&self, mut file: &mut F) -> io::Result<()> {
        let stdout = io::stdout();
        let mut stdout = stdout.lock();
        writeln!(stdout, "{:?} {} {} {} {} {}",
            self.path.to_vec(),
            self.size,
            self.atime, self.mtime, self.ctime, self.btime
        )?;

        io::copy(&mut file, &mut stdout).and_then(move |written|
            if written != self.size {
                Err(io::Error::new(
                    io::ErrorKind::UnexpectedEof,
                    format!("expecting to write {} but wrote {}", self.size, written)))
            } else {
                Ok(())
            })
    }
}

impl OutputTo {
    fn from_file(path: &str, fd: &fs::File) -> io::Result<OutputTo> {
        let meta = fd.metadata()?;
        Ok(OutputTo {
            path: Node::head(path.to_string()),
            size: meta.len(),
            atime: meta.accessed().map(simple_time_sys)?,
            mtime: meta.modified().map(simple_time_sys)?,
            ctime: simple_time_ctime(&meta),
            btime: simple_time_btime(&meta)?,
        })
    }

    fn with_path(&self, path: &str) -> OutputTo {
        OutputTo {
            path: Node::plus(&self.path, path.to_string()),
            size: 0,
            atime: 0,
            mtime: 0,
            ctime: 0,
            btime: 0,
        }
    }
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum FileType {
    GZip,
    Zip,
    Tar,
    Ar,
    BZip2,
    Xz,
    Other,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum Status {
    Done,
    Rewind,
}

fn read_octal(bytes: &[u8]) -> Option<u32> {
    let mut start = 0;
    while start < bytes.len() && b' ' == bytes[start] {
        start += 1;
    }

    let mut end = bytes.len() - 1;
    while end > start && (b' ' == bytes[end] || 0 == bytes[end]) {
        end -= 1;
    }

    if let Ok(string) = std::str::from_utf8(&bytes[start..(end+1)]) {
        if let Ok(val) = u32::from_str_radix(string, 8) {
            return Some(val);
        }
    }
    None
}

fn simple_time(dur: time::Duration) -> u64 {
    dur.as_secs().checked_mul(1_000_000_000)
        .map_or(0, |nanos| nanos + dur.subsec_nanos() as u64)
}

fn simple_time_sys(val: time::SystemTime) -> u64 {
    val.duration_since(time::UNIX_EPOCH).map(simple_time).unwrap_or(0)
}

fn simple_time_tm(val: crates_time::Tm) -> u64 {
    let timespec = val.to_timespec();
    simple_time(time::Duration::new(timespec.sec as u64, timespec.nsec as u32))
}

fn simple_time_btime(val: &fs::Metadata) -> io::Result<u64> {
    match val.created() {
        Ok(time) => Ok(simple_time_sys(time)),
        // "Other" is how "unsupported" is represented here; ew.
        Err(ref e) if e.kind() == io::ErrorKind::Other => Ok(0),
        Err(other) => Err(other),
    }
}

// TODO: I really feel this should be exposed by Rust, without cfg.
fn simple_time_ctime(val: &fs::Metadata) -> u64 {
    #[cfg(linux)] {
        use std::os::linux::fs::MetadataExt;
        let ctime: i64 = val.st_ctime();
        if ctime <= 0 {
            0
        } else {
            ctime as u64
        }
    }

    #[cfg(not(linux))] {
        0
    }
}

fn is_probably_tar(header: &[u8]) -> bool {
    if header.len() < 512 {
        return false;
    }

    if let Some(checksum) = read_octal(&header[148..156]) {
        let mut sum: u32 = (b' ' as u32) * 8;
        for i in 0..148 {
            sum += header[i] as u32;
        }
        for i in 156..512 {
            sum += header[i] as u32;
        }

        if checksum == sum {
            return true;
        }
    }

    return false;
}

fn identify<'a>(fd: &mut Box<io::BufRead + 'a>) -> io::Result<FileType> {
    let header = fd.fill_buf()?;
    if header.len() >= 20
        && 0x1f == header[0] && 0x8b == header[1] {
        Ok(FileType::GZip)
   } else if header.len() >= 152
        && b'P' == header[0] && b'K' == header[1]
        && 0x03 == header[2] && 0x04 == header[3] {
        Ok(FileType::Zip)
    } else if header.len() > 257 + 10
        && b'u' == header[257] && b's' == header[258]
        && b't' == header[259] && b'a' == header[260]
        && b'r' == header[261]
        && (
            (0 == header[262] && b'0' == header[263] && b'0' == header[264]) ||
            (b' ' == header[262] && b' ' == header[263] && 0 == header[264])
        ) {
        Ok(FileType::Tar)
    } else if header.len() > 8
        && b'!' == header[0] && b'<' == header[1]
        && b'a' == header[2] && b'r' == header[3]
        && b'c' == header[4] && b'h' == header[5]
        && b'>' == header[6] && b'\n' == header[7] {
        Ok(FileType::Ar)
    } else if header.len() > 40
        && b'B' == header[0] && b'Z' == header[1]
        && b'h' == header[2] && 0x31 == header[3]
        && 0x41 == header[4] && 0x59 == header[5]
        && 0x26 == header[6] {
        Ok(FileType::BZip2)
    } else if header.len() > 6
        && 0xfd == header[0] && b'7' == header[1]
        && b'z' == header[2] && b'X' == header[3]
        && b'Z' == header[4] && 0 == header[5] {
        Ok(FileType::Xz)
    } else if is_probably_tar(header) {
        Ok(FileType::Tar)
    } else {
        Ok(FileType::Other)
    }
}

struct BoxReader<'a> {
    fd: Box<io::BufRead + 'a>
}

impl<'a> io::Read for BoxReader<'a> {
    fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize> {
        self.fd.read(&mut buf)
    }
}

fn count_bytes<'a, R: io::Read>(mut fd: &mut R) -> io::Result<u64> {
    let mut block = [0u8; 4096];
    let mut count = 0u64;
    loop {
        let found = fd.read(&mut block[..])?;
        if 0 == found {
            break;
        }
        count += found as u64;
    }
    Ok(count)
}

fn unpack_or_raw<'a, F>(
    fd: Box<io::BufRead + 'a>,
    output: &OutputTo,
    fun: F) -> io::Result<Status>
where F: FnOnce(Box<io::BufRead + 'a>) -> io::Result<Box<io::BufRead + 'a>>
{
    match fun(fd) {
        Ok(inner) => unpack(inner, output),
        Err(e) => {
            output.warn(format!(
                    "thought we could unpack '{:?}' but we couldn't: {}",
                    output.path, e));
            Ok(Status::Rewind)
        }
    }
}

fn unpack<'a>(mut fd: Box<io::BufRead + 'a>, output: &OutputTo) -> io::Result<Status> {
    match identify(&mut fd)? {
        FileType::GZip => {
            unpack_or_raw(fd, output,
                |fd| gzip::Decoder::new(fd).map(
                    |dec| Box::new(io::BufReader::new(dec)) as Box<io::BufRead>))
        },
        FileType::Xz => {
            unpack_or_raw(fd, output,
                |fd| Ok(Box::new(io::BufReader::new(xz2::bufread::XzDecoder::new(fd)))))
        },
        FileType::Ar if output.path.value.ends_with(".deb") => {
            let mut decoder = ar::Archive::new(fd);
            while let Some(entry) = decoder.next_entry() {
                let entry = entry?;
                let new_output = output.with_path(entry.header().identifier());
                unpack(Box::new(io::BufReader::new(entry)), &new_output)?;
            }
            Ok(Status::Done)
        },
        FileType::Tar => {
            let mut decoder = tar::Archive::new(fd);
            for entry in decoder.entries()? {
                let entry = entry?;
                let new_output = output.with_path(entry.path()?.to_str().expect("valid utf-8"));
                unpack(Box::new(io::BufReader::new(entry)), &new_output)?;
            }
            Ok(Status::Done)
        },
        FileType::Zip => {
            let mut temp = tempfile()?;
            io::copy(&mut BoxReader { fd }, &mut temp)?;
            let mut zip = zip::ZipArchive::new(temp)?;

            for i in 0..zip.len() {

                // well, this has gone rather poorly
                let mut new_output = output.with_path(zip.by_index(i)?.name());

                let file_result = {
                    let entry = zip.by_index(i)?;

                    new_output.size = entry.size();
                    new_output.mtime = simple_time_tm(entry.last_modified());
                    let reader = Box::new(io::BufReader::new(entry));
                    unpack(reader, &new_output)?
                };
                match file_result {
                    Status::Done => (),
                    Status::Rewind => {
                        // TODO: update output? ? handling? ???
                        new_output.raw(&mut zip.by_index(i)?)?
                    },
                };
            }

            Ok(Status::Done)
        },

        // TODO: unimplemented!()
        _ => {
            Ok(Status::Rewind)
        },
    }
}

fn output_raw(file: &mut fs::File, output: &OutputTo) -> io::Result<()> {
    file.seek(io::SeekFrom::Start(0))?;
    output.raw(file)?;
    Ok(())
}

fn process_real_path(path: &str) -> io::Result<()> {
    let mut file = fs::File::open(path).unwrap();
    let output = OutputTo::from_file(
        path,
        &file
    )?;

    let attempt = {
        let read = io::BufReader::new(&file);
        unpack(Box::new(read), &output)
    };

    match attempt {
        Ok(Status::Done) => Ok(()),
        Ok(Status::Rewind) => output_raw(&mut file, &output),
        Err(e) => Err(e)
    }
}

fn real_main() -> u8 {

    let matches = App::new("contentin")
                    .arg(Arg::with_name("to-tar")
                         .long("to-tar")
                         .help("emit a tar file")
                         .required(true))
                    .arg(Arg::with_name("INPUT")
                         .required(true)
                         .multiple(true))
                    .get_matches();

    for path in matches.values_of("INPUT").unwrap() {
        if let Err(e) = process_real_path(path) {
            if let Err(_) = writeln!(io::stderr(), "fatal: processing '{}': {}", path, e) {
                return 6;
            }

            return 4;
        }
    }
    return 0;
}

fn main() {
    std::process::exit(real_main() as i32)
}
<commit_msg>Tee trait?<commit_after>extern crate ar;
extern crate clap;
extern crate libflate;
extern crate tar;
extern crate tempfile;
extern crate time as crates_time;
extern crate xz2;
extern crate zip;

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

use std::rc::Rc;
use std::vec::Vec;

use clap::{Arg, App};

use libflate::gzip;
use tempfile::tempfile;

// magic:
use std::io::Seek;
use std::io::Write;

#[derive(Debug)]
struct Node<T> {
    next: Option<Rc<Node<T>>>,
    value: T,
}

impl<T: Clone> Node<T> {
    fn head(obj: T) -> Rc<Node<T>> {
        Rc::new(Node {
            next: None,
            value: obj,
        })
    }

    fn plus(what: &Rc<Node<T>>, obj: T) -> Rc<Node<T>> {
        Rc::new(Node {
            next: Some(what.clone()),
            value: obj
        })
    }

    fn to_vec(&self) -> Vec<T> {
        let mut ret = Vec::new();
        let mut val = self;
        loop {
            ret.push(val.value.clone());
            if let Some(ref next) = val.next {
                val = next;
            } else {
                break;
            }
        }
        ret.reverse();
        ret
    }
}

struct OutputTo {
    path: Rc<Node<String>>,
    size: u64,
    atime: u64,
    mtime: u64,
    ctime: u64,
    btime: u64,
}

impl OutputTo {
    fn warn(&self, msg: String) {
        writeln!(io::stderr(), "TODO: {}", msg).expect("stderr");
    }

    fn raw<F: io::Read>(&self, mut file: &mut F) -> io::Result<()> {
        let stdout = io::stdout();
        let mut stdout = stdout.lock();
        writeln!(stdout, "{:?} {} {} {} {} {}",
            self.path.to_vec(),
            self.size,
            self.atime, self.mtime, self.ctime, self.btime
        )?;

        io::copy(&mut file, &mut stdout).and_then(move |written|
            if written != self.size {
                Err(io::Error::new(
                    io::ErrorKind::UnexpectedEof,
                    format!("expecting to write {} but wrote {}", self.size, written)))
            } else {
                Ok(())
            })
    }

    fn from_file(path: &str, fd: &fs::File) -> io::Result<OutputTo> {
        let meta = fd.metadata()?;
        Ok(OutputTo {
            path: Node::head(path.to_string()),
            size: meta.len(),
            atime: meta.accessed().map(simple_time_sys)?,
            mtime: meta.modified().map(simple_time_sys)?,
            ctime: simple_time_ctime(&meta),
            btime: simple_time_btime(&meta)?,
        })
    }

    fn with_path(&self, path: &str) -> OutputTo {
        OutputTo {
            path: Node::plus(&self.path, path.to_string()),
            size: 0,
            atime: 0,
            mtime: 0,
            ctime: 0,
            btime: 0,
        }
    }
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum FileType {
    GZip,
    Zip,
    Tar,
    Ar,
    BZip2,
    Xz,
    Other,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum Status {
    Done,
    Rewind,
}

fn read_octal(bytes: &[u8]) -> Option<u32> {
    let mut start = 0;
    while start < bytes.len() && b' ' == bytes[start] {
        start += 1;
    }

    let mut end = bytes.len() - 1;
    while end > start && (b' ' == bytes[end] || 0 == bytes[end]) {
        end -= 1;
    }

    if let Ok(string) = std::str::from_utf8(&bytes[start..(end+1)]) {
        if let Ok(val) = u32::from_str_radix(string, 8) {
            return Some(val);
        }
    }
    None
}

fn simple_time(dur: time::Duration) -> u64 {
    dur.as_secs().checked_mul(1_000_000_000)
        .map_or(0, |nanos| nanos + dur.subsec_nanos() as u64)
}

fn simple_time_sys(val: time::SystemTime) -> u64 {
    val.duration_since(time::UNIX_EPOCH).map(simple_time).unwrap_or(0)
}

fn simple_time_tm(val: crates_time::Tm) -> u64 {
    let timespec = val.to_timespec();
    simple_time(time::Duration::new(timespec.sec as u64, timespec.nsec as u32))
}

fn simple_time_btime(val: &fs::Metadata) -> io::Result<u64> {
    match val.created() {
        Ok(time) => Ok(simple_time_sys(time)),
        // "Other" is how "unsupported" is represented here; ew.
        Err(ref e) if e.kind() == io::ErrorKind::Other => Ok(0),
        Err(other) => Err(other),
    }
}

// TODO: I really feel this should be exposed by Rust, without cfg.
fn simple_time_ctime(val: &fs::Metadata) -> u64 {
    #[cfg(linux)] {
        use std::os::linux::fs::MetadataExt;
        let ctime: i64 = val.st_ctime();
        if ctime <= 0 {
            0
        } else {
            ctime as u64
        }
    }

    #[cfg(not(linux))] {
        0
    }
}

fn is_probably_tar(header: &[u8]) -> bool {
    if header.len() < 512 {
        return false;
    }

    if let Some(checksum) = read_octal(&header[148..156]) {
        let mut sum: u32 = (b' ' as u32) * 8;
        for i in 0..148 {
            sum += header[i] as u32;
        }
        for i in 156..512 {
            sum += header[i] as u32;
        }

        if checksum == sum {
            return true;
        }
    }

    return false;
}

fn identify<'a, T: io::BufRead + ?Sized>(fd: &mut Box<T>) -> io::Result<FileType> {
    let header = fd.fill_buf()?;
    if header.len() >= 20
        && 0x1f == header[0] && 0x8b == header[1] {
        Ok(FileType::GZip)
   } else if header.len() >= 152
        && b'P' == header[0] && b'K' == header[1]
        && 0x03 == header[2] && 0x04 == header[3] {
        Ok(FileType::Zip)
    } else if header.len() > 257 + 10
        && b'u' == header[257] && b's' == header[258]
        && b't' == header[259] && b'a' == header[260]
        && b'r' == header[261]
        && (
            (0 == header[262] && b'0' == header[263] && b'0' == header[264]) ||
            (b' ' == header[262] && b' ' == header[263] && 0 == header[264])
        ) {
        Ok(FileType::Tar)
    } else if header.len() > 8
        && b'!' == header[0] && b'<' == header[1]
        && b'a' == header[2] && b'r' == header[3]
        && b'c' == header[4] && b'h' == header[5]
        && b'>' == header[6] && b'\n' == header[7] {
        Ok(FileType::Ar)
    } else if header.len() > 40
        && b'B' == header[0] && b'Z' == header[1]
        && b'h' == header[2] && 0x31 == header[3]
        && 0x41 == header[4] && 0x59 == header[5]
        && 0x26 == header[6] {
        Ok(FileType::BZip2)
    } else if header.len() > 6
        && 0xfd == header[0] && b'7' == header[1]
        && b'z' == header[2] && b'X' == header[3]
        && b'Z' == header[4] && 0 == header[5] {
        Ok(FileType::Xz)
    } else if is_probably_tar(header) {
        Ok(FileType::Tar)
    } else {
        Ok(FileType::Other)
    }
}

trait Tee: io::BufRead {
}

impl<T: io::Read> Tee for io::BufReader<T> {

}

fn count_bytes<'a, R: io::Read>(mut fd: &mut R) -> io::Result<u64> {
    let mut block = [0u8; 4096];
    let mut count = 0u64;
    loop {
        let found = fd.read(&mut block[..])?;
        if 0 == found {
            break;
        }
        count += found as u64;
    }
    Ok(count)
}

fn unpack_or_raw<'a, F>(
    fd: Box<Tee + 'a>,
    output: &OutputTo,
    fun: F) -> io::Result<Status>
where F: FnOnce(Box<Tee + 'a>) -> io::Result<Box<Tee + 'a>>
{
    match fun(fd) {
        Ok(inner) => unpack(inner, output),
        Err(e) => {
            output.warn(format!(
                    "thought we could unpack '{:?}' but we couldn't: {}",
                    output.path, e));
            Ok(Status::Rewind)
        }
    }
}

fn unpack<'a>(mut fd: Box<Tee + 'a>, output: &OutputTo) -> io::Result<Status> {
    match identify(&mut fd)? {
        FileType::GZip => {
            unpack_or_raw(fd, output,
                |fd| gzip::Decoder::new(fd).map(
                    |dec| Box::new(io::BufReader::new(dec)) as Box<Tee>))
        },
        FileType::Xz => {
            unpack_or_raw(fd, output,
                |fd| Ok(Box::new(io::BufReader::new(xz2::bufread::XzDecoder::new(fd)))))
        },
        FileType::Ar if output.path.value.ends_with(".deb") => {
            let mut decoder = ar::Archive::new(fd);
            while let Some(entry) = decoder.next_entry() {
                let entry = entry?;
                let new_output = output.with_path(entry.header().identifier());
                unpack(Box::new(io::BufReader::new(entry)), &new_output)?;
            }
            Ok(Status::Done)
        },
        FileType::Tar => {
            let mut decoder = tar::Archive::new(fd);
            for entry in decoder.entries()? {
                let entry = entry?;
                let new_output = output.with_path(entry.path()?.to_str().expect("valid utf-8"));
                unpack(Box::new(io::BufReader::new(entry)), &new_output)?;
            }
            Ok(Status::Done)
        },
        FileType::Zip => {
            let mut temp = tempfile()?;
            io::copy(&mut fd, &mut temp)?;
            let mut zip = zip::ZipArchive::new(temp)?;

            for i in 0..zip.len() {

                // well, this has gone rather poorly
                let mut new_output = output.with_path(zip.by_index(i)?.name());

                let file_result = {
                    let entry = zip.by_index(i)?;

                    new_output.size = entry.size();
                    new_output.mtime = simple_time_tm(entry.last_modified());
                    let reader = Box::new(io::BufReader::new(entry));
                    unpack(reader, &new_output)?
                };
                match file_result {
                    Status::Done => (),
                    Status::Rewind => {
                        // TODO: update output? ? handling? ???
                        new_output.raw(&mut zip.by_index(i)?)?
                    },
                };
            }

            Ok(Status::Done)
        },

        // TODO: unimplemented!()
        _ => {
            Ok(Status::Rewind)
        },
    }
}

fn output_raw(file: &mut fs::File, output: &OutputTo) -> io::Result<()> {
    file.seek(io::SeekFrom::Start(0))?;
    output.raw(file)?;
    Ok(())
}

fn process_real_path(path: &str) -> io::Result<()> {
    let mut file = fs::File::open(path).unwrap();
    let output = OutputTo::from_file(
        path,
        &file
    )?;

    let attempt = {
        let read = io::BufReader::new(&file);
        unpack(Box::new(read), &output)
    };

    match attempt {
        Ok(Status::Done) => Ok(()),
        Ok(Status::Rewind) => output_raw(&mut file, &output),
        Err(e) => Err(e)
    }
}

fn real_main() -> u8 {

    let matches = App::new("contentin")
                    .arg(Arg::with_name("to-tar")
                         .long("to-tar")
                         .help("emit a tar file")
                         .required(true))
                    .arg(Arg::with_name("INPUT")
                         .required(true)
                         .multiple(true))
                    .get_matches();

    for path in matches.values_of("INPUT").unwrap() {
        if let Err(e) = process_real_path(path) {
            if let Err(_) = writeln!(io::stderr(), "fatal: processing '{}': {}", path, e) {
                return 6;
            }

            return 4;
        }
    }
    return 0;
}

fn main() {
    std::process::exit(real_main() as i32)
}
<|endoftext|>


<commit_before>#![allow(unused_assignments)]
#![feature(slicing_syntax)]

extern crate toml;
extern crate glob;

use std::io::fs::PathExtensions;
use std::io::fs;
use std::io;
use std::os;

use app_result::{AppResult, app_err};
use dependencies::read_dependencies;
use types::{TagsRoot, TagsKind};

use tags::{
   update_tags,
   update_tags_and_check_for_reexports,
   create_tags,
   merge_tags
};

use dirs::rusty_tags_dir;

mod app_result;
mod dependencies;
mod dirs;
mod tags;
mod types;

fn main()
{
   let args = os::args();
   let tags_kind =
      if args.len() == 2 {
         match args[1].as_slice() {
            "vi"    => Some(TagsKind::Vi),
            "emacs" => Some(TagsKind::Emacs),
            _       => None
         }
      }
      else {
         None
      };

   if let Some(tkind) = tags_kind {
      update_all_tags(&tkind).unwrap_or_else(|err| {
         let stderr = &mut io::stderr();
         let _ = writeln!(stderr, "rusty-tags: {:?}", err);
         os::set_exit_status(1);
      });
   }
   else {
      println!("Usage:
   rusty-tags vi
   rusty-tags emacs");
   }
}

fn update_all_tags(tags_kind: &TagsKind) -> AppResult<()>
{
   let cwd = try!(os::getcwd());
   let cargo_dir = try!(find_cargo_toml_dir(&cwd));
   let tags_roots = try!(read_dependencies(&cargo_dir));

   let rust_std_lib_tags_file = try!(rust_std_lib_tags_file(tags_kind));

   for tags_root in tags_roots.iter() {
      let mut tag_files: Vec<Path> = Vec::new();
      let mut tag_dir: Option<Path> = None;

      match *tags_root {
         TagsRoot::Src { ref src_dir, ref dependencies } => {
            let mut src_tags = src_dir.clone();
            src_tags.push(tags_kind.tags_file_name());
            try!(create_tags(tags_kind, src_dir, &src_tags));
            tag_files.push(src_tags);

            for dep in dependencies.iter() {
               tag_files.push(try!(update_tags(tags_kind, dep)).tags_file);
            }

            tag_dir = Some(src_dir.clone());
         },

         TagsRoot::Lib { ref src_kind, ref dependencies } => {
            let lib_tags = try!(update_tags_and_check_for_reexports(tags_kind, src_kind, dependencies));
            if lib_tags.is_up_to_date(tags_kind) {
               continue;
            }

            tag_files.push(lib_tags.tags_file);

            for dep in dependencies.iter() {
               tag_files.push(try!(update_tags(tags_kind, dep)).tags_file);
            }

            tag_dir = Some(lib_tags.src_dir.clone());
         }
      }

      if tag_files.is_empty() || tag_dir.is_none() {
         continue;
      }

      if rust_std_lib_tags_file.is_file() {
         tag_files.push(rust_std_lib_tags_file.clone());
      }

      let mut tags_file = tag_dir.unwrap();
      tags_file.push(tags_kind.tags_file_name());

      try!(merge_tags(tags_kind, &tag_files, &tags_file));
   }

   Ok(())
}

/// Searches for a directory containing a `Cargo.toml` file starting at
/// `start_dir` and continuing the search upwards the directory tree
/// until a directory is found.
fn find_cargo_toml_dir(start_dir: &Path) -> AppResult<Path>
{
   let mut dir = start_dir.clone();
   loop {
      if let Ok(files) = fs::readdir(&dir) {
         for file in files.iter() {
            if file.is_file() {
               if let Some("Cargo.toml") = file.filename_str() {
                  return Ok(dir);
               }
            }
         }
      }

      if ! dir.pop() {
         return Err(app_err(format!("Couldn't find 'Cargo.toml' starting at directory '{}'!", start_dir.display())));
      }
   }
}

/// the tags file containing the tags for the rust standard library
fn rust_std_lib_tags_file(tags_kind: &TagsKind) -> AppResult<Path>
{
   let mut tags_file = try!(rusty_tags_dir());
   tags_file.push(format!("rust-std-lib.{}", tags_kind.tags_file_extension()));

   Ok(tags_file)
}
<commit_msg>Just continue for now, when the source of a dependency couldn't be found<commit_after>#![allow(unused_assignments)]
#![feature(slicing_syntax)]

extern crate toml;
extern crate glob;

use std::io::fs::PathExtensions;
use std::io::fs;
use std::io;
use std::os;

use app_result::{AppResult, AppErr, app_err};
use dependencies::read_dependencies;
use types::{TagsRoot, TagsKind};

use tags::{
   update_tags,
   update_tags_and_check_for_reexports,
   create_tags,
   merge_tags
};

use dirs::rusty_tags_dir;

mod app_result;
mod dependencies;
mod dirs;
mod tags;
mod types;

fn main()
{
   let args = os::args();
   let tags_kind =
      if args.len() == 2 {
         match args[1].as_slice() {
            "vi"    => Some(TagsKind::Vi),
            "emacs" => Some(TagsKind::Emacs),
            _       => None
         }
      }
      else {
         None
      };

   if let Some(tkind) = tags_kind {
      update_all_tags(&tkind).unwrap_or_else(|err| {
         write_to_stderr(&err);
         os::set_exit_status(1);
      });
   }
   else {
      println!("Usage:
   rusty-tags vi
   rusty-tags emacs");
   }
}

fn update_all_tags(tags_kind: &TagsKind) -> AppResult<()>
{
   let cwd = try!(os::getcwd());
   let cargo_dir = try!(find_cargo_toml_dir(&cwd));
   let tags_roots = try!(read_dependencies(&cargo_dir));

   let rust_std_lib_tags_file = try!(rust_std_lib_tags_file(tags_kind));

   for tags_root in tags_roots.iter() {
      let mut tag_files: Vec<Path> = Vec::new();
      let mut tag_dir: Option<Path> = None;

      match *tags_root {
         TagsRoot::Src { ref src_dir, ref dependencies } => {
            let mut src_tags = src_dir.clone();
            src_tags.push(tags_kind.tags_file_name());
            try!(create_tags(tags_kind, src_dir, &src_tags));
            tag_files.push(src_tags);

            for dep in dependencies.iter() {
               match update_tags(tags_kind, dep) {
                  Ok(tags) => tag_files.push(tags.tags_file),
                  Err(err) => write_to_stderr(&err)
               }
            }

            tag_dir = Some(src_dir.clone());
         },

         TagsRoot::Lib { ref src_kind, ref dependencies } => {
            let lib_tags = match update_tags_and_check_for_reexports(tags_kind, src_kind, dependencies) {
               Ok(tags) => {
                 if tags.is_up_to_date(tags_kind) {
                    continue;
                 }
                 else {
                    tags
                 }
               }

               Err(err) => {
                   write_to_stderr(&err);
                   continue;
               }
            };

            tag_files.push(lib_tags.tags_file);

            for dep in dependencies.iter() {
               match update_tags(tags_kind, dep) {
                  Ok(tags) => tag_files.push(tags.tags_file),
                  Err(err) => write_to_stderr(&err)
               }
            }

            tag_dir = Some(lib_tags.src_dir.clone());
         }
      }

      if tag_files.is_empty() || tag_dir.is_none() {
         continue;
      }

      if rust_std_lib_tags_file.is_file() {
         tag_files.push(rust_std_lib_tags_file.clone());
      }

      let mut tags_file = tag_dir.unwrap();
      tags_file.push(tags_kind.tags_file_name());

      try!(merge_tags(tags_kind, &tag_files, &tags_file));
   }

   Ok(())
}

/// Searches for a directory containing a `Cargo.toml` file starting at
/// `start_dir` and continuing the search upwards the directory tree
/// until a directory is found.
fn find_cargo_toml_dir(start_dir: &Path) -> AppResult<Path>
{
   let mut dir = start_dir.clone();
   loop {
      if let Ok(files) = fs::readdir(&dir) {
         for file in files.iter() {
            if file.is_file() {
               if let Some("Cargo.toml") = file.filename_str() {
                  return Ok(dir);
               }
            }
         }
      }

      if ! dir.pop() {
         return Err(app_err(format!("Couldn't find 'Cargo.toml' starting at directory '{}'!", start_dir.display())));
      }
   }
}

/// the tags file containing the tags for the rust standard library
fn rust_std_lib_tags_file(tags_kind: &TagsKind) -> AppResult<Path>
{
   let mut tags_file = try!(rusty_tags_dir());
   tags_file.push(format!("rust-std-lib.{}", tags_kind.tags_file_extension()));

   Ok(tags_file)
}

fn write_to_stderr(err: &AppErr)
{
   let stderr = &mut io::stderr();
   let _ = writeln!(stderr, "rusty-tags: {:?}", err);
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate glium;
#[macro_use]
extern crate log;

extern crate env_logger;
extern crate image;
extern crate nalgebra;
extern crate obj;
extern crate time;

extern crate genmesh;

mod camera;
mod draw;
mod shader;

use std::collections::HashMap;
use std::io::Read;
use std::fs::File;

use camera::Camera;
use draw::{Cube, Grid, GameObject};
use shader::ShaderType;

use glium::{glutin, Display, DisplayBuild, DrawError, Program, Surface};
use glium::backend::Facade;
use glium::glutin::{ElementState, VirtualKeyCode};

use nalgebra::{zero, BaseFloat, Vec3};

type Scene = Vec<Box<GameObject>>;

const RELATIVE_ROTATION: bool = true;

fn get_display_dim(display: &Display) -> (u32, u32) {
    match display.get_window().unwrap().get_inner_size() {
        Some(dim) => dim,
        None => panic!("Couldn't get window dimensions")
    }
}

pub struct EngineContext {
    vertex_shader: String,
    shader_map: HashMap<ShaderType, String>,
}

impl EngineContext {
    pub fn new() -> Self {
        let mut shader = String::new();
        File::open("shaders/vertex.glsl").unwrap().read_to_string(&mut shader).unwrap();
        EngineContext { vertex_shader: shader, shader_map: HashMap::new() }
    }

    pub fn draw<'a, F: Facade, S: Surface>(&mut self,
                                           surface: &mut S,
                                           facade: &F,
                                           camera: &Camera,
                                           obj: &Box<GameObject>)
                                           -> Result<(), DrawError> {
        let parent = obj.parent();
        let uniforms = obj.construct_uniforms(&camera);

        let &mut EngineContext { ref vertex_shader, ref mut shader_map } = self;
        let fragment_shader = Self::get_shader(shader_map, parent.shader_type);
        let program = Program::from_source(facade, vertex_shader,
                                           fragment_shader, None).unwrap();
        surface.draw(&parent.vertex_buffer, parent.indices.clone(), &program, &uniforms,
                     &parent.draw_params)
    }

    fn get_shader(shader_map: &mut HashMap<ShaderType, String>, shader_type: ShaderType) -> &str {
        shader_map.entry(shader_type).or_insert_with(|| {
            let mut shader = String::new();
            File::open(shader_type.to_filename()).unwrap().read_to_string(&mut shader).unwrap();
            shader
        })
    }
}

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

    let display = glutin::WindowBuilder::new()
        .with_dimensions(800, 600)
        .with_title(format!("3D Cube"))
        .build_glium()
        .unwrap();

    let mut camera_pos = Vec3::new(0., 0., 1.);
    let mut camera = {
        let (w, h) = get_display_dim(&display);
        let (w, h) = (w as f32, h as f32);
        Camera::new(camera_pos.clone(), w / h)
    };

    let mut scene = Scene::new();
    scene.push(Box::new(Grid::new(&display, 20)));
    scene.push(Box::new(Cube::new(&display, 0.25, zero())));

    let mut mouse_pressed = false;
    let mut old_mouse_coords = None;

    let mut ctxt = EngineContext::new();
    loop {
        let mut target = display.draw();
        target.clear_color_and_depth((0., 0., 0., 1.), 1.);
        for obj in scene.iter() {
            ctxt.draw(&mut target, &display, &camera, obj).unwrap();
        }
        target.finish().unwrap();

        for ev in display.poll_events() {
            match ev {
                glutin::Event::KeyboardInput(ElementState::Pressed, _, Some(key)) => {
                    match key {
                        VirtualKeyCode::Up => camera_pos.y += 0.05,
                        VirtualKeyCode::Down => camera_pos.y -= 0.05,
                        VirtualKeyCode::Left => camera_pos.x -= 0.05,
                        VirtualKeyCode::Right => camera_pos.x += 0.05,
                        VirtualKeyCode::R => {
                            camera_pos = Vec3::new(0., 0., 1.);
                            camera.set_abs_rotation(0., 0.);
                            camera.set_fov(BaseFloat::frac_pi_2());
                        }
                        _ => ()
                    }
                    camera.set_pos(&camera_pos);
                },
                glutin::Event::MouseWheel(glutin::MouseScrollDelta::LineDelta(_, v)) => {
                    let fov = camera.fov();
                    let new_fov = nalgebra::clamp(fov + (v * 0.05), 0., BaseFloat::pi());
                    camera.set_fov(new_fov);
                },
                glutin::Event::MouseMoved((x, y)) => {
                    if mouse_pressed {
                        let (x, y) = (x as f32, y as f32);
                        let (w, h) = get_display_dim(&display);
                        let (w, h) = (w as f32, h as f32);
                        if !RELATIVE_ROTATION {
                            let pitch = (y / h) * f32::two_pi();
                            let yaw = (x / w) * f32::two_pi();
                            camera.set_abs_rotation(pitch, -yaw);
                        } else {
                            if let Some((x_old, y_old)) = old_mouse_coords {
                                let delta_x = x - x_old;
                                let delta_y = y - y_old;

                                let pitch = (delta_y * 0.5 / h) * f32::two_pi();
                                let yaw = (delta_x * 0.5 / w) * f32::two_pi();
                                camera.rotate(pitch, yaw);
                            }
                            old_mouse_coords = Some((x, y));
                        }
                    }
                },
                glutin::Event::MouseInput(state, glutin::MouseButton::Left) => {
                    mouse_pressed = if state == ElementState::Pressed {
                        true
                    } else {
                        old_mouse_coords = None;
                        false
                    };
                },
                glutin::Event::Resized(x, y) => {
                    camera.set_aspect_ratio(x as f32 / y as f32);
                },
                glutin::Event::Closed => return,
                _ => ()
            }
        }
    }
}
<commit_msg>Refactored Scene and EngineContext<commit_after>#[macro_use]
extern crate glium;
#[macro_use]
extern crate log;

extern crate env_logger;
extern crate image;
extern crate nalgebra;
extern crate obj;
extern crate time;

extern crate genmesh;

mod camera;
mod draw;
mod shader;

use std::collections::HashMap;
use std::io::Read;
use std::fs::File;

use camera::Camera;
use draw::{Cube, Grid, GameObject};
use shader::ShaderType;

use glium::{glutin, Display, DisplayBuild, DrawError, Program, Surface};
use glium::glutin::{ElementState, VirtualKeyCode};

use nalgebra::{zero, BaseFloat, Vec3};

struct Scene {
    objects: Vec<Box<GameObject>>,
    camera: Camera,
}

impl Scene {
    fn new(camera: Camera) -> Self {
        Scene { camera: camera, objects: Vec::new() }
    }

    fn draw(&self, ctxt: &mut EngineContext) {
        let mut target = ctxt.display.draw();
        target.clear_color_and_depth((0., 0., 0., 1.), 1.);
        for obj in self.objects.iter() {
            ctxt.draw(&mut target, &self.camera, obj).unwrap();
        }
        target.finish().unwrap();
    }

    fn add<G: GameObject + 'static>(&mut self, object: G) {
        self.objects.push(Box::new(object));
    }
}

const RELATIVE_ROTATION: bool = true;

fn get_display_dim(display: &Display) -> (u32, u32) {
    match display.get_window().unwrap().get_inner_size() {
        Some(dim) => dim,
        None => panic!("Couldn't get window dimensions")
    }
}

pub struct EngineContext {
    display: Display,
    vertex_shader: String,
    shader_map: HashMap<ShaderType, String>,
}

impl EngineContext {
    pub fn new(display: Display) -> Self {
        let mut shader = String::new();
        File::open("shaders/vertex.glsl").unwrap().read_to_string(&mut shader).unwrap();
        EngineContext { display: display, vertex_shader: shader, shader_map: HashMap::new() }
    }

    pub fn draw<S: Surface>(&mut self, surface: &mut S, camera: &Camera,
                            obj: &Box<GameObject>) -> Result<(), DrawError> {
        let parent = obj.parent();
        let uniforms = obj.construct_uniforms(&camera);

        let &mut EngineContext { ref display, ref vertex_shader, ref mut shader_map } = self;
        let fragment_shader = Self::get_shader(shader_map, parent.shader_type);
        let program = Program::from_source(display, vertex_shader, fragment_shader, None).unwrap();
        surface.draw(&parent.vertex_buffer, parent.indices.clone(), &program, &uniforms,
                     &parent.draw_params)
    }

    fn get_shader(shader_map: &mut HashMap<ShaderType, String>, shader_type: ShaderType) -> &str {
        shader_map.entry(shader_type).or_insert_with(|| {
            let mut shader = String::new();
            File::open(shader_type.to_filename()).unwrap().read_to_string(&mut shader).unwrap();
            shader
        })
    }
}

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

    let display = glutin::WindowBuilder::new()
        .with_dimensions(800, 600)
        .with_title(format!("3D Cube"))
        .build_glium()
        .unwrap();

    let mut camera_pos = Vec3::new(0., 0., 1.);
    let camera = {
        let (w, h) = get_display_dim(&display);
        let (w, h) = (w as f32, h as f32);
        Camera::new(camera_pos.clone(), w / h)
    };

    let mut scene = Scene::new(camera);
    scene.add(Grid::new(&display, 20));
    scene.add(Cube::new(&display, 0.25, zero()));

    let mut mouse_pressed = false;
    let mut old_mouse_coords = None;

    let mut ctxt = EngineContext::new(display);
    loop {
        scene.draw(&mut ctxt);

        for ev in ctxt.display.poll_events() {
            match ev {
                glutin::Event::KeyboardInput(ElementState::Pressed, _, Some(key)) => {
                    match key {
                        VirtualKeyCode::Up => camera_pos.y += 0.05,
                        VirtualKeyCode::Down => camera_pos.y -= 0.05,
                        VirtualKeyCode::Left => camera_pos.x -= 0.05,
                        VirtualKeyCode::Right => camera_pos.x += 0.05,
                        VirtualKeyCode::R => {
                            camera_pos = Vec3::new(0., 0., 1.);
                            scene.camera.set_abs_rotation(0., 0.);
                            scene.camera.set_fov(BaseFloat::frac_pi_2());
                        }
                        _ => ()
                    }
                    scene.camera.set_pos(&camera_pos);
                },
                glutin::Event::MouseWheel(glutin::MouseScrollDelta::LineDelta(_, v)) => {
                    let fov = scene.camera.fov();
                    let new_fov = nalgebra::clamp(fov + (v * 0.05), 0., BaseFloat::pi());
                    scene.camera.set_fov(new_fov);
                },
                glutin::Event::MouseMoved((x, y)) => {
                    if mouse_pressed {
                        let (x, y) = (x as f32, y as f32);
                        let (w, h) = get_display_dim(&ctxt.display);
                        let (w, h) = (w as f32, h as f32);
                        if !RELATIVE_ROTATION {
                            let pitch = (y / h) * f32::two_pi();
                            let yaw = (x / w) * f32::two_pi();
                            scene.camera.set_abs_rotation(pitch, -yaw);
                        } else {
                            if let Some((x_old, y_old)) = old_mouse_coords {
                                let delta_x = x - x_old;
                                let delta_y = y - y_old;

                                let pitch = (delta_y * 0.5 / h) * f32::two_pi();
                                let yaw = (delta_x * 0.5 / w) * f32::two_pi();
                                scene.camera.rotate(pitch, yaw);
                            }
                            old_mouse_coords = Some((x, y));
                        }
                    }
                },
                glutin::Event::MouseInput(state, glutin::MouseButton::Left) => {
                    mouse_pressed = if state == ElementState::Pressed {
                        true
                    } else {
                        old_mouse_coords = None;
                        false
                    };
                },
                glutin::Event::Resized(x, y) => {
                    scene.camera.set_aspect_ratio(x as f32 / y as f32);
                },
                glutin::Event::Closed => return,
                _ => ()
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

enum Type {
  Assign(String, int),
  Print(String),
  Block
}

struct Context {
  symbol_table: HashMap<String, int>
}

struct Node {
  t: Type,
  children: Vec<Node>
}

fn set(s: &String, i: int, cxt: &mut Context) {
  if cxt.symbol_table.contains_key(s) {
    *cxt.symbol_table.get_mut(s) = i;
  } else {
    cxt.symbol_table.insert(s.clone(), i);
  }
}

fn lookup(s: &String, cxt: &mut Context) -> int {
  cxt.symbol_table.get_copy(s)
}

fn eval(cxt: &mut Context, n: &Node) {
  // Match on the type
  match n.t {
    Assign(ref s, i) => set(s, i, cxt),
    Print(ref s) => println!("{} = {}", s, lookup(s, cxt)),
    Block => for n in n.children.iter() { eval(cxt, n); }
  }
}

fn main() {
  let mut context = Context { symbol_table: HashMap::new() };
  let program = Node {
    t: Block,
    children: vec!(
      Node {t: Assign("x".to_string(), 5), children: vec!()},
      Node {t: Print("x".to_string()), children: vec!()})
  };
  eval(&mut context, &program);
}
<commit_msg>Added variable assignments and recollection<commit_after>mod ast {
  use std::collections::HashMap;

  // Type
  pub enum Type {
    Assign(String, int),
    Print(String),
    Block
  }

  pub struct Node {
    t: Type,
    children: Vec<Node>
  }

  // Context
  pub struct Context {
    pub symbol_table: HashMap<String, int>
  }

  impl Context {
    pub fn new() -> Context {
      Context {
        symbol_table: HashMap::new()
      }
    }

    fn set(&mut self, s: &String, i: int) {
      if self.symbol_table.contains_key(s) {
        *self.symbol_table.get_mut(s) = i;
      } else {
        self.symbol_table.insert(s.clone(), i);
      }
    }

    fn get(&mut self, s: &String) -> int {
      self.symbol_table.get_copy(s)
    }
  }

  // Constructors
  pub fn block(cs: Vec<Node>) -> Node {
    Node {
      t: Block,
      children: cs
    }
  }

  pub fn assign(s: &str, i: int) -> Node {
    Node {
      t: Assign(s.to_string(), i),
      children: vec!()
    }
  }

  pub fn print(s: &str) -> Node {
    Node {
      t: Print(s.to_string()),
      children: vec!()
    }
  }

  // Evaluate
  pub fn eval(cxt: &mut Context, n: &Node) {
    match n.t {
      Assign(ref s, i) => cxt.set(s, i),
      Print(ref s) => println!("{} = {}", s, cxt.get(s)),
      Block => for n in n.children.iter() { eval(cxt, n); }
    }
  }
}

fn main() {
  let program =
    ast::block(vec!(
      ast::assign("x", 5),
      ast::assign("y", 7),
      ast::print("x"),
      ast::print("y"),
      ast::assign("x", 6),
      ast::print("x")));
  ast::eval(&mut ast::Context::new(), &program);
}
<|endoftext|>