<commit_before>extern crate iron;
extern crate mote;
extern crate params;
extern crate rgb;
extern crate router;
extern crate serde;
extern crate serde_json;
extern crate unicase;
extern crate url;

#[macro_use]
extern crate serde_derive;

#[macro_use]
extern crate maplit;

use std::io::Read;
use std::str::FromStr;
use std::sync::Mutex;

use iron::headers::{AccessControlAllowHeaders, AccessControlAllowOrigin, ContentType};
use iron::middleware::Handler;
use iron::modifiers::Redirect;
use iron::prelude::{IronResult, Request, Response};
use iron::prelude::*;
use iron::status;
use router::Router;
use unicase::UniCase;
use url::Url;

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

mod smart_home;
use smart_home::{LightMode, LightType, LightStatus, Light, Device, ThermostatMode};

mod oauth;

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

impl Handler for Hub {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        println!("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();

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

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

                let ref devices = *self.devices.lock().unwrap();
                for device in devices {
                    match device {
                        &Device::Light(ref light) => {
                            response.payload.devices.push(SyncResponseDevice {
                                id: light.id.clone(),
                                type_: light.type_.to_string(),
                                traits: light.available_light_modes
                                    .iter()
                                    .map(LightMode::to_string)
                                    .collect(),
                                name: Name {
                                    default_name: vec![light.name.to_string()],
                                    name: Some(light.name.clone()),
                                    nicknames: vec![],
                                },
                                will_report_state: false,
                                device_info: None,
                                room_hint: None,
                                structure_hint: None,
                                attributes: None,
                            })
                        }
                        &Device::Thermostat(ref thermostat) => {
                            response.payload.devices.push(SyncResponseDevice {
                                id: thermostat.id.clone(),
                                type_: "".to_string(), // XXX
                                traits: vec!["action.devices.traits.TemperatureSetting"
                                                 .to_string()],
                                name: Name {
                                    default_name: vec![thermostat.name.to_string()],
                                    name: Some(thermostat.name.clone()),
                                    nicknames: vec![],
                                },
                                // TODO: attributes.
                                will_report_state: false,
                                device_info: None,
                                room_hint: None,
                                structure_hint: None,
                                attributes: None,
                            })
                        }
                        &Device::Scene(ref scene) => {
                            response.payload.devices.push(SyncResponseDevice {
                                id: scene.id.clone(),
                                type_: "action.devices.types.SCENE".to_string(),
                                traits: vec!["action.devices.traits.Scene".to_string()],
                                name: Name {
                                    default_name: vec![scene.name.to_string()],
                                    name: Some(scene.name.clone()),
                                    nicknames: vec![],
                                },
                                will_report_state: false,
                                device_info: None,
                                room_hint: None,
                                structure_hint: None,
                                attributes: None,
                            })
                        }
                    }
                }

                let res = serde_json::to_string(&response).unwrap_or("".to_string());
                println!("action_response: {:?}", res);
                let mut rsp = Response::with((status::Ok, res));
                rsp.headers.set(ContentType::json());
                return Ok(rsp);
            } else if input.intent == "action.devices.QUERY" {
                let mut response = QueryResponse {
                    request_id: action_request.request_id.clone(),
                    payload: QueryResponsePayload { devices: btreemap!{} },
                };

                let ref devices = *self.devices.lock().unwrap();
                if let Some(payload) = input.payload {
                    for request_device in payload.devices {
                        for device in devices {
                            match device {
                                &Device::Light(ref light) => {
                                    if light.id == request_device.id {
                                        response.payload
                                            .devices
                                            .insert(light.id.clone(), light.status.clone().into());
                                    }
                                }
                                &Device::Thermostat(ref thermostat) => {
                                    if thermostat.id == request_device.id {
                                        // TODO
                                    }
                                }
                                &Device::Scene(ref scene) => {}
                            }
                        }
                    }
                }

                let res = serde_json::to_string(&response).unwrap_or("".to_string());
                println!("action_response: {:?}", res);
                let mut rsp = Response::with((status::Ok, res));
                rsp.headers.set(ContentType::json());
                return Ok(rsp);
            } else if input.intent == "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 {
                        println!("command: {:?}", command);
                        for execution in &command.execution {
                            println!("execution: {:?}", execution);
                            for request_device in &command.devices {
                                println!("request_device: {:?}", request_device);
                                let ref mut devices = *self.devices.lock().unwrap();
                                for device in devices {
                                    match device {
                                        &mut Device::Light(ref mut light) => {
                                            if light.id == request_device.id {
                                                if let Some(s) = execution.params.on {
                                                    light.set_on(s);
                                                }
                                                if let Some(s) = execution.params.brightness {
                                                    light.set_brightness(s);
                                                }
                                                if let Some(ref s) = execution.params.color {
                                                    if let Some(s) = s.spectrum_rgb {
                                                        light.set_color(to_rgb(s));
                                                    }
                                                }
                                                response.payload
                                                    .commands
                                                    .push(ExecuteResponseCommand {
                                                        ids: vec![light.id.clone()],
                                                        status: "SUCCESS".to_string(),
                                                        states: light.status.clone().into(),
                                                    });
                                            }
                                        }
                                        &mut Device::Thermostat(ref mut thermostat) => {
                                            if thermostat.id == request_device.id {
                                                if let Some(s) = execution.params
                                                    .thermostat_temperature_setpoint {
                                                    thermostat.temperature_setpoint(s);
                                                }
                                                if let (Some(low), Some(high)) =
                                                    (execution.params
                                                         .thermostat_temperature_setpoint_low,
                                                     execution.params
                                                         .thermostat_temperature_setpoint_high) {
                                                    thermostat.temperature_set_range(low, high);
                                                }
                                                if let Some(ref mode) = execution.params
                                                    .thermostat_mode {
                                                    if let Ok(mode) =
                                                        ThermostatMode::from_str(mode) {
                                                        thermostat.thermostat_set_mode(mode);
                                                    }
                                                }
                                                response.payload
                                                    .commands
                                                    .push(ExecuteResponseCommand {
                                                        ids: vec![thermostat.id.clone()],
                                                        status: "SUCCESS".to_string(),
                                                        states: thermostat.status.clone().into(),
                                                    });
                                            }
                                        }
                                        &mut Device::Scene(ref mut scene) => {}
                                    }
                                }
                            }
                        }
                    }
                }

                let res = serde_json::to_string(&response).unwrap_or("".to_string());
                println!("action_response: {:?}", res);
                let mut rsp = Response::with((status::Ok, res));
                rsp.headers.set(ContentType::json());
                return Ok(rsp);
            }
        }

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

fn to_rgb(c: u64) -> rgb::RGB8 {
    rgb::RGB8 {
        r: ((c & 0xFF0000) >> 16) as u8,
        g: ((c & 0x00FF00) >> 8) as u8,
        b: ((c & 0x0000FF) >> 0) as u8,
    }
}

fn main() {
    let hub = Hub {
        devices: Mutex::new(vec![Device::Light(Light {
                                     id: "11".to_string(),
                                     name: "TV lights".to_string(),
                                     status: LightStatus::default(),
                                     type_: LightType::Light,
                                     available_light_modes: vec![LightMode::OnOff,
                                                                 LightMode::Brightness,
                                                                 LightMode::ColorSpectrum],
                                     mote: mote::Mote::new("/dev/ttyACM0"),
                                 })]),
    };
    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("/", index_handler, "index");
    println!("Listening on port 1234");
    Iron::new(control)
        .http("0.0.0.0:1234")
        .unwrap();
}

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

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>more headers<commit_after>extern crate iron;
extern crate mote;
extern crate params;
extern crate rgb;
extern crate router;
extern crate serde;
extern crate serde_json;
extern crate unicase;
extern crate url;

#[macro_use]
extern crate serde_derive;

#[macro_use]
extern crate maplit;

use std::io::Read;
use std::str::FromStr;
use std::sync::Mutex;

use iron::headers::{AccessControlAllowHeaders, AccessControlAllowOrigin, ContentType};
use iron::middleware::Handler;
use iron::modifiers::Redirect;
use iron::prelude::{IronResult, Request, Response};
use iron::prelude::*;
use iron::status;
use router::Router;
use unicase::UniCase;
use url::Url;

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

mod smart_home;
use smart_home::{LightMode, LightType, LightStatus, Light, Device, ThermostatMode};

mod oauth;

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

impl Handler for Hub {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        println!("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();

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

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

                let ref devices = *self.devices.lock().unwrap();
                for device in devices {
                    match device {
                        &Device::Light(ref light) => {
                            response.payload.devices.push(SyncResponseDevice {
                                id: light.id.clone(),
                                type_: light.type_.to_string(),
                                traits: light.available_light_modes
                                    .iter()
                                    .map(LightMode::to_string)
                                    .collect(),
                                name: Name {
                                    default_name: vec![light.name.to_string()],
                                    name: Some(light.name.clone()),
                                    nicknames: vec![],
                                },
                                will_report_state: false,
                                device_info: None,
                                room_hint: None,
                                structure_hint: None,
                                attributes: None,
                            })
                        }
                        &Device::Thermostat(ref thermostat) => {
                            response.payload.devices.push(SyncResponseDevice {
                                id: thermostat.id.clone(),
                                type_: "".to_string(), // XXX
                                traits: vec!["action.devices.traits.TemperatureSetting"
                                                 .to_string()],
                                name: Name {
                                    default_name: vec![thermostat.name.to_string()],
                                    name: Some(thermostat.name.clone()),
                                    nicknames: vec![],
                                },
                                // TODO: attributes.
                                will_report_state: false,
                                device_info: None,
                                room_hint: None,
                                structure_hint: None,
                                attributes: None,
                            })
                        }
                        &Device::Scene(ref scene) => {
                            response.payload.devices.push(SyncResponseDevice {
                                id: scene.id.clone(),
                                type_: "action.devices.types.SCENE".to_string(),
                                traits: vec!["action.devices.traits.Scene".to_string()],
                                name: Name {
                                    default_name: vec![scene.name.to_string()],
                                    name: Some(scene.name.clone()),
                                    nicknames: vec![],
                                },
                                will_report_state: false,
                                device_info: None,
                                room_hint: None,
                                structure_hint: None,
                                attributes: None,
                            })
                        }
                    }
                }

                let res = serde_json::to_string(&response).unwrap_or("".to_string());
                println!("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);
            } else if input.intent == "action.devices.QUERY" {
                let mut response = QueryResponse {
                    request_id: action_request.request_id.clone(),
                    payload: QueryResponsePayload { devices: btreemap!{} },
                };

                let ref devices = *self.devices.lock().unwrap();
                if let Some(payload) = input.payload {
                    for request_device in payload.devices {
                        for device in devices {
                            match device {
                                &Device::Light(ref light) => {
                                    if light.id == request_device.id {
                                        response.payload
                                            .devices
                                            .insert(light.id.clone(), light.status.clone().into());
                                    }
                                }
                                &Device::Thermostat(ref thermostat) => {
                                    if thermostat.id == request_device.id {
                                        // TODO
                                    }
                                }
                                &Device::Scene(ref scene) => {}
                            }
                        }
                    }
                }

                let res = serde_json::to_string(&response).unwrap_or("".to_string());
                println!("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);
            } else if input.intent == "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 {
                        println!("command: {:?}", command);
                        for execution in &command.execution {
                            println!("execution: {:?}", execution);
                            for request_device in &command.devices {
                                println!("request_device: {:?}", request_device);
                                let ref mut devices = *self.devices.lock().unwrap();
                                for device in devices {
                                    match device {
                                        &mut Device::Light(ref mut light) => {
                                            if light.id == request_device.id {
                                                if let Some(s) = execution.params.on {
                                                    light.set_on(s);
                                                }
                                                if let Some(s) = execution.params.brightness {
                                                    light.set_brightness(s);
                                                }
                                                if let Some(ref s) = execution.params.color {
                                                    if let Some(s) = s.spectrum_rgb {
                                                        light.set_color(to_rgb(s));
                                                    }
                                                }
                                                response.payload
                                                    .commands
                                                    .push(ExecuteResponseCommand {
                                                        ids: vec![light.id.clone()],
                                                        status: "SUCCESS".to_string(),
                                                        states: light.status.clone().into(),
                                                    });
                                            }
                                        }
                                        &mut Device::Thermostat(ref mut thermostat) => {
                                            if thermostat.id == request_device.id {
                                                if let Some(s) = execution.params
                                                    .thermostat_temperature_setpoint {
                                                    thermostat.temperature_setpoint(s);
                                                }
                                                if let (Some(low), Some(high)) =
                                                    (execution.params
                                                         .thermostat_temperature_setpoint_low,
                                                     execution.params
                                                         .thermostat_temperature_setpoint_high) {
                                                    thermostat.temperature_set_range(low, high);
                                                }
                                                if let Some(ref mode) = execution.params
                                                    .thermostat_mode {
                                                    if let Ok(mode) =
                                                        ThermostatMode::from_str(mode) {
                                                        thermostat.thermostat_set_mode(mode);
                                                    }
                                                }
                                                response.payload
                                                    .commands
                                                    .push(ExecuteResponseCommand {
                                                        ids: vec![thermostat.id.clone()],
                                                        status: "SUCCESS".to_string(),
                                                        states: thermostat.status.clone().into(),
                                                    });
                                            }
                                        }
                                        &mut Device::Scene(ref mut scene) => {}
                                    }
                                }
                            }
                        }
                    }
                }

                let res = serde_json::to_string(&response).unwrap_or("".to_string());
                println!("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);
            }
        }

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

fn to_rgb(c: u64) -> rgb::RGB8 {
    rgb::RGB8 {
        r: ((c & 0xFF0000) >> 16) as u8,
        g: ((c & 0x00FF00) >> 8) as u8,
        b: ((c & 0x0000FF) >> 0) as u8,
    }
}

fn main() {
    let hub = Hub {
        devices: Mutex::new(vec![Device::Light(Light {
                                     id: "11".to_string(),
                                     name: "TV lights".to_string(),
                                     status: LightStatus::default(),
                                     type_: LightType::Light,
                                     available_light_modes: vec![LightMode::OnOff,
                                                                 LightMode::Brightness,
                                                                 LightMode::ColorSpectrum],
                                     mote: mote::Mote::new("/dev/ttyACM0"),
                                 })]),
    };
    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("/", index_handler, "index");
    println!("Listening on port 1234");
    Iron::new(control)
        .http("0.0.0.0:1234")
        .unwrap();
}

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

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>#![feature(box_syntax, core, io, path, hash, collections, os, env, std_misc)]

use std::old_io::File;

use std::cmp::min;
use std::iter;

use parser::parse;
use lexer::Lexer;
use error::Logger;
use dlx::codegen::codegen;

mod parser;
mod dlx;
mod lexer;
mod ast;
mod error;

fn main() {
    let args: Vec<_> = std::env::args().map(|s| s.into_string().unwrap()).collect();
    if args.len() != 2 {
        println!("Invalid usage");
        return;
    }
    let mut file = match File::open(&Path::new(args[1].clone())) {
        Ok(f) => f,
        Err(e) => panic!("Error opening file: {}", e)
    };
    let input = match file.read_to_string() {
        Ok(input) => input,
        Err(e)  => panic!("Error reading file: {}", e)
    };

    let logger = Logger::new(&input, true);
    let program = parse(Lexer::new(&input), &logger);
    let code = codegen(program, &logger, true);

    let mut space = 0;
    let mut program_string = String::new();
    for inst in code {
        match inst {
            dlx::asm::Label(label) => {
                if space != 0 {
                    program_string.push('\n');
                    space = 0;
                }
                program_string.push_str(&label);
                space += label.len();
            },
            dlx::asm::RawAsm(data) => {
                if space != 0 {
                    program_string.push('\n');
                    space = 0;
                }
                program_string.push_str(&data);
                program_string.push('\n');
            },
            other => {
                let data = other.to_string();
                program_string.extend(iter::repeat(' ').take(8 - min(7, space)));
                program_string.push_str(&data);
                program_string.push('\n');
                space = 0;
            }
        }
    }

    println!("{}", program_string);
}
<commit_msg>Minor updates<commit_after>#![feature(box_syntax, core, io, path, hash, collections, env, std_misc)]

use std::old_io::File;

use std::cmp::min;
use std::iter;

use parser::parse;
use lexer::Lexer;
use error::Logger;
use dlx::codegen::codegen;

mod parser;
mod dlx;
mod lexer;
mod ast;
mod error;

fn main() {
    let args: Vec<_> = std::env::args().collect();
    if args.len() != 2 {
        println!("Invalid usage");
        return;
    }
    let mut file = match File::open(&Path::new(args[1].clone())) {
        Ok(f) => f,
        Err(e) => panic!("Error opening file: {}", e)
    };
    let input = match file.read_to_string() {
        Ok(input) => input,
        Err(e)  => panic!("Error reading file: {}", e)
    };

    let logger = Logger::new(&input, true);
    let program = parse(Lexer::new(&input), &logger);
    let code = codegen(program, &logger, true);

    let mut space = 0;
    let mut program_string = String::new();
    for inst in code {
        match inst {
            dlx::asm::Label(label) => {
                if space != 0 {
                    program_string.push('\n');
                    space = 0;
                }
                program_string.push_str(&label);
                space += label.len();
            },
            dlx::asm::RawAsm(data) => {
                if space != 0 {
                    program_string.push('\n');
                    space = 0;
                }
                program_string.push_str(&data);
                program_string.push('\n');
            },
            other => {
                let data = other.to_string();
                program_string.extend(iter::repeat(' ').take(8 - min(7, space)));
                program_string.push_str(&data);
                program_string.push('\n');
                space = 0;
            }
        }
    }

    println!("{}", program_string);
}
<|endoftext|>


<commit_before>#![feature(convert)]
#![feature(core)]
#![feature(split_off)]
#![feature(iter_arith)]

extern crate getopts;
extern crate core;

use getopts::Options;
use std::env;
use std::thread::{JoinHandle, Thread};
use std::thread;
use std::sync::{Arc, Mutex};
use std::collections::{HashMap, BinaryHeap};
use std::sync::mpsc::{channel, Receiver, Sender};

extern crate bounded_spsc_queue;
use bounded_spsc_queue::{Producer, Consumer};

extern crate kissfft;
use kissfft::KissFFT;
use kissfft::binding::kiss_fft_cpx;

extern crate sound_stream;
//use sound_stream::{CallbackFlags, CallbackResult, SoundStream, Settings, StreamParams};
use sound_stream::*;
extern crate osc;
use osc::osc_sender::*;
use osc::osc_data::*;
use osc::osc_data::OscPacket::*;
use osc::osc_data::OscArg::*;
use std::net::{Ipv4Addr,SocketAddrV4};
use core::str::FromStr;

type ChannelBuffers = Arc<Mutex<HashMap<i32, Vec<f32>>>>;

const Fs : usize = 44100usize;
const osc_interval : usize = Fs / 30usize;

#[derive(Clone)]
struct IndexedMagnitude {
    index : usize,
    magnitude : f32
}

use std::cmp::Ordering;
impl PartialOrd for IndexedMagnitude {
     fn partial_cmp(&self, other: &IndexedMagnitude) -> Option<Ordering> {
        return self.magnitude.partial_cmp(&other.magnitude);
     }
}
impl PartialEq for IndexedMagnitude {
    fn eq(&self, other: &IndexedMagnitude) -> bool {
        return self.magnitude.eq(&other.magnitude);
    }
}
extern crate num;
use num::integer::Integer;
fn pitch_detect(buckets : &Vec<f32>) -> f32{
    //  gcd of top 5 bands
    let mut indexed_buckets = vec!();
    let mut i = 0usize;
    for bucket in buckets {
        indexed_buckets.push(IndexedMagnitude{index : i, magnitude: bucket.clone()});
        i += 1usize;
    }
    let mut harmonics = indexed_buckets.clone();
    for indexed_bucket in indexed_buckets.iter() {
        for i in 1..4 {
            if indexed_bucket.index / i > 0usize {
                harmonics[indexed_bucket.index / i].magnitude += indexed_bucket.magnitude;
            }
        }
    }
    harmonics.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Equal));
    let max_idx = harmonics.pop().unwrap();
    //  convert index to freq
    let freq = (max_idx.index * Fs) as f32 / buckets.len() as f32;
    return freq;
}

fn pitch_centroid(buckets : &Vec<f32>) -> f32 {
    let mut centroid = 0f32;
    let totalMag : f32 = buckets.iter().sum();
    let mut i = 1usize;
    for bucket in buckets {
        centroid += i as f32 * bucket / totalMag;
        i += 1usize;
    }
    centroid / buckets.len() as f32
}

use std::iter::FromIterator;
fn meter_fft(
    num_channels : i32,
    c : Consumer<f32>,
    osc_sender : Arc<Mutex<OscSender>>,
    osc_prefix : String
    ) -> JoinHandle<()> {
        let mut bufs_by_channel = HashMap::new();
        let mut chan_index = 0;
        let fft_buckets = 2048*4;
        thread::spawn(move || {
            loop {
                if let Some(s) = c.try_pop() {
                    let mut buf = bufs_by_channel.entry(chan_index).or_insert(vec!());
                    buf.push(kiss_fft_cpx{r : s, i : 0f32});
                    if buf.len() == fft_buckets {
                        let mut fft = KissFFT::new(fft_buckets, false);
                        let mut fft_out = fft.transform_to_vec(buf);
                        //  only use first half
                        fft_out.split_off(fft_buckets / 2usize);
                        let fft_norm = Vec::from_iter(fft_out.iter().map(|c| (c.r * c.r + c.i * c.i).sqrt()));
                        let pitch = pitch_detect(&fft_norm);
                        let centroid = pitch_centroid(&fft_norm);
                        let mut sender = osc_sender.lock().unwrap();
                        sender.send(
                            OscMessage{
                            addr : format!("/opera/meter/id-{}/track{}/pitch_centroid", osc_prefix, chan_index).to_string(),
                            args : vec!(OscFloat(centroid))
                        });
                        buf.truncate(fft_buckets * 7 / 8 as usize);
                    }

                    chan_index = (chan_index + 1) % num_channels;
                } else {
                    thread::sleep_ms(12u32);
                }
            }
        })

    }
fn meter_rms(
    num_channels : i32,
    c : Consumer<f32>,
    p : Producer<f32>,
    osc_sender : Arc<Mutex<OscSender>>,
    osc_prefix : String
    ) -> JoinHandle<()> {
    let mut rms_map : HashMap<i32, f32> = HashMap::new();
    let mut chan_idx = 0;
    let mut samples = 0usize;
    let mut last_sent_time = 0usize;
    // TODO: use sample rate
    let alpha = 30f32 / 44100f32;
    thread::spawn(move || {
        loop {
            if let Some(s) = c.try_pop() {
                let old_rms = *rms_map.entry(chan_idx).or_insert(0f32);
                let new_rms = ((old_rms.powi(2) + s.powi(2)) / 2f32).sqrt();
                rms_map.insert(chan_idx, (1f32 - alpha) * old_rms + new_rms * alpha);
                if samples > last_sent_time + osc_interval {
                    let mut sender = osc_sender.lock().unwrap();
                    let mut msg_vec = vec!();
                    for (chan, rms) in rms_map.iter() {
                        let rms_msg = OscMessage{
                            addr : format!("/opera/meter/id-{}/track{}/rms", osc_prefix, chan).to_string(),
                            args : vec!(OscFloat(*rms as f32))
                        };
                        msg_vec.push(rms_msg);
                    }
                    let bundle = OscBundle {
                        time_tag : (0, 1),
                        conts : msg_vec
                    };
                    if let Err(e) = sender.send(bundle) {
                        println!("Error sending OSC: {:?}", e);
                    }
                    last_sent_time = samples;
                }
                chan_idx = (chan_idx + 1) % num_channels;
                samples += 1usize;
                p.push(s);
            } else {
                thread::sleep_ms(1u32);
            }
        }
    })
}

fn setup_stream(
    frames_per_buffer : u16,
    active_channels : i32,
    total_channels : i32,
    p : Producer<f32>) {
        let mut channel_idx = 0usize;
        let f = Box::new(move |input: &[f32], _: Settings, o: &mut[f32], _: Settings, dt: f64, _: CallbackFlags| {
            for s in input.iter() {
                if (channel_idx as i32) < active_channels {
                    p.push(*s);
                }
                channel_idx = (channel_idx + 1usize) % total_channels as usize;
            }
            return CallbackResult::Continue;
        });

        let stream = SoundStream::new().frames_per_buffer(frames_per_buffer).duplex(StreamParams::new().channels(total_channels), StreamParams::new()).run_callback(f).unwrap();
        while let Ok(true) = stream.is_active() {
            thread::sleep_ms(500);
        }
}

fn main() {
     let args: Vec<String> = env::args().collect();
     let active_channels : i32 = i32::from_str_radix(args[1].as_str(), 10).unwrap();
     let total_channels : i32 = i32::from_str_radix(args[2].as_str(), 10).unwrap();
     let frames_per_buffer : usize = usize::from_str_radix(args[3].as_str(), 10).unwrap();
     let send_ip = args[4].as_str();
     let send_port = u16::from_str_radix(args[5].as_str(), 10).unwrap();
     let meter_id = args[6].as_str();

     let (p_pa, c_rms) = bounded_spsc_queue::make(16 * frames_per_buffer * (total_channels as usize));
     let (p_rms, c_fft) = bounded_spsc_queue::make(16 * frames_per_buffer * (total_channels as usize));

     let mut sender;
     match OscSender::new(
         SocketAddrV4::new(Ipv4Addr::from_str("127.0.0.1").unwrap(), 7000),
         SocketAddrV4::new(Ipv4Addr::from_str(send_ip).unwrap(), send_port)
         ) {
         Ok(s) => { sender = s; },
         Err(e) => { panic!(e); }
     }
     let sender_arc = Arc::new(Mutex::new(sender));
     meter_rms(active_channels, c_rms, p_rms, sender_arc.clone(), String::from(meter_id));
     meter_fft(active_channels, c_fft, sender_arc.clone(), String::from(meter_id));
     setup_stream(frames_per_buffer as u16, active_channels, total_channels, p_pa);
}
<commit_msg>listen on UDP port '0'<commit_after>#![feature(convert)]
#![feature(core)]
#![feature(split_off)]
#![feature(iter_arith)]

extern crate getopts;
extern crate core;

use getopts::Options;
use std::env;
use std::thread::{JoinHandle, Thread};
use std::thread;
use std::sync::{Arc, Mutex};
use std::collections::{HashMap, BinaryHeap};
use std::sync::mpsc::{channel, Receiver, Sender};

extern crate bounded_spsc_queue;
use bounded_spsc_queue::{Producer, Consumer};

extern crate kissfft;
use kissfft::KissFFT;
use kissfft::binding::kiss_fft_cpx;

extern crate sound_stream;
//use sound_stream::{CallbackFlags, CallbackResult, SoundStream, Settings, StreamParams};
use sound_stream::*;
extern crate osc;
use osc::osc_sender::*;
use osc::osc_data::*;
use osc::osc_data::OscPacket::*;
use osc::osc_data::OscArg::*;
use std::net::{Ipv4Addr,SocketAddrV4};
use core::str::FromStr;

type ChannelBuffers = Arc<Mutex<HashMap<i32, Vec<f32>>>>;

const Fs : usize = 44100usize;
const osc_interval : usize = Fs / 30usize;

#[derive(Clone)]
struct IndexedMagnitude {
    index : usize,
    magnitude : f32
}

use std::cmp::Ordering;
impl PartialOrd for IndexedMagnitude {
     fn partial_cmp(&self, other: &IndexedMagnitude) -> Option<Ordering> {
        return self.magnitude.partial_cmp(&other.magnitude);
     }
}
impl PartialEq for IndexedMagnitude {
    fn eq(&self, other: &IndexedMagnitude) -> bool {
        return self.magnitude.eq(&other.magnitude);
    }
}
extern crate num;
use num::integer::Integer;
fn pitch_detect(buckets : &Vec<f32>) -> f32{
    //  gcd of top 5 bands
    let mut indexed_buckets = vec!();
    let mut i = 0usize;
    for bucket in buckets {
        indexed_buckets.push(IndexedMagnitude{index : i, magnitude: bucket.clone()});
        i += 1usize;
    }
    let mut harmonics = indexed_buckets.clone();
    for indexed_bucket in indexed_buckets.iter() {
        for i in 1..4 {
            if indexed_bucket.index / i > 0usize {
                harmonics[indexed_bucket.index / i].magnitude += indexed_bucket.magnitude;
            }
        }
    }
    harmonics.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Equal));
    let max_idx = harmonics.pop().unwrap();
    //  convert index to freq
    let freq = (max_idx.index * Fs) as f32 / buckets.len() as f32;
    return freq;
}

fn pitch_centroid(buckets : &Vec<f32>) -> f32 {
    let mut centroid = 0f32;
    let totalMag : f32 = buckets.iter().sum();
    let mut i = 1usize;
    for bucket in buckets {
        centroid += i as f32 * bucket / totalMag;
        i += 1usize;
    }
    centroid / buckets.len() as f32
}

use std::iter::FromIterator;
fn meter_fft(
    num_channels : i32,
    c : Consumer<f32>,
    osc_sender : Arc<Mutex<OscSender>>,
    osc_prefix : String
    ) -> JoinHandle<()> {
        let mut bufs_by_channel = HashMap::new();
        let mut chan_index = 0;
        let fft_buckets = 2048*4;
        thread::spawn(move || {
            loop {
                if let Some(s) = c.try_pop() {
                    let mut buf = bufs_by_channel.entry(chan_index).or_insert(vec!());
                    buf.push(kiss_fft_cpx{r : s, i : 0f32});
                    if buf.len() == fft_buckets {
                        let mut fft = KissFFT::new(fft_buckets, false);
                        let mut fft_out = fft.transform_to_vec(buf);
                        //  only use first half
                        fft_out.split_off(fft_buckets / 2usize);
                        let fft_norm = Vec::from_iter(fft_out.iter().map(|c| (c.r * c.r + c.i * c.i).sqrt()));
                        let pitch = pitch_detect(&fft_norm);
                        let centroid = pitch_centroid(&fft_norm);
                        let mut sender = osc_sender.lock().unwrap();
                        sender.send(
                            OscMessage{
                            addr : format!("/opera/meter/id-{}/track{}/pitch_centroid", osc_prefix, chan_index).to_string(),
                            args : vec!(OscFloat(centroid))
                        });
                        buf.truncate(fft_buckets * 7 / 8 as usize);
                    }

                    chan_index = (chan_index + 1) % num_channels;
                } else {
                    thread::sleep_ms(12u32);
                }
            }
        })

    }
fn meter_rms(
    num_channels : i32,
    c : Consumer<f32>,
    p : Producer<f32>,
    osc_sender : Arc<Mutex<OscSender>>,
    osc_prefix : String
    ) -> JoinHandle<()> {
    let mut rms_map : HashMap<i32, f32> = HashMap::new();
    let mut chan_idx = 0;
    let mut samples = 0usize;
    let mut last_sent_time = 0usize;
    // TODO: use sample rate
    let alpha = 30f32 / 44100f32;
    thread::spawn(move || {
        loop {
            if let Some(s) = c.try_pop() {
                let old_rms = *rms_map.entry(chan_idx).or_insert(0f32);
                let new_rms = ((old_rms.powi(2) + s.powi(2)) / 2f32).sqrt();
                rms_map.insert(chan_idx, (1f32 - alpha) * old_rms + new_rms * alpha);
                if samples > last_sent_time + osc_interval {
                    let mut sender = osc_sender.lock().unwrap();
                    let mut msg_vec = vec!();
                    for (chan, rms) in rms_map.iter() {
                        let rms_msg = OscMessage{
                            addr : format!("/opera/meter/id-{}/track{}/rms", osc_prefix, chan).to_string(),
                            args : vec!(OscFloat(*rms as f32))
                        };
                        msg_vec.push(rms_msg);
                    }
                    let bundle = OscBundle {
                        time_tag : (0, 1),
                        conts : msg_vec
                    };
                    if let Err(e) = sender.send(bundle) {
                        println!("Error sending OSC: {:?}", e);
                    }
                    last_sent_time = samples;
                }
                chan_idx = (chan_idx + 1) % num_channels;
                samples += 1usize;
                p.push(s);
            } else {
                thread::sleep_ms(1u32);
            }
        }
    })
}

fn setup_stream(
    frames_per_buffer : u16,
    active_channels : i32,
    total_channels : i32,
    p : Producer<f32>) {
        let mut channel_idx = 0usize;
        let f = Box::new(move |input: &[f32], _: Settings, o: &mut[f32], _: Settings, dt: f64, _: CallbackFlags| {
            for s in input.iter() {
                if (channel_idx as i32) < active_channels {
                    p.push(*s);
                }
                channel_idx = (channel_idx + 1usize) % total_channels as usize;
            }
            return CallbackResult::Continue;
        });

        let stream = SoundStream::new().frames_per_buffer(frames_per_buffer).duplex(StreamParams::new().channels(total_channels), StreamParams::new()).run_callback(f).unwrap();
        while let Ok(true) = stream.is_active() {
            thread::sleep_ms(500);
        }
}

fn main() {
     let args: Vec<String> = env::args().collect();
     let active_channels : i32 = i32::from_str_radix(args[1].as_str(), 10).unwrap();
     let total_channels : i32 = i32::from_str_radix(args[2].as_str(), 10).unwrap();
     let frames_per_buffer : usize = usize::from_str_radix(args[3].as_str(), 10).unwrap();
     let send_ip = args[4].as_str();
     let send_port = u16::from_str_radix(args[5].as_str(), 10).unwrap();
     let meter_id = args[6].as_str();

     let (p_pa, c_rms) = bounded_spsc_queue::make(16 * frames_per_buffer * (total_channels as usize));
     let (p_rms, c_fft) = bounded_spsc_queue::make(16 * frames_per_buffer * (total_channels as usize));

     let mut sender;
     match OscSender::new(
         SocketAddrV4::new(Ipv4Addr::from_str("127.0.0.1").unwrap(), 0),
         SocketAddrV4::new(Ipv4Addr::from_str(send_ip).unwrap(), send_port)
         ) {
         Ok(s) => { sender = s; },
         Err(e) => { panic!(e); }
     }
     let sender_arc = Arc::new(Mutex::new(sender));
     meter_rms(active_channels, c_rms, p_rms, sender_arc.clone(), String::from(meter_id));
     meter_fft(active_channels, c_fft, sender_arc.clone(), String::from(meter_id));
     setup_stream(frames_per_buffer as u16, active_channels, total_channels, p_pa);
}
<|endoftext|>


<commit_before>use std::io;
use std::io::Write;
use std::marker::PhantomData;
use Event;

pub struct ReadHtml<'a, I> where I: Iterator<Item=Event<'a>> + 'a {
    events: I,
    current: Vec<u8>,
    phantom: PhantomData<&'a I>,
}

impl<'a, I> ReadHtml<'a, I> where I: Iterator<Item=Event<'a>> {
    pub fn new<II>(events: II) -> ReadHtml<'a, I> where II: IntoIterator<IntoIter=I, Item=Event<'a>> {
        ReadHtml {
            events: events.into_iter(),
            current: Vec::new(),
            phantom: PhantomData,
        }
    }
}

impl<'a, I> io::Read for ReadHtml<'a, I> where I: Iterator<Item=Event<'a>> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        while self.current.len() == 0 {
            if let Some(event) = self.events.next() {
                // Possible to do better?
                try!(write!(&mut self.current, "{}", event));
            } else {
                return Ok(0)
            }
        }
        let curlen = self.current.len();
        let len = ::std::cmp::min(curlen, buf.len());
        buf[..len].clone_from_slice(&self.current[..len]);
        for i in len..curlen {
            self.current[i - len] = self.current[i];
        }
        self.current.truncate(curlen - len);
        Ok(len)
    }
}

#[cfg(test)]
mod tests {
    use std::io::Read;
    use ReadHtml;

    #[test]
    fn test() {
        let events = vec![
            start_tag!("h1", id="hello", class="fun"),
            text!("Hello, "),
            raw_html!(""), // empty event
            start_tag!("small"),
            text!("world"),
            end_tag!("small"),
            closed_tag!("img", src="foo-link"),
            end_tag!("h1"),
        ];

        let mut result = String::new();
        ReadHtml::new(events).read_to_string(&mut result).unwrap();

        assert_eq!(result, "
Hello, \
                            world
");
    }
}
<commit_msg>Better naming of ReadHtml fields<commit_after>use std::io;
use std::io::Write;
use std::marker::PhantomData;
use Event;

pub struct ReadHtml<'a, I> where I: Iterator<Item=Event<'a>> + 'a {
    events: I,
    buffer: Vec<u8>,
    ev_life: PhantomData<Event<'a>>,
}

impl<'a, I> ReadHtml<'a, I> where I: Iterator<Item=Event<'a>> {
    pub fn new<II>(events: II) -> ReadHtml<'a, I> where II: IntoIterator<IntoIter=I, Item=Event<'a>> {
        ReadHtml {
            events: events.into_iter(),
            buffer: Vec::new(),
            ev_life: PhantomData,
        }
    }
}

impl<'a, I> io::Read for ReadHtml<'a, I> where I: Iterator<Item=Event<'a>> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        while self.buffer.len() == 0 {
            if let Some(event) = self.events.next() {
                // Possible to do better?
                try!(write!(&mut self.buffer, "{}", event));
            } else {
                return Ok(0)
            }
        }
        let curlen = self.buffer.len();
        let len = ::std::cmp::min(curlen, buf.len());
        buf[..len].clone_from_slice(&self.buffer[..len]);
        for i in len..curlen {
            self.buffer[i - len] = self.buffer[i];
        }
        self.buffer.truncate(curlen - len);
        Ok(len)
    }
}

#[cfg(test)]
mod tests {
    use std::io::Read;
    use ReadHtml;

    #[test]
    fn test() {
        let events = vec![
            start_tag!("h1", id="hello", class="fun"),
            text!("Hello, "),
            raw_html!(""), // empty event
            start_tag!("small"),
            text!("world"),
            end_tag!("small"),
            closed_tag!("img", src="foo-link"),
            end_tag!("h1"),
        ];

        let mut result = String::new();
        ReadHtml::new(events).read_to_string(&mut result).unwrap();

        assert_eq!(result, "
Hello, \
                            world
");
    }
}
<|endoftext|>


<commit_before>fn main() {
    println!("Hello, world!");
}
<commit_msg>serve the form for entering the numbers<commit_after>extern crate iron;
#[macro_use] extern crate mime;

use iron::prelude::*;
use iron::status;

fn main() {
    println!("Serving on http://0.0.0.0:3000...");
    Iron::new(get_form).http("0.0.0.0:3000").unwrap();
}

#[allow(unused_variables)]
fn get_form(request: &mut Request) -> IronResult<Response> {
    let mut response = Response::new();

    response.set_mut(status::Ok);
    response.set_mut(mime!(Text/Html; Charset=Utf8));
    response.set_mut(r#"
        <title>GCD Calculator</title>
        <form action="/gcd" method="post">
            <input type="text" name="n" />
            <input type="text" name="m" />
            <button type="submit">Compute GCD</button>
        </form>
    "#);

    Ok(response)
}<|endoftext|>


<commit_before>/*
 * TODO: do not show an error when there is no config file.
 * TODO: map O to open with the current url.
 * TODO: only add space at the end when there is no argument (or don't add the space when there is
 * an URL?).
 * TODO: support modes (to avoid entering commands while typing in a text input).
 * TODO: support new window.
 * TODO: search (using FindController).
 * TODO: follow link.
 * TODO: write a webkit2 plugin to support scrolling.
 * TODO: cookie.
 * TODO: download manager.
 * TODO: open file (instead of download).
 * TODO: support bookmarks with tags.
 * TODO: adblock.
 * TODO: command/open completions.
 * TODO: copy/paste URLs.
 * TODO: NoScript.
 * TODO: open textarea in text editor.
 * TODO: non-modal javascript alert, prompt and confirm.
 */

extern crate gtk;
extern crate mg;
#[macro_use]
extern crate mg_settings;
extern crate url;
extern crate webkit2;
extern crate xdg;

use mg::Application;
use mg_settings::Config;
use url::Url;
use webkit2::WebView;
use xdg::BaseDirectories;

use AppCommand::*;

commands!(AppCommand {
    Back,
    Forward,
    Open(String),
    Quit,
    Reload,
    Reloadbypasscache,
    Stop,
});

const APP_NAME: &'static str = env!("CARGO_PKG_NAME");

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

    let config = Config {
        mapping_modes: vec!["n".to_string()],
    };

    let xdg_dirs = BaseDirectories::with_prefix(APP_NAME).unwrap();
    let config_path = xdg_dirs.place_config_file("config")
        .expect("cannot create configuration directory");

    let app = Application::new_with_config(config);
    app.use_dark_theme();
    let url_label = app.add_statusbar_item();

    if let Err(error) = app.parse_config(config_path) {
        app.error(error.description());
    }
    app.set_window_title(APP_NAME);

    let webview = WebView::new();
    webview.load_uri("https://duckduckgo.com/lite/");

    {
        let app = app.clone();
        webview.connect_load_changed(move |webview, _load_event| {
            if let Some(url) = webview.get_uri() {
                url_label.set_text(&url);
            }

            set_title(&app, webview);
        });
    }
    {
        let app = app.clone();
        webview.connect_resource_load_started(move |webview, _resource, _uri_request| {
            set_title(&app, webview);
        });
    }
    app.set_view(&webview);

    app.connect_command(move |command| {
        match command {
            Back => webview.go_back(),
            Forward => webview.go_forward(),
            Open(url) => {
                if let Ok(_) = Url::parse(&url) {
                    webview.load_uri(&url);
                }
                else {
                    webview.load_uri(&format!("http://{}", url));
                }
            },
            Quit => gtk::main_quit(),
            Reload => webview.reload(),
            Reloadbypasscache => webview.reload_bypass_cache(),
            Stop => webview.stop_loading(),
        }
    });

    gtk::main();
}

/// Set the title of the window as the progress and the web page title.
fn set_title(app: &Application<AppCommand>, webview: &WebView) {
    let progress = (webview.get_estimated_load_progress() * 100.0) as i32;
    if let Some(title) = webview.get_title() {
        if progress == 100 {
            app.set_window_title(&format!("{} - {}", title, APP_NAME));
        }
        else {
            app.set_window_title(&format!("[{}%] {} - {}", progress, title, APP_NAME));
        }
    }
}
<commit_msg>Create config file if it does not exist.<commit_after>/*
 * TODO: map O to open with the current url.
 * TODO: only add space at the end when there is no argument (or don't add the space when there is
 * an URL?).
 * TODO: support modes (to avoid entering commands while typing in a text input).
 * TODO: support new window.
 * TODO: search (using FindController).
 * TODO: follow link.
 * TODO: write a webkit2 plugin to support scrolling.
 * TODO: settings.
 * TODO: cookie.
 * TODO: download manager.
 * TODO: open file (instead of download).
 * TODO: support bookmarks with tags.
 * TODO: adblock.
 * TODO: command/open completions.
 * TODO: copy/paste URLs.
 * TODO: NoScript.
 * TODO: open textarea in text editor.
 * TODO: non-modal javascript alert, prompt and confirm.
 * TODO: add option to use light theme variant instead of dark variant.
 */

extern crate gtk;
extern crate mg;
#[macro_use]
extern crate mg_settings;
extern crate url;
extern crate webkit2;
extern crate xdg;

use std::fs::OpenOptions;

use mg::Application;
use mg_settings::Config;
use url::Url;
use webkit2::WebView;
use xdg::BaseDirectories;

use AppCommand::*;

macro_rules! unwrap_or_show_error {
    ($app:expr, $error:expr) => {
        if let Err(error) = $error {
            $app.error(&error.to_string());
        }
    };
}

commands!(AppCommand {
    Back,
    Forward,
    Open(String),
    Quit,
    Reload,
    Reloadbypasscache,
    Stop,
});

const APP_NAME: &'static str = env!("CARGO_PKG_NAME");

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

    let config = Config {
        mapping_modes: vec!["n".to_string()],
    };

    let xdg_dirs = BaseDirectories::with_prefix(APP_NAME).unwrap();
    let config_path = xdg_dirs.place_config_file("config")
        .expect("cannot create configuration directory");

    let app = Application::new_with_config(config);
    app.use_dark_theme();
    let url_label = app.add_statusbar_item();

    unwrap_or_show_error!(app, OpenOptions::new().create(true).write(true).open(&config_path));
    unwrap_or_show_error!(app, app.parse_config(config_path));

    app.set_window_title(APP_NAME);

    let webview = WebView::new();
    webview.load_uri("https://duckduckgo.com/lite/");

    {
        let app = app.clone();
        webview.connect_load_changed(move |webview, _load_event| {
            if let Some(url) = webview.get_uri() {
                url_label.set_text(&url);
            }

            set_title(&app, webview);
        });
    }
    {
        let app = app.clone();
        webview.connect_resource_load_started(move |webview, _resource, _uri_request| {
            set_title(&app, webview);
        });
    }
    app.set_view(&webview);

    app.connect_command(move |command| {
        match command {
            Back => webview.go_back(),
            Forward => webview.go_forward(),
            Open(url) => {
                if let Ok(_) = Url::parse(&url) {
                    webview.load_uri(&url);
                }
                else {
                    webview.load_uri(&format!("http://{}", url));
                }
            },
            Quit => gtk::main_quit(),
            Reload => webview.reload(),
            Reloadbypasscache => webview.reload_bypass_cache(),
            Stop => webview.stop_loading(),
        }
    });

    gtk::main();
}

/// Set the title of the window as the progress and the web page title.
fn set_title(app: &Application<AppCommand>, webview: &WebView) {
    let progress = (webview.get_estimated_load_progress() * 100.0) as i32;
    if let Some(title) = webview.get_title() {
        if progress == 100 {
            app.set_window_title(&format!("{} - {}", title, APP_NAME));
        }
        else {
            app.set_window_title(&format!("[{}%] {} - {}", progress, title, APP_NAME));
        }
    }
}
<|endoftext|>


<commit_before>use clap::{Arg, App, AppSettings, SubCommand};
use slog::{LevelFilter, Level, DrainExt, Logger};
use yaml_rust::YamlLoader;
use std::io::prelude::*;
use std::fs::File;
use yaml_rust::{Yaml, YamlEmitter};
use std::error::Error;
use std::path::Path;
use std::process::exit;
use errors::DotcopterError;

#[macro_use]
extern crate slog;
extern crate slog_term;
extern crate slog_stdlog;
extern crate yaml_rust;
extern crate crypto;
extern crate regex;
#[macro_use]
extern crate clap;

#[cfg(test)]
extern crate spectral;

mod model;
mod config;
mod checksum;
mod files;
mod mutate;
mod import;
mod errors;

fn main() {
  let matches: clap::ArgMatches = create_app().get_matches();
  let stream = slog_term::streamer().full().build();
  let verbose: bool = matches.is_present("verbose");
  let force: bool = matches.is_present("force");
  let log = if verbose {
    slog::Logger::root(stream.fuse(), o!())
  } else {
    slog::Logger::root(LevelFilter::new(stream, Level::Info).fuse(), o!())
  };

  let config_file = matches.value_of("config_file").unwrap();
  info!(log, "Starting engine"; "config_file" => config_file);

  let config = match load_config_file(&log, config_file) {
    Ok(content) => content,
    Err(e) => {
      error!(log, "Failed to load config file."; "error" => e.description());
      exit(1)
    }
  };

  let mut yaml_documents = match YamlLoader::load_from_str(&config) {
    Ok(yaml) => yaml,
    Err(e) => {
      error!(log, "Failed to parse config file."; "error" => e.description());
      exit(2)
    }
  };
  if yaml_documents.is_empty() {
    let s = "files:";
    yaml_documents = YamlLoader::load_from_str(s).unwrap();
  }

  let maybe_ln_matches = matches.subcommand_matches("ln");
  let maybe_cp_matches = matches.subcommand_matches("cp");
  let maybe_apply_matches = matches.subcommand_matches("apply");
  let maybe_import_matches = matches.subcommand_matches("import");
  if maybe_apply_matches.is_some() {
    let yaml_config = &yaml_documents[0];
    let dot_files: &Yaml = &yaml_config["files"];
    info!(log, "Liftoff! Applying configuration.");
    files::process_dot_files(&log, dot_files, force);
  } else if let Some(ln_matches) = maybe_ln_matches {
    let yaml_config = &yaml_documents[0];
    let link_target = ln_matches.value_of("link_target").unwrap();
    let link_name = ln_matches.value_of("link_name").unwrap();
    let log = log.new(o!("link_target" => link_target.to_string(), "link_name" => link_name.to_string()));
    info!(log, "Liftoff! Adding new link to configuration");
    let new_config = mutate::add_dotfiles_to_config(&log,
                                                    yaml_config,
                                                    &[model::DotFile {
                                                        target: link_name.to_string(),
                                                        source: link_target.to_string(),
                                                        dot_file_type: model::DotFileType::LINK,
                                                      }]);
    write_new_yaml(&log, &new_config, config_file);
  } else if let Some(cp_matches) = maybe_cp_matches {
    let yaml_config = &yaml_documents[0];
    let target = cp_matches.value_of("target").unwrap();
    let source = cp_matches.value_of("source").unwrap();
    let log = log.new(o!("target" => target.to_string(), "source" => source.to_string()));
    info!(log, "Liftoff! Adding new copy to configuration");
    let new_config = mutate::add_dotfiles_to_config(&log,
                                                    yaml_config,
                                                    &[model::DotFile {
                                                        target: target.to_string(),
                                                        source: source.to_string(),
                                                        dot_file_type: model::DotFileType::COPY,
                                                      }]);
    write_new_yaml(&log, &new_config, config_file);
  } else if let Some(import_matches) = maybe_import_matches {
    let dir = import_matches.value_of("dir").unwrap();
    let log = log.new(o!("import_directory" => dir.to_string()));
    let yaml_config = &yaml_documents[0];
    info!(log, "Liftoff! Importing to configuration");
    let dot_files = import::scan_dir(&log, dir);
    if !dot_files.is_empty() {
      let new_config = mutate::add_dotfiles_to_config(&log, yaml_config, &dot_files);
      write_new_yaml(&log, &new_config, config_file);
    }
  }
}

fn write_new_yaml(log: &Logger, document: &Yaml, config_file: &str) {
  let mut out_str = String::new();
  {
    let mut emitter = YamlEmitter::new(&mut out_str);
    match emitter.dump(document) {
      Ok(_) => {}
      Err(e) => {
        error!(log, "Failed to write config file."; "error" => format!("{:?}", e));
        exit(3);
      }
    }
  }
  out_str.push_str("\n");
  match write_config_file(config_file, &out_str) {
    Ok(_) => info!(log, "Successfully written configuration"),
    Err(e) => {
      error!(log, "Failed to write config file."; "error" => e.description());
      exit(4);
    }
  };
}

fn write_config_file(file: &str, content: &str) -> Result<(), DotcopterError> {
  let mut file = try!(File::create(file));
  try!(file.write_all(content.as_bytes()));
  Ok(())
}

fn load_config_file(log: &Logger, file: &str) -> Result<String, DotcopterError> {
  let path = Path::new(file);
  if path.exists() {
    let mut file = try!(File::open(file));
    let mut content = String::new();
    try!(file.read_to_string(&mut content));
    Ok(content)
  } else {
    warn!(log, "Configuration doesn't exit"; "file" => file);
    Ok("".to_string())
  }
}

fn create_app<'a>() -> App<'a, 'a> {
  App::new("dotcopter")
    .version(crate_version!())
    .setting(AppSettings::ColoredHelp)
    .author("Patrick Haun <bomgar85@googlemail.com>")
    .about("manages dotfiles installation")
    .arg(Arg::with_name("force")
           .short("f")
           .long("force")
           .takes_value(false))
    .arg(Arg::with_name("verbose")
           .long("verbose")
           .short("v")
           .help("debug output")
           .required(false)
           .takes_value(false))
    .arg(Arg::with_name("config_file").required(true))
    .subcommand(SubCommand::with_name("apply").about("applies a dotfile configuration"))
    .subcommand(SubCommand::with_name("ln")
                  .about("adds new link to configuration")
                  .arg(Arg::with_name("link_target").required(true))
                  .arg(Arg::with_name("link_name").required(true)))
    .subcommand(SubCommand::with_name("cp")
                  .about("adds new copy to configuration")
                  .arg(Arg::with_name("source").required(true))
                  .arg(Arg::with_name("target").required(true)))
    .subcommand(SubCommand::with_name("import")
                  .about("imports dotfiles from a folder into the configuration")
                  .arg(Arg::with_name("dir").required(true)))
}
<commit_msg>[bug] require subcommand<commit_after>use clap::{Arg, App, AppSettings, SubCommand};
use slog::{LevelFilter, Level, DrainExt, Logger};
use yaml_rust::YamlLoader;
use std::io::prelude::*;
use std::fs::File;
use yaml_rust::{Yaml, YamlEmitter};
use std::error::Error;
use std::path::Path;
use std::process::exit;
use errors::DotcopterError;

#[macro_use]
extern crate slog;
extern crate slog_term;
extern crate slog_stdlog;
extern crate yaml_rust;
extern crate crypto;
extern crate regex;
#[macro_use]
extern crate clap;

#[cfg(test)]
extern crate spectral;

mod model;
mod config;
mod checksum;
mod files;
mod mutate;
mod import;
mod errors;

fn main() {
  let matches: clap::ArgMatches = create_app().get_matches();
  let stream = slog_term::streamer().full().build();
  let verbose: bool = matches.is_present("verbose");
  let force: bool = matches.is_present("force");
  let log = if verbose {
    slog::Logger::root(stream.fuse(), o!())
  } else {
    slog::Logger::root(LevelFilter::new(stream, Level::Info).fuse(), o!())
  };

  let config_file = matches.value_of("config_file").unwrap();
  info!(log, "Starting engine"; "config_file" => config_file);

  let config = match load_config_file(&log, config_file) {
    Ok(content) => content,
    Err(e) => {
      error!(log, "Failed to load config file."; "error" => e.description());
      exit(1)
    }
  };

  let mut yaml_documents = match YamlLoader::load_from_str(&config) {
    Ok(yaml) => yaml,
    Err(e) => {
      error!(log, "Failed to parse config file."; "error" => e.description());
      exit(2)
    }
  };
  if yaml_documents.is_empty() {
    let s = "files:";
    yaml_documents = YamlLoader::load_from_str(s).unwrap();
  }

  let maybe_ln_matches = matches.subcommand_matches("ln");
  let maybe_cp_matches = matches.subcommand_matches("cp");
  let maybe_apply_matches = matches.subcommand_matches("apply");
  let maybe_import_matches = matches.subcommand_matches("import");
  if maybe_apply_matches.is_some() {
    let yaml_config = &yaml_documents[0];
    let dot_files: &Yaml = &yaml_config["files"];
    info!(log, "Liftoff! Applying configuration.");
    files::process_dot_files(&log, dot_files, force);
  } else if let Some(ln_matches) = maybe_ln_matches {
    let yaml_config = &yaml_documents[0];
    let link_target = ln_matches.value_of("link_target").unwrap();
    let link_name = ln_matches.value_of("link_name").unwrap();
    let log = log.new(o!("link_target" => link_target.to_string(), "link_name" => link_name.to_string()));
    info!(log, "Liftoff! Adding new link to configuration");
    let new_config = mutate::add_dotfiles_to_config(&log,
                                                    yaml_config,
                                                    &[model::DotFile {
                                                        target: link_name.to_string(),
                                                        source: link_target.to_string(),
                                                        dot_file_type: model::DotFileType::LINK,
                                                      }]);
    write_new_yaml(&log, &new_config, config_file);
  } else if let Some(cp_matches) = maybe_cp_matches {
    let yaml_config = &yaml_documents[0];
    let target = cp_matches.value_of("target").unwrap();
    let source = cp_matches.value_of("source").unwrap();
    let log = log.new(o!("target" => target.to_string(), "source" => source.to_string()));
    info!(log, "Liftoff! Adding new copy to configuration");
    let new_config = mutate::add_dotfiles_to_config(&log,
                                                    yaml_config,
                                                    &[model::DotFile {
                                                        target: target.to_string(),
                                                        source: source.to_string(),
                                                        dot_file_type: model::DotFileType::COPY,
                                                      }]);
    write_new_yaml(&log, &new_config, config_file);
  } else if let Some(import_matches) = maybe_import_matches {
    let dir = import_matches.value_of("dir").unwrap();
    let log = log.new(o!("import_directory" => dir.to_string()));
    let yaml_config = &yaml_documents[0];
    info!(log, "Liftoff! Importing to configuration");
    let dot_files = import::scan_dir(&log, dir);
    if !dot_files.is_empty() {
      let new_config = mutate::add_dotfiles_to_config(&log, yaml_config, &dot_files);
      write_new_yaml(&log, &new_config, config_file);
    }
  }
}

fn write_new_yaml(log: &Logger, document: &Yaml, config_file: &str) {
  let mut out_str = String::new();
  {
    let mut emitter = YamlEmitter::new(&mut out_str);
    match emitter.dump(document) {
      Ok(_) => {}
      Err(e) => {
        error!(log, "Failed to write config file."; "error" => format!("{:?}", e));
        exit(3);
      }
    }
  }
  out_str.push_str("\n");
  match write_config_file(config_file, &out_str) {
    Ok(_) => info!(log, "Successfully written configuration"),
    Err(e) => {
      error!(log, "Failed to write config file."; "error" => e.description());
      exit(4);
    }
  };
}

fn write_config_file(file: &str, content: &str) -> Result<(), DotcopterError> {
  let mut file = try!(File::create(file));
  try!(file.write_all(content.as_bytes()));
  Ok(())
}

fn load_config_file(log: &Logger, file: &str) -> Result<String, DotcopterError> {
  let path = Path::new(file);
  if path.exists() {
    let mut file = try!(File::open(file));
    let mut content = String::new();
    try!(file.read_to_string(&mut content));
    Ok(content)
  } else {
    warn!(log, "Configuration doesn't exit"; "file" => file);
    Ok("".to_string())
  }
}

fn create_app<'a>() -> App<'a, 'a> {
  App::new("dotcopter")
    .version(crate_version!())
    .setting(AppSettings::ColoredHelp)
    .author("Patrick Haun <bomgar85@googlemail.com>")
    .about("manages dotfiles installation")
    .setting(AppSettings::SubcommandRequired)
    .arg(Arg::with_name("force")
           .short("f")
           .long("force")
           .takes_value(false))
    .arg(Arg::with_name("verbose")
           .long("verbose")
           .short("v")
           .help("debug output")
           .required(false)
           .takes_value(false))
    .arg(Arg::with_name("config_file").required(true))
    .subcommand(SubCommand::with_name("apply").about("applies a dotfile configuration"))
    .subcommand(SubCommand::with_name("ln")
                  .about("adds new link to configuration")
                  .arg(Arg::with_name("link_target").required(true))
                  .arg(Arg::with_name("link_name").required(true)))
    .subcommand(SubCommand::with_name("cp")
                  .about("adds new copy to configuration")
                  .arg(Arg::with_name("source").required(true))
                  .arg(Arg::with_name("target").required(true)))
    .subcommand(SubCommand::with_name("import")
                  .about("imports dotfiles from a folder into the configuration")
                  .arg(Arg::with_name("dir").required(true)))
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate termios;

use libc::{STDIN_FILENO, STDOUT_FILENO, TIOCGWINSZ, winsize};
use termios::{Termios, tcsetattr, TCSAFLUSH, VMIN, VTIME};
use termios::{BRKINT, ICRNL, INPCK, ISTRIP, IXON};
use termios::{OPOST, CS8};
use termios::{ECHO, ICANON, IEXTEN, ISIG};

use std::io::{self, Stdin, Stdout, Read, Error, ErrorKind, Write};

macro_rules! ctrl_key {
    ($k:expr) => ($k & 0x1f);
}

struct TermReset {
    orig_term: Termios
}

struct EditorConfig {
    _term: TermReset,
    screenrows: u16,
    screencols: u16,
}

struct Editor {
    config: EditorConfig,
    stdin: Stdin,
    stdout: Stdout,
}

impl Drop for TermReset {
    fn drop(&mut self) {
        tcsetattr(STDIN_FILENO, TCSAFLUSH, &self.orig_term).unwrap()
    }
}

fn enable_raw_mode() -> io::Result<TermReset> {
    let mut term = Termios::from_fd(STDIN_FILENO)?;
    let mode = TermReset { orig_term: term.clone() };

    term.c_iflag &= !(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
    term.c_oflag &= !OPOST;
    term.c_cflag |= CS8;
    term.c_lflag &= !(ECHO | ICANON | IEXTEN | ISIG);
    term.c_cc[VMIN] = 0;
    term.c_cc[VTIME] = 1;

    tcsetattr(STDIN_FILENO, TCSAFLUSH, &term)?;
    Ok(mode)
}

impl EditorConfig {
    fn new() -> EditorConfig {
        let term = enable_raw_mode().unwrap();
        let (rows, cols) = get_window_size().unwrap();
        EditorConfig { _term: term, screenrows: rows, screencols: cols }
    }
}

impl Editor {
    fn new(config: EditorConfig) -> Editor {
        let stdin = io::stdin();
        let stdout = io::stdout();
        Editor { config: config, stdin: stdin, stdout: stdout }
    }
}

impl Drop for Editor {
    fn drop(&mut self) {
        clear_screen(&mut self.stdout).unwrap();
        self.stdout.flush().unwrap();
    }
}

fn editor_read_key(stdin: &mut Stdin) -> u8 {
    let mut buf = [0; 1];
    loop {
        let n = stdin.read(&mut buf)
                 .or_else(|e| if e.kind() == ErrorKind::WouldBlock { Ok(0) } else { Err(e) })
                 .expect("read");
        if n == 1 {
            return buf[0];
        }
    }
}

fn get_window_size() -> io::Result<(u16, u16)> {
    let ws = winsize { ws_col: 0, ws_row: 0, ws_xpixel: 0, ws_ypixel: 0 };
    unsafe {
        if libc::ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0 {
            return Err(Error::new(ErrorKind::Other, "get_window_size: ioctl failed"))
        }
    }
    Ok((ws.ws_row, ws.ws_col))
}

fn clear_screen(stdout: &mut Stdout) -> io::Result<()> {
    stdout.write(b"\x1b[2J")?;
    stdout.write(b"\x1b[H")?;
    Ok(())
}

fn editor_draw_rows(stdout: &mut Stdout, e: &EditorConfig) -> io::Result<()> {
    for _ in 0..(e.screenrows - 1) {
        stdout.write(b"~\r\n")?;
    }
    stdout.write(b"~")?;
    Ok(())
}

fn editor_refresh_screen(stdout: &mut Stdout, e: &EditorConfig) -> io::Result<()> {
    stdout.write(b"\x1b[?25l")?;
    clear_screen(stdout)?;

    editor_draw_rows(stdout, e)?;

    stdout.write(b"\x1b[H")?;
    stdout.write(b"\x1b[?25h")?;
    stdout.flush()
}

fn editor_process_keypress(stdin: &mut Stdin) -> bool {
    let c = editor_read_key(stdin);

    match c {
        k if k == ctrl_key!(b'q') => {
            false
        },
        _ => true
    }
}

fn main() {
    let mut editor = Editor::new(EditorConfig::new());

    editor_refresh_screen(&mut editor.stdout, &editor.config).unwrap();
    while editor_process_keypress(&mut editor.stdin) {
        editor_refresh_screen(&mut editor.stdout, &editor.config).unwrap();
    }
}
<commit_msg>Clear lines one at a time<commit_after>extern crate libc;
extern crate termios;

use libc::{STDIN_FILENO, STDOUT_FILENO, TIOCGWINSZ, winsize};
use termios::{Termios, tcsetattr, TCSAFLUSH, VMIN, VTIME};
use termios::{BRKINT, ICRNL, INPCK, ISTRIP, IXON};
use termios::{OPOST, CS8};
use termios::{ECHO, ICANON, IEXTEN, ISIG};

use std::io::{self, Stdin, Stdout, Read, Error, ErrorKind, Write};

macro_rules! ctrl_key {
    ($k:expr) => ($k & 0x1f);
}

struct TermReset {
    orig_term: Termios
}

struct EditorConfig {
    _term: TermReset,
    screenrows: u16,
    screencols: u16,
}

struct Editor {
    config: EditorConfig,
    stdin: Stdin,
    stdout: Stdout,
}

impl Drop for TermReset {
    fn drop(&mut self) {
        tcsetattr(STDIN_FILENO, TCSAFLUSH, &self.orig_term).unwrap()
    }
}

fn enable_raw_mode() -> io::Result<TermReset> {
    let mut term = Termios::from_fd(STDIN_FILENO)?;
    let mode = TermReset { orig_term: term.clone() };

    term.c_iflag &= !(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
    term.c_oflag &= !OPOST;
    term.c_cflag |= CS8;
    term.c_lflag &= !(ECHO | ICANON | IEXTEN | ISIG);
    term.c_cc[VMIN] = 0;
    term.c_cc[VTIME] = 1;

    tcsetattr(STDIN_FILENO, TCSAFLUSH, &term)?;
    Ok(mode)
}

impl EditorConfig {
    fn new() -> EditorConfig {
        let term = enable_raw_mode().unwrap();
        let (rows, cols) = get_window_size().unwrap();
        EditorConfig { _term: term, screenrows: rows, screencols: cols }
    }
}

impl Editor {
    fn new(config: EditorConfig) -> Editor {
        let stdin = io::stdin();
        let stdout = io::stdout();
        Editor { config: config, stdin: stdin, stdout: stdout }
    }
}

impl Drop for Editor {
    fn drop(&mut self) {
        self.stdout.write(b"\x1b[2J").unwrap();
        self.stdout.write(b"\x1b[H").unwrap();
        self.stdout.flush().unwrap();
    }
}

fn editor_read_key(stdin: &mut Stdin) -> u8 {
    let mut buf = [0; 1];
    loop {
        let n = stdin.read(&mut buf)
                 .or_else(|e| if e.kind() == ErrorKind::WouldBlock { Ok(0) } else { Err(e) })
                 .expect("read");
        if n == 1 {
            return buf[0];
        }
    }
}

fn get_window_size() -> io::Result<(u16, u16)> {
    let ws = winsize { ws_col: 0, ws_row: 0, ws_xpixel: 0, ws_ypixel: 0 };
    unsafe {
        if libc::ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0 {
            return Err(Error::new(ErrorKind::Other, "get_window_size: ioctl failed"))
        }
    }
    Ok((ws.ws_row, ws.ws_col))
}

fn editor_draw_rows(stdout: &mut Stdout, e: &EditorConfig) -> io::Result<()> {
    for y in 0..(e.screenrows) {
        stdout.write(b"~")?;

        stdout.write(b"\x1b[K")?;
        if y < e.screenrows - 1 {
            stdout.write(b"\r\n")?;
        }
    }
    Ok(())
}

fn editor_refresh_screen(stdout: &mut Stdout, e: &EditorConfig) -> io::Result<()> {
    stdout.write(b"\x1b[?25l")?;
    stdout.write(b"\x1b[H")?;

    editor_draw_rows(stdout, e)?;

    stdout.write(b"\x1b[H")?;
    stdout.write(b"\x1b[?25h")?;
    stdout.flush()
}

fn editor_process_keypress(stdin: &mut Stdin) -> bool {
    let c = editor_read_key(stdin);

    match c {
        k if k == ctrl_key!(b'q') => {
            false
        },
        _ => true
    }
}

fn main() {
    let mut editor = Editor::new(EditorConfig::new());

    editor_refresh_screen(&mut editor.stdout, &editor.config).unwrap();
    while editor_process_keypress(&mut editor.stdin) {
        editor_refresh_screen(&mut editor.stdout, &editor.config).unwrap();
    }
}
<|endoftext|>


<commit_before>extern crate winapi;
extern crate winit;

use com::{ComPtr, ToResult, HResult, as_ptr};
use std::ptr;
use winapi::shared::dxgi1_2::DXGI_SWAP_CHAIN_DESC1;
use winapi::shared::dxgi1_2::IDXGIFactory2;
use winapi::shared::minwindef::{TRUE, FALSE};
use winapi::shared::windef::HWND;
use winapi::shared::winerror::S_OK;
use winapi::um::d3d11::ID3D11Device;
use winapi::um::dcomp::IDCompositionDevice;
use winapi::um::dcomp::IDCompositionTarget;
use winapi::um::dcomp::IDCompositionVisual;
use winit::os::windows::WindowExt;

mod com;

fn main() {
    let mut events_loop = winit::EventsLoop::new();
    let window = winit::WindowBuilder::new()
        .with_title("Hello, world!")
        .with_dimensions(1024, 768)
        .build(&events_loop)
        .unwrap();

    let _composition = unsafe {
        initialize(window.get_hwnd() as _).unwrap()
    };

    if std::env::var_os("INIT_ONLY").is_some() {
//        return
    }

    events_loop.run_forever(|event| match event {
        winit::Event::WindowEvent { event: winit::WindowEvent::Closed, .. } => {
            winit::ControlFlow::Break
        }
        _ => winit::ControlFlow::Continue,
    });
}

/// https://msdn.microsoft.com/en-us/library/windows/desktop/hh449180(v=vs.85).aspx

unsafe fn initialize(hwnd: HWND) -> HResult<(
    DirectComposition,
    ComPtr<winapi::shared::dxgi1_2::IDXGISwapChain1>,
    ComPtr<winapi::um::d3d11::ID3D11Texture2D>,
    ComPtr<winapi::um::d3d11::ID3D11DeviceContext>,
)> {
    let mut composition = DirectComposition::new(hwnd)?;

    let swap_chain = composition.create_swap_chain(300, 200)?;
    composition.root_visual.SetContent(&*****swap_chain).to_result()?;
    composition.composition_device.Commit().to_result()?;

    let back_buffer = ComPtr::<winapi::um::d3d11::ID3D11Texture2D>::new_with_uuid(|uuid, ptr_ptr| {
        swap_chain.GetBuffer(0, uuid, ptr_ptr)
    })?;
    let render_target = ComPtr::new_with(|ptr_ptr| {
        composition.d3d_device.CreateRenderTargetView(
            as_ptr(&back_buffer), ptr::null_mut(), ptr_ptr,
        )
    })?;
    let context = ComPtr::new_with(|ptr_ptr| {
        composition.d3d_device.GetImmediateContext(ptr_ptr);
        S_OK
    })?;
    context.OMSetRenderTargets(1, &render_target.as_raw(), ptr::null_mut());
    let green_rgba = [0., 0.5, 0., 1.];
    context.ClearRenderTargetView(render_target.as_raw(), &green_rgba);
    swap_chain.Present(0, 0).to_result()?;

    Ok((composition, swap_chain, back_buffer, context))
}

#[allow(unused)]
struct DirectComposition {
    d3d_device: ComPtr<ID3D11Device>,
    dxgi_factory: ComPtr<IDXGIFactory2>,
    composition_device: ComPtr<IDCompositionDevice>,
    composition_target: ComPtr<IDCompositionTarget>,
    root_visual: ComPtr<IDCompositionVisual>,
}

impl DirectComposition {
    unsafe fn new(hwnd: HWND) -> HResult<Self> {
        let mut feature_level_supported = 0;

        let d3d_device = ComPtr::new_with(|ptr_ptr| winapi::um::d3d11::D3D11CreateDevice(
            ptr::null_mut(),
            winapi::um::d3dcommon::D3D_DRIVER_TYPE_HARDWARE,
            ptr::null_mut(),
            winapi::um::d3d11::D3D11_CREATE_DEVICE_BGRA_SUPPORT |
            if cfg!(debug_assertions) {
                winapi::um::d3d11::D3D11_CREATE_DEVICE_DEBUG
            } else {
                0
            },
            ptr::null_mut(),
            0,
            winapi::um::d3d11::D3D11_SDK_VERSION,
            ptr_ptr,
            &mut feature_level_supported,
            ptr::null_mut(),
        ))?;

        let dxgi_device = d3d_device.cast::<winapi::shared::dxgi::IDXGIDevice>()?;

        // https://msdn.microsoft.com/en-us/library/windows/desktop/hh404556(v=vs.85).aspx#code-snippet-1
        // “Because you can create a Direct3D device without creating a swap chain,
        //  you might need to retrieve the factory that is used to create the device
        //  in order to create a swap chain.”
        let adapter = ComPtr::new_with(|ptr_ptr| dxgi_device.GetAdapter(ptr_ptr))?;
        let dxgi_factory = ComPtr::<IDXGIFactory2>::new_with_uuid(|uuid, ptr_ptr| {
            adapter.GetParent(uuid, ptr_ptr)
        })?;

        // Create the DirectComposition device object.
        let composition_device = ComPtr::<IDCompositionDevice>::new_with_uuid(|uuid, ptr_ptr| {
            winapi::um::dcomp::DCompositionCreateDevice(&*dxgi_device, uuid,ptr_ptr)
        })?;

        // Create the composition target object based on the
        // specified application window.
        let composition_target = ComPtr::new_with(|ptr_ptr| {
            composition_device.CreateTargetForHwnd(hwnd, TRUE, ptr_ptr)
        })?;

        let root_visual = ComPtr::new_with(|ptr_ptr| composition_device.CreateVisual(ptr_ptr))?;
        composition_target.SetRoot(&*root_visual).to_result()?;

        Ok(DirectComposition {
            d3d_device, dxgi_factory, composition_device, composition_target, root_visual,
        })
    }

    unsafe fn create_swap_chain(&mut self, width: u32, height: u32)
        -> HResult<ComPtr<winapi::shared::dxgi1_2::IDXGISwapChain1>>
    {
        let desc = DXGI_SWAP_CHAIN_DESC1 {
            Width: width,
            Height: height,
            Format: winapi::shared::dxgiformat::DXGI_FORMAT_B8G8R8A8_UNORM,
            Stereo: FALSE,
            SampleDesc: winapi::shared::dxgitype::DXGI_SAMPLE_DESC {
                Count: 1,
                Quality: 0,
            },
            BufferUsage: winapi::shared::dxgitype::DXGI_USAGE_RENDER_TARGET_OUTPUT,
            BufferCount: 2,
            Scaling: winapi::shared::dxgi1_2::DXGI_SCALING_STRETCH,
            SwapEffect: winapi::shared::dxgi::DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL,
            AlphaMode:  winapi::shared::dxgi1_2::DXGI_ALPHA_MODE_IGNORE,
            Flags: 0,
        };
        ComPtr::<winapi::shared::dxgi1_2::IDXGISwapChain1>::new_with(|ptr_ptr| {
            self.dxgi_factory.CreateSwapChainForComposition(
                as_ptr(&self.d3d_device),
                &desc,
                ptr::null_mut(),
                ptr_ptr,
            )
        })
    }
}
<commit_msg>Try to provide safe APIs. (Still needs safety review.)<commit_after>extern crate winapi;
extern crate winit;

use com::{ComPtr, ToResult, HResult, as_ptr};
use std::ptr;
use winapi::shared::dxgi1_2::DXGI_SWAP_CHAIN_DESC1;
use winapi::shared::dxgi1_2::IDXGIFactory2;
use winapi::shared::minwindef::{TRUE, FALSE};
use winapi::shared::windef::HWND;
use winapi::shared::winerror::S_OK;
use winapi::um::d3d11::ID3D11Device;
use winapi::um::dcomp::IDCompositionDevice;
use winapi::um::dcomp::IDCompositionTarget;
use winapi::um::dcomp::IDCompositionVisual;
use winit::os::windows::WindowExt;

mod com;

fn main() {
    let mut events_loop = winit::EventsLoop::new();
    let window = winit::WindowBuilder::new()
        .with_title("Hello, world!")
        .with_dimensions(1024, 768)
        .build(&events_loop)
        .unwrap();

    let _composition = initialize(window.get_hwnd() as _).unwrap();

    if std::env::var_os("INIT_ONLY").is_some() {
        return
    }

    events_loop.run_forever(|event| match event {
        winit::Event::WindowEvent { event: winit::WindowEvent::Closed, .. } => {
            winit::ControlFlow::Break
        }
        _ => winit::ControlFlow::Continue,
    });
}

/// https://msdn.microsoft.com/en-us/library/windows/desktop/hh449180(v=vs.85).aspx

fn initialize(hwnd: HWND) -> HResult<DirectComposition> {
    unsafe {
        let mut composition = DirectComposition::new(hwnd)?;

        let swap_chain = composition.create_swap_chain(300, 200)?;
        composition.root_visual.SetContent(&*****swap_chain).to_result()?;
        composition.composition_device.Commit().to_result()?;

        let back_buffer = ComPtr::<winapi::um::d3d11::ID3D11Texture2D>::new_with_uuid(|uuid, ptr_ptr| {
            swap_chain.GetBuffer(0, uuid, ptr_ptr)
        })?;
        let render_target = ComPtr::new_with(|ptr_ptr| {
            composition.d3d_device.CreateRenderTargetView(
                as_ptr(&back_buffer), ptr::null_mut(), ptr_ptr,
            )
        })?;
        let context = ComPtr::new_with(|ptr_ptr| {
            composition.d3d_device.GetImmediateContext(ptr_ptr);
            S_OK
        })?;
        context.OMSetRenderTargets(1, &render_target.as_raw(), ptr::null_mut());
        let green_rgba = [0., 0.5, 0., 1.];
        context.ClearRenderTargetView(render_target.as_raw(), &green_rgba);
        swap_chain.Present(0, 0).to_result()?;

        Ok(composition)
    }
}

#[allow(unused)]
struct DirectComposition {
    d3d_device: ComPtr<ID3D11Device>,
    dxgi_factory: ComPtr<IDXGIFactory2>,
    composition_device: ComPtr<IDCompositionDevice>,
    composition_target: ComPtr<IDCompositionTarget>,
    root_visual: ComPtr<IDCompositionVisual>,
}

impl DirectComposition {
    pub fn new(hwnd: HWND) -> HResult<Self> {
        unsafe {
            let mut feature_level_supported = 0;

            let d3d_device = ComPtr::new_with(|ptr_ptr| winapi::um::d3d11::D3D11CreateDevice(
                ptr::null_mut(),
                winapi::um::d3dcommon::D3D_DRIVER_TYPE_HARDWARE,
                ptr::null_mut(),
                winapi::um::d3d11::D3D11_CREATE_DEVICE_BGRA_SUPPORT |
                if cfg!(debug_assertions) {
                    winapi::um::d3d11::D3D11_CREATE_DEVICE_DEBUG
                } else {
                    0
                },
                ptr::null_mut(),
                0,
                winapi::um::d3d11::D3D11_SDK_VERSION,
                ptr_ptr,
                &mut feature_level_supported,
                ptr::null_mut(),
            ))?;

            let dxgi_device = d3d_device.cast::<winapi::shared::dxgi::IDXGIDevice>()?;

            // https://msdn.microsoft.com/en-us/library/windows/desktop/hh404556(v=vs.85).aspx#code-snippet-1
            // “Because you can create a Direct3D device without creating a swap chain,
            //  you might need to retrieve the factory that is used to create the device
            //  in order to create a swap chain.”
            let adapter = ComPtr::new_with(|ptr_ptr| dxgi_device.GetAdapter(ptr_ptr))?;
            let dxgi_factory = ComPtr::<IDXGIFactory2>::new_with_uuid(|uuid, ptr_ptr| {
                adapter.GetParent(uuid, ptr_ptr)
            })?;

            // Create the DirectComposition device object.
            let composition_device = ComPtr::<IDCompositionDevice>::new_with_uuid(|uuid, ptr_ptr| {
                winapi::um::dcomp::DCompositionCreateDevice(&*dxgi_device, uuid,ptr_ptr)
            })?;

            // Create the composition target object based on the
            // specified application window.
            let composition_target = ComPtr::new_with(|ptr_ptr| {
                composition_device.CreateTargetForHwnd(hwnd, TRUE, ptr_ptr)
            })?;

            let root_visual = ComPtr::new_with(|ptr_ptr| composition_device.CreateVisual(ptr_ptr))?;
            composition_target.SetRoot(&*root_visual).to_result()?;

            Ok(DirectComposition {
                d3d_device, dxgi_factory, composition_device, composition_target, root_visual,
            })
        }
    }

    pub fn create_swap_chain(&mut self, width: u32, height: u32)
        -> HResult<ComPtr<winapi::shared::dxgi1_2::IDXGISwapChain1>>
    {
        unsafe {
            let desc = DXGI_SWAP_CHAIN_DESC1 {
                Width: width,
                Height: height,
                Format: winapi::shared::dxgiformat::DXGI_FORMAT_B8G8R8A8_UNORM,
                Stereo: FALSE,
                SampleDesc: winapi::shared::dxgitype::DXGI_SAMPLE_DESC {
                    Count: 1,
                    Quality: 0,
                },
                BufferUsage: winapi::shared::dxgitype::DXGI_USAGE_RENDER_TARGET_OUTPUT,
                BufferCount: 2,
                Scaling: winapi::shared::dxgi1_2::DXGI_SCALING_STRETCH,
                SwapEffect: winapi::shared::dxgi::DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL,
                AlphaMode:  winapi::shared::dxgi1_2::DXGI_ALPHA_MODE_IGNORE,
                Flags: 0,
            };
            ComPtr::<winapi::shared::dxgi1_2::IDXGISwapChain1>::new_with(|ptr_ptr| {
                self.dxgi_factory.CreateSwapChainForComposition(
                    as_ptr(&self.d3d_device),
                    &desc,
                    ptr::null_mut(),
                    ptr_ptr,
                )
            })
        }
    }
}
<|endoftext|>