<commit_before>// Copyright 2016 Matthew Collins
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![recursion_limit="300"]
#![feature(const_fn)]
#![feature(plugin)]

// #![plugin(clippy)]
// #![allow(similar_names)]
// #![allow(new_without_default)]
// #![allow(many_single_char_names)]
// #![allow(if_not_else)]
// #![allow(float_cmp)]
// #![allow(single_char_pattern)]
// #![allow(too_many_arguments)]
// #![allow(cyclomatic_complexity)]

extern crate sdl2;
extern crate image;
extern crate time;
extern crate byteorder;
extern crate serde_json;
extern crate steven_openssl as openssl;
extern crate hyper;
extern crate flate2;
extern crate rand;
extern crate rustc_serialize;
extern crate cgmath;
#[macro_use]
extern crate log;
#[macro_use]
extern crate lazy_static;
extern crate collision;
pub extern crate steven_blocks;
extern crate steven_shared as shared;

#[macro_use]
pub mod macros;

pub mod ecs;
pub mod protocol;
pub mod format;
pub mod nbt;
pub mod item;
pub mod gl;
pub mod types;
pub mod resources;
pub mod render;
pub mod ui;
pub mod screen;
#[macro_use]
pub mod console;
pub mod server;
pub mod world;
pub mod chunk_builder;
pub mod auth;
pub mod model;
pub mod entity;

use std::sync::{Arc, RwLock, Mutex};
use std::marker::PhantomData;
use std::thread;
use std::sync::mpsc;

const CL_BRAND: console::CVar<String> = console::CVar {
    ty: PhantomData,
    name: "cl_brand",
    description: "cl_brand has the value of the clients current 'brand'. e.g. \"Steven\" or \
                  \"Vanilla\"",
    mutable: false,
    serializable: false,
    default: &|| "Steven".to_owned(),
};

pub struct Game {
    renderer: render::Renderer,
    screen_sys: screen::ScreenSystem,
    resource_manager: Arc<RwLock<resources::Manager>>,
    console: Arc<Mutex<console::Console>>,
    should_close: bool,

    server: server::Server,
    focused: bool,
    chunk_builder: chunk_builder::ChunkBuilder,

    connect_reply: Option<mpsc::Receiver<Result<server::Server, protocol::Error>>>,
}

impl Game {
    pub fn connect_to(&mut self, address: &str) {
        let (tx, rx) = mpsc::channel();
        self.connect_reply = Some(rx);
        let address = address.to_owned();
        let resources = self.resource_manager.clone();
        let console = self.console.clone();
        thread::spawn(move || {
            tx.send(server::Server::connect(resources, console, &address)).unwrap();
        });
    }

    pub fn tick(&mut self, delta: f64) {
        if !self.server.is_connected() {
            self.renderer.camera.pos = cgmath::Point3::new(0.5, 13.2, 0.5);
            self.renderer.camera.yaw += 0.005 * delta;
            if self.renderer.camera.yaw > ::std::f64::consts::PI * 2.0 {
                self.renderer.camera.yaw = 0.0;
            }
        }
        let mut clear_reply = false;
        if let Some(ref recv) = self.connect_reply {
            if let Ok(server) = recv.try_recv() {
                clear_reply = true;
                match server {
                    Ok(val) => {
                        self.screen_sys.pop_screen();
                        self.focused = true;
                        self.server.remove(&mut self.renderer);
                        self.server = val;
                    },
                    Err(err) => {
                        let msg = match err {
                            protocol::Error::Disconnect(val) => val,
                            err => {
                                let mut msg = format::TextComponent::new(&format!("{}", err));
                                msg.modifier.color = Some(format::Color::Red);
                                format::Component::Text(msg)
                            },
                        };
                        self.screen_sys.replace_screen(Box::new(screen::ServerList::new(
                            Some(msg)
                        )));
                    }
                }
            }
        }
        if clear_reply {
            self.connect_reply = None;
        }
    }
}

fn main() {
    let con = Arc::new(Mutex::new(console::Console::new()));
    {
        let mut con = con.lock().unwrap();
        con.register(CL_BRAND);
        auth::register_vars(&mut con);
        con.load_config();
        con.save_config();
    }

    let proxy = console::ConsoleProxy::new(con.clone());

    log::set_logger(|max_log_level| {
        max_log_level.set(log::LogLevelFilter::Trace);
        Box::new(proxy)
    }).unwrap();

    info!("Starting steven");

    let resource_manager = Arc::new(RwLock::new(resources::Manager::new()));
    {
        resource_manager.write().unwrap().tick();
    }

    let sdl = sdl2::init().unwrap();
    let sdl_video = sdl.video().unwrap();

    sdl_video.gl_set_swap_interval(1);

    let window = sdl2::video::WindowBuilder::new(&sdl_video, "Steven", 854, 480)
                            .opengl()
                            .resizable()
                            .build()
                            .expect("Could not create sdl window.");
    let gl_attr = sdl_video.gl_attr();
    gl_attr.set_stencil_size(0);
    gl_attr.set_depth_size(24);
    gl_attr.set_context_major_version(3);
    gl_attr.set_context_minor_version(2);
    gl_attr.set_context_profile(sdl2::video::GLProfile::Core);

    let gl_context = window.gl_create_context().unwrap();
    window.gl_make_current(&gl_context).expect("Could not set current context.");

    gl::init(&sdl_video);

    let renderer = render::Renderer::new(resource_manager.clone());
    let mut ui_container = ui::Container::new();

    let mut last_frame = time::now();
    let frame_time = (time::Duration::seconds(1).num_nanoseconds().unwrap() as f64) / 60.0;

    let mut screen_sys = screen::ScreenSystem::new();
    screen_sys.add_screen(Box::new(screen::Login::new(con.clone())));

    let textures = renderer.get_textures();
    let mut game = Game {
        server: server::Server::dummy_server(resource_manager.clone(), con.clone()),
        focused: false,
        renderer: renderer,
        screen_sys: screen_sys,
        resource_manager: resource_manager.clone(),
        console: con,
        should_close: false,
        chunk_builder: chunk_builder::ChunkBuilder::new(resource_manager, textures),
        connect_reply: None,
    };

    let mut events = sdl.event_pump().unwrap();
    while !game.should_close {
        let version = {
            let mut res = game.resource_manager.write().unwrap();
            res.tick();
            res.version()
        };

        let now = time::now();
        let diff = now - last_frame;
        last_frame = now;
        let delta = (diff.num_nanoseconds().unwrap() as f64) / frame_time;
        let (width, height) = window.drawable_size();

        game.tick(delta);
        game.server.tick(&mut game.renderer, delta);

        game.renderer.update_camera(width, height);
        game.server.world.compute_render_list(&mut game.renderer);
        game.chunk_builder.tick(&mut game.server.world, &mut game.renderer, version);

        game.screen_sys.tick(delta, &mut game.renderer, &mut ui_container);
        game.console
            .lock()
            .unwrap()
            .tick(&mut ui_container, &mut game.renderer, delta, width as f64);
        ui_container.tick(&mut game.renderer, delta, width as f64, height as f64);
        game.renderer.tick(&mut game.server.world, delta, width, height);

        window.gl_swap_window();

        for event in events.poll_iter() {
            handle_window_event(&window, &mut game, &mut ui_container, event)
        }
    }
}

fn handle_window_event(window: &sdl2::video::Window,
                       game: &mut Game,
                       ui_container: &mut ui::Container,
                       event: sdl2::event::Event) {
    use sdl2::event::Event;
    use sdl2::keyboard::Keycode;
    use sdl2::mouse::Mouse;
    use std::f64::consts::PI;

    let mouse = window.subsystem().sdl().mouse();

    match event {
        Event::Quit{..} => game.should_close = true,

        Event::MouseMotion{x, y, xrel, yrel, ..} => {
            let (width, height) = window.size();
            if game.focused {
                if !mouse.relative_mouse_mode() {
                    mouse.set_relative_mouse_mode(true);
                }
                if let Some(player) = game.server.player {
                    let s = 2000.0 + 0.01;
                    let (rx, ry) = (xrel as f64 / s, yrel as f64 / s);
                    let rotation = game.server.entities.get_component_mut(player, game.server.rotation).unwrap();
                    rotation.yaw -= rx;
                    rotation.pitch -= ry;
                    if rotation.pitch < (PI/2.0) + 0.01 {
                        rotation.pitch = (PI/2.0) + 0.01;
                    }
                    if rotation.pitch > (PI/2.0)*3.0 - 0.01 {
                        rotation.pitch = (PI/2.0)*3.0 - 0.01;
                    }
                }
            } else {
                ui_container.hover_at(game, x as f64, y as f64, width as f64, height as f64);
            }
        }
        Event::MouseButtonUp{mouse_btn: Mouse::Left, x, y, ..} => {
            let (width, height) = window.size();

            if game.server.is_connected() && !game.focused {
                game.focused = true;
                mouse.set_relative_mouse_mode(true);
                mouse.warp_mouse_in_window(&window, (width/2) as i32, (height/2) as i32);
                return;
            }
            if !game.focused {
                ui_container.click_at(game, x as f64, y as f64, width as f64, height as f64);
            }
        }
        Event::MouseWheel{x, y, ..} => {
            game.screen_sys.on_scroll(x as f64, y as f64);
        }
        Event::KeyUp{keycode: Some(Keycode::Escape), ..} => {
            if game.focused {
                mouse.set_relative_mouse_mode(false);
                game.focused = false;
            }
        }
        Event::KeyDown{keycode: Some(Keycode::Backquote), ..} => {
            game.console.lock().unwrap().toggle();
        }
        Event::KeyDown{keycode: Some(key), ..} => {
            if game.focused {
                game.server.key_press(true, key);
            } else {
                ui_container.key_press(game, key, true);
            }
        }
        Event::KeyUp{keycode: Some(key), ..} => {
            if game.focused {
                game.server.key_press(false, key);
            } else {
                ui_container.key_press(game, key, false);
            }
        }
        Event::TextInput{text, ..} => {
            if !game.focused {
                for c in text.chars() {
                    ui_container.key_type(game, c);
                }
            }
        }
        _ => (),
    }
}
<commit_msg>Remove commented out clippy settings<commit_after>// Copyright 2016 Matthew Collins
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![recursion_limit="300"]
#![feature(const_fn)]
#![feature(plugin)]

extern crate sdl2;
extern crate image;
extern crate time;
extern crate byteorder;
extern crate serde_json;
extern crate steven_openssl as openssl;
extern crate hyper;
extern crate flate2;
extern crate rand;
extern crate rustc_serialize;
extern crate cgmath;
#[macro_use]
extern crate log;
#[macro_use]
extern crate lazy_static;
extern crate collision;
pub extern crate steven_blocks;
extern crate steven_shared as shared;

#[macro_use]
pub mod macros;

pub mod ecs;
pub mod protocol;
pub mod format;
pub mod nbt;
pub mod item;
pub mod gl;
pub mod types;
pub mod resources;
pub mod render;
pub mod ui;
pub mod screen;
#[macro_use]
pub mod console;
pub mod server;
pub mod world;
pub mod chunk_builder;
pub mod auth;
pub mod model;
pub mod entity;

use std::sync::{Arc, RwLock, Mutex};
use std::marker::PhantomData;
use std::thread;
use std::sync::mpsc;

const CL_BRAND: console::CVar<String> = console::CVar {
    ty: PhantomData,
    name: "cl_brand",
    description: "cl_brand has the value of the clients current 'brand'. e.g. \"Steven\" or \
                  \"Vanilla\"",
    mutable: false,
    serializable: false,
    default: &|| "Steven".to_owned(),
};

pub struct Game {
    renderer: render::Renderer,
    screen_sys: screen::ScreenSystem,
    resource_manager: Arc<RwLock<resources::Manager>>,
    console: Arc<Mutex<console::Console>>,
    should_close: bool,

    server: server::Server,
    focused: bool,
    chunk_builder: chunk_builder::ChunkBuilder,

    connect_reply: Option<mpsc::Receiver<Result<server::Server, protocol::Error>>>,
}

impl Game {
    pub fn connect_to(&mut self, address: &str) {
        let (tx, rx) = mpsc::channel();
        self.connect_reply = Some(rx);
        let address = address.to_owned();
        let resources = self.resource_manager.clone();
        let console = self.console.clone();
        thread::spawn(move || {
            tx.send(server::Server::connect(resources, console, &address)).unwrap();
        });
    }

    pub fn tick(&mut self, delta: f64) {
        if !self.server.is_connected() {
            self.renderer.camera.pos = cgmath::Point3::new(0.5, 13.2, 0.5);
            self.renderer.camera.yaw += 0.005 * delta;
            if self.renderer.camera.yaw > ::std::f64::consts::PI * 2.0 {
                self.renderer.camera.yaw = 0.0;
            }
        }
        let mut clear_reply = false;
        if let Some(ref recv) = self.connect_reply {
            if let Ok(server) = recv.try_recv() {
                clear_reply = true;
                match server {
                    Ok(val) => {
                        self.screen_sys.pop_screen();
                        self.focused = true;
                        self.server.remove(&mut self.renderer);
                        self.server = val;
                    },
                    Err(err) => {
                        let msg = match err {
                            protocol::Error::Disconnect(val) => val,
                            err => {
                                let mut msg = format::TextComponent::new(&format!("{}", err));
                                msg.modifier.color = Some(format::Color::Red);
                                format::Component::Text(msg)
                            },
                        };
                        self.screen_sys.replace_screen(Box::new(screen::ServerList::new(
                            Some(msg)
                        )));
                    }
                }
            }
        }
        if clear_reply {
            self.connect_reply = None;
        }
    }
}

fn main() {
    let con = Arc::new(Mutex::new(console::Console::new()));
    {
        let mut con = con.lock().unwrap();
        con.register(CL_BRAND);
        auth::register_vars(&mut con);
        con.load_config();
        con.save_config();
    }

    let proxy = console::ConsoleProxy::new(con.clone());

    log::set_logger(|max_log_level| {
        max_log_level.set(log::LogLevelFilter::Trace);
        Box::new(proxy)
    }).unwrap();

    info!("Starting steven");

    let resource_manager = Arc::new(RwLock::new(resources::Manager::new()));
    {
        resource_manager.write().unwrap().tick();
    }

    let sdl = sdl2::init().unwrap();
    let sdl_video = sdl.video().unwrap();

    sdl_video.gl_set_swap_interval(1);

    let window = sdl2::video::WindowBuilder::new(&sdl_video, "Steven", 854, 480)
                            .opengl()
                            .resizable()
                            .build()
                            .expect("Could not create sdl window.");
    let gl_attr = sdl_video.gl_attr();
    gl_attr.set_stencil_size(0);
    gl_attr.set_depth_size(24);
    gl_attr.set_context_major_version(3);
    gl_attr.set_context_minor_version(2);
    gl_attr.set_context_profile(sdl2::video::GLProfile::Core);

    let gl_context = window.gl_create_context().unwrap();
    window.gl_make_current(&gl_context).expect("Could not set current context.");

    gl::init(&sdl_video);

    let renderer = render::Renderer::new(resource_manager.clone());
    let mut ui_container = ui::Container::new();

    let mut last_frame = time::now();
    let frame_time = (time::Duration::seconds(1).num_nanoseconds().unwrap() as f64) / 60.0;

    let mut screen_sys = screen::ScreenSystem::new();
    screen_sys.add_screen(Box::new(screen::Login::new(con.clone())));

    let textures = renderer.get_textures();
    let mut game = Game {
        server: server::Server::dummy_server(resource_manager.clone(), con.clone()),
        focused: false,
        renderer: renderer,
        screen_sys: screen_sys,
        resource_manager: resource_manager.clone(),
        console: con,
        should_close: false,
        chunk_builder: chunk_builder::ChunkBuilder::new(resource_manager, textures),
        connect_reply: None,
    };

    let mut events = sdl.event_pump().unwrap();
    while !game.should_close {
        let version = {
            let mut res = game.resource_manager.write().unwrap();
            res.tick();
            res.version()
        };

        let now = time::now();
        let diff = now - last_frame;
        last_frame = now;
        let delta = (diff.num_nanoseconds().unwrap() as f64) / frame_time;
        let (width, height) = window.drawable_size();

        game.tick(delta);
        game.server.tick(&mut game.renderer, delta);

        game.renderer.update_camera(width, height);
        game.server.world.compute_render_list(&mut game.renderer);
        game.chunk_builder.tick(&mut game.server.world, &mut game.renderer, version);

        game.screen_sys.tick(delta, &mut game.renderer, &mut ui_container);
        game.console
            .lock()
            .unwrap()
            .tick(&mut ui_container, &mut game.renderer, delta, width as f64);
        ui_container.tick(&mut game.renderer, delta, width as f64, height as f64);
        game.renderer.tick(&mut game.server.world, delta, width, height);

        window.gl_swap_window();

        for event in events.poll_iter() {
            handle_window_event(&window, &mut game, &mut ui_container, event)
        }
    }
}

fn handle_window_event(window: &sdl2::video::Window,
                       game: &mut Game,
                       ui_container: &mut ui::Container,
                       event: sdl2::event::Event) {
    use sdl2::event::Event;
    use sdl2::keyboard::Keycode;
    use sdl2::mouse::Mouse;
    use std::f64::consts::PI;

    let mouse = window.subsystem().sdl().mouse();

    match event {
        Event::Quit{..} => game.should_close = true,

        Event::MouseMotion{x, y, xrel, yrel, ..} => {
            let (width, height) = window.size();
            if game.focused {
                if !mouse.relative_mouse_mode() {
                    mouse.set_relative_mouse_mode(true);
                }
                if let Some(player) = game.server.player {
                    let s = 2000.0 + 0.01;
                    let (rx, ry) = (xrel as f64 / s, yrel as f64 / s);
                    let rotation = game.server.entities.get_component_mut(player, game.server.rotation).unwrap();
                    rotation.yaw -= rx;
                    rotation.pitch -= ry;
                    if rotation.pitch < (PI/2.0) + 0.01 {
                        rotation.pitch = (PI/2.0) + 0.01;
                    }
                    if rotation.pitch > (PI/2.0)*3.0 - 0.01 {
                        rotation.pitch = (PI/2.0)*3.0 - 0.01;
                    }
                }
            } else {
                ui_container.hover_at(game, x as f64, y as f64, width as f64, height as f64);
            }
        }
        Event::MouseButtonUp{mouse_btn: Mouse::Left, x, y, ..} => {
            let (width, height) = window.size();

            if game.server.is_connected() && !game.focused {
                game.focused = true;
                mouse.set_relative_mouse_mode(true);
                mouse.warp_mouse_in_window(&window, (width/2) as i32, (height/2) as i32);
                return;
            }
            if !game.focused {
                ui_container.click_at(game, x as f64, y as f64, width as f64, height as f64);
            }
        }
        Event::MouseWheel{x, y, ..} => {
            game.screen_sys.on_scroll(x as f64, y as f64);
        }
        Event::KeyUp{keycode: Some(Keycode::Escape), ..} => {
            if game.focused {
                mouse.set_relative_mouse_mode(false);
                game.focused = false;
            }
        }
        Event::KeyDown{keycode: Some(Keycode::Backquote), ..} => {
            game.console.lock().unwrap().toggle();
        }
        Event::KeyDown{keycode: Some(key), ..} => {
            if game.focused {
                game.server.key_press(true, key);
            } else {
                ui_container.key_press(game, key, true);
            }
        }
        Event::KeyUp{keycode: Some(key), ..} => {
            if game.focused {
                game.server.key_press(false, key);
            } else {
                ui_container.key_press(game, key, false);
            }
        }
        Event::TextInput{text, ..} => {
            if !game.focused {
                for c in text.chars() {
                    ui_container.key_type(game, c);
                }
            }
        }
        _ => (),
    }
}
<|endoftext|>


<commit_before>extern crate xmltree;

#[macro_use]
mod utils;

use std::path::Path;
use std::path::PathBuf;
use std::collections::HashMap;
use xmltree::Element;

const NAME: &str = "msp430-gcc-support-files/targetdb/devices/CC430F5123.xml";

fn main() {
    let file_name = &PathBuf::from(NAME);
    let dev = parse_dslite(file_name);
    //println!("{:#?}", dev);
}

#[derive(Debug)]
pub struct Device {
    name: String,
    modules: HashMap<String, Module>,
}

pub fn parse_dslite(file_name: &Path) -> Device {
    let el = uw!(utils::load_xml(file_name));

    let name = uw!(el.attributes.get("id")).to_owned();
    let cpu = uw!(el.children.iter().find(|i| i.name == "cpu"));

    let mut modules = HashMap::new();
    let mut registers = Vec::new();
    for i in &cpu.children {
        if let Some(module) = parse_cpu_instance(i, file_name) {
            modules.insert(module.name.clone(), module.clone());
            for r in module.registers {
                registers.push(r);
            }
        }
    }

    println!("{:#?}", registers);

    Device {
        name: name,
        modules: modules,
    }
}

#[derive(Debug, Clone)]
struct Module {
    name: String,
    registers: Vec<Register>,
}

fn parse_cpu_instance(el: &Element, root_file: &Path) -> Option<Module> {
    assert_eq!(el.name, "instance");
    let base = uw!(utils::parse_u32(uw!(el.attributes.get("baseaddr"))));
    assert_eq!(base, 0);

    let href = uw!(el.attributes.get("href")).to_owned();
    let root_path = uw!(root_file.parent());
    let module_path = root_path.join(href);

    parse_dslite_module(&module_path)
}

fn parse_dslite_module(file_name: &Path) -> Option<Module> {
    let el = uw!(utils::load_xml(file_name));

    assert_eq!(el.name, "module");
    match el.attributes.get("hidden") {
        Some(val) if val == "true" => return None,
        _ => {}
    }

    let name = uw!(el.attributes.get("id")).to_owned();
    let registers = el.children.iter()
        .map(|r| parse_register(r, &name))
        .collect::<Vec<_>>();

    Some(Module {
             name: name,
             registers: registers,
         })
}

#[derive(Debug, Clone)]
struct Register {
    name: String,
    module: String,
    offset: u32,
    width: u32,
}

fn parse_register(el: &Element, module: &str) -> Register {
    assert_eq!(el.name, "register");

    let name = uw!(el.attributes.get("acronym")).to_owned();
    let offset = uw!(utils::parse_u32(uw!(el.attributes.get("offset"))));
    let width = uw!(utils::parse_u32(uw!(el.attributes.get("width"))));

    Register {
        name: name,
        offset: offset,
        width: width,
        module: module.to_owned(),
    }
}
<commit_msg>track overlap<commit_after>extern crate xmltree;

#[macro_use]
mod utils;

use std::path::Path;
use std::path::PathBuf;
use std::collections::HashMap;
use xmltree::Element;

const NAME: &str = "msp430-gcc-support-files/targetdb/devices/CC430F5123.xml";

fn main() {
    let file_name = &PathBuf::from(NAME);
    let dev = parse_dslite(file_name);
    //println!("{:#?}", dev);
}

#[derive(Debug)]
pub struct Device {
    name: String,
    modules: HashMap<String, Module>,
}

pub fn parse_dslite(file_name: &Path) -> Device {
    let el = uw!(utils::load_xml(file_name));

    let name = uw!(el.attributes.get("id")).to_owned();
    let cpu = uw!(el.children.iter().find(|i| i.name == "cpu"));

    let mut modules = HashMap::new();
    let mut registers = Vec::new();
    for i in &cpu.children {
        if let Some(module) = parse_cpu_instance(i, file_name) {
            modules.insert(module.name.clone(), module.clone());
            for r in module.registers {
                registers.push(r);
            }
        }
    }

    registers.sort_by_key(|r| r.offset * 4 + r.width / 8);

    let mut next_address = 0;
    let mut prev_per = None;
    for r in &registers {
        if r.offset < next_address {
            println!("overlap: {:?}\n\t{:?}", prev_per, r);
        } else {
            next_address = r.offset + (r.width / 8);
            prev_per = Some(r)
        }
    }

    //println!("{:#?}", registers);

    Device {
        name: name,
        modules: modules,
    }
}

#[derive(Debug, Clone)]
struct Module {
    name: String,
    registers: Vec<Register>,
}

fn parse_cpu_instance(el: &Element, root_file: &Path) -> Option<Module> {
    assert_eq!(el.name, "instance");
    let base = uw!(utils::parse_u32(uw!(el.attributes.get("baseaddr"))));
    assert_eq!(base, 0);

    let href = uw!(el.attributes.get("href")).to_owned();
    let root_path = uw!(root_file.parent());
    let module_path = root_path.join(href);

    parse_dslite_module(&module_path)
}

fn parse_dslite_module(file_name: &Path) -> Option<Module> {
    let el = uw!(utils::load_xml(file_name));

    assert_eq!(el.name, "module");
    match el.attributes.get("hidden") {
        Some(val) if val == "true" => return None,
        _ => {}
    }

    let name = uw!(el.attributes.get("id")).to_owned();
    let registers = el.children
        .iter()
        .map(|r| parse_register(r, &name))
        .collect::<Vec<_>>();

    Some(Module {
             name: name,
             registers: registers,
         })
}

#[derive(Debug, Clone)]
struct Register {
    name: String,
    module: String,
    offset: u32,
    width: u32,
}

fn parse_register(el: &Element, module: &str) -> Register {
    assert_eq!(el.name, "register");

    let name = uw!(el.attributes.get("acronym")).to_owned();
    let offset = uw!(utils::parse_u32(uw!(el.attributes.get("offset"))));
    let width = uw!(utils::parse_u32(uw!(el.attributes.get("width"))));

    Register {
        name: name,
        offset: offset,
        width: width,
        module: module.to_owned(),
    }
}
<|endoftext|>


<commit_before>extern crate byteorder;
extern crate cairo;
extern crate clap;
extern crate env_logger;
extern crate gdk;
extern crate gettextrs;
extern crate gio;
extern crate glib;
extern crate gstreamer;
extern crate gstreamer_audio;
extern crate gtk;
extern crate image;
extern crate pango;
extern crate sample;

#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
#[macro_use]
extern crate nom;

#[cfg(feature = "dump-waveform")]
extern crate chrono;

use clap::{App, Arg};

use gettextrs::{gettext, TextDomain, TextDomainError};

use gio::prelude::*;
use gtk::Builder;

use std::path::PathBuf;

mod media;
mod metadata;
mod ui;
use ui::MainController;

const APP_ID: &str = "org.fengalin.media-toc";

fn init_locale() {
    match TextDomain::new("media-toc").prepend("target").init() {
        Ok(locale) => info!("Translation found, `setlocale` returned {:?}", locale),
        Err(TextDomainError::TranslationNotFound(lang)) => {
            warn!("Translation not found for language {}", lang)
        }
        Err(TextDomainError::InvalidLocale(locale)) => error!("Invalid locale {}", locale),
    }
}

fn handle_command_line() -> Option<PathBuf> {
    let about_msg =
        gettext("Build a table of contents from a media file\nor split a media file into chapters");
    let help_msg = gettext("Display this message");
    let version_msg = gettext("Print version information");

    let input_arg = gettext("MEDIA");

    App::new("media-toc")
        .version("0.4.1")
        .author("François Laignel <fengalin@free.fr>")
        .about(about_msg.as_str())
        .help_message(help_msg.as_str())
        .version_message(version_msg.as_str())
        .arg(
            Arg::with_name(input_arg.as_str())
                .help(&gettext("Path to the input media file"))
                .last(false),
        )
        .get_matches()
        .value_of(input_arg.as_str())
        .map(|input_file| input_file.into())
}

fn run(is_gst_ok: bool, input_file: Option<PathBuf>) {
    // Init resources
    let res_bytes = include_bytes!("../target/resources/icons.gresource");
    let gbytes = glib::Bytes::from(res_bytes.as_ref());
    let _res = gio::Resource::new_from_data(&gbytes)
        .and_then(|resource| {
            gio::resources_register(&resource);
            Ok(())
        })
        .unwrap_or_else(|err| {
            warn!("unable to load resources: {:?}", err);
        });

    // Init App
    let gtk_app = gtk::Application::new(Some(APP_ID), gio::ApplicationFlags::empty())
        .expect("Failed to initialize GtkApplication");

    gtk_app.connect_startup(move |gtk_app| {
        let main_ctrl = MainController::new(
            gtk_app,
            &Builder::new_from_string(include_str!("ui/media-toc.ui")),
            is_gst_ok,
        );

        main_ctrl.borrow().show_all();

        let input_file = input_file.clone();
        gtk_app.connect_activate(move |_| {
            if is_gst_ok {
                if let Some(ref input_file) = input_file {
                    // FIXME: there must be a lifetime way to avoid
                    // all these duplications
                    main_ctrl.borrow_mut().open_media(input_file.clone());
                }
            }
        });
    });

    gtk_app.run(&[]);
}

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

    init_locale();

    // Messages are not translated unless gtk (glib) is initialized
    let is_gtk_ok = gtk::init().is_ok();

    let input_file = handle_command_line();

    if is_gtk_ok {
        run(gstreamer::init().is_ok(), input_file);
    } else {
        error!("{}", gettext("Failed to initialize GTK"));
    }
}<commit_msg>Show main window in `connect_active`<commit_after>extern crate byteorder;
extern crate cairo;
extern crate clap;
extern crate env_logger;
extern crate gdk;
extern crate gettextrs;
extern crate gio;
extern crate glib;
extern crate gstreamer;
extern crate gstreamer_audio;
extern crate gtk;
extern crate image;
extern crate pango;
extern crate sample;

#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
#[macro_use]
extern crate nom;

#[cfg(feature = "dump-waveform")]
extern crate chrono;

use clap::{App, Arg};

use gettextrs::{gettext, TextDomain, TextDomainError};

use gio::prelude::*;
use gtk::Builder;

use std::path::PathBuf;

mod media;
mod metadata;
mod ui;
use ui::MainController;

const APP_ID: &str = "org.fengalin.media-toc";

fn init_locale() {
    match TextDomain::new("media-toc").prepend("target").init() {
        Ok(locale) => info!("Translation found, `setlocale` returned {:?}", locale),
        Err(TextDomainError::TranslationNotFound(lang)) => {
            warn!("Translation not found for language {}", lang)
        }
        Err(TextDomainError::InvalidLocale(locale)) => error!("Invalid locale {}", locale),
    }
}

fn handle_command_line() -> Option<PathBuf> {
    let about_msg =
        gettext("Build a table of contents from a media file\nor split a media file into chapters");
    let help_msg = gettext("Display this message");
    let version_msg = gettext("Print version information");

    let input_arg = gettext("MEDIA");

    App::new("media-toc")
        .version("0.4.1")
        .author("François Laignel <fengalin@free.fr>")
        .about(about_msg.as_str())
        .help_message(help_msg.as_str())
        .version_message(version_msg.as_str())
        .arg(
            Arg::with_name(input_arg.as_str())
                .help(&gettext("Path to the input media file"))
                .last(false),
        )
        .get_matches()
        .value_of(input_arg.as_str())
        .map(|input_file| input_file.into())
}

fn run(is_gst_ok: bool, input_file: Option<PathBuf>) {
    // Init resources
    let res_bytes = include_bytes!("../target/resources/icons.gresource");
    let gbytes = glib::Bytes::from(res_bytes.as_ref());
    let _res = gio::Resource::new_from_data(&gbytes)
        .and_then(|resource| {
            gio::resources_register(&resource);
            Ok(())
        })
        .unwrap_or_else(|err| {
            warn!("unable to load resources: {:?}", err);
        });

    // Init App
    let gtk_app = gtk::Application::new(APP_ID, gio::ApplicationFlags::empty())
        .expect("Failed to initialize GtkApplication");

    gtk_app.connect_startup(move |gtk_app| {
        let main_ctrl = MainController::new(
            gtk_app,
            &Builder::new_from_string(include_str!("ui/media-toc.ui")),
            is_gst_ok,
        );

        let input_file = input_file.clone();
        gtk_app.connect_activate(move |_| {
            let mut main_ctrl = main_ctrl.borrow_mut();
            main_ctrl.show_all();

            if is_gst_ok {
                if let Some(ref input_file) = input_file {
                    // FIXME: there must be a lifetime way to avoid
                    // all these duplications
                    main_ctrl.open_media(input_file.clone());
                }
            }
        });
    });

    gtk_app.run(&[]);
}

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

    init_locale();

    // Messages are not translated unless gtk (glib) is initialized
    let is_gtk_ok = gtk::init().is_ok();

    let input_file = handle_command_line();

    if is_gtk_ok {
        run(gstreamer::init().is_ok(), input_file);
    } else {
        error!("{}", gettext("Failed to initialize GTK"));
    }
}<|endoftext|>


<commit_before>#![feature(core)]
#![feature(path)]
#![feature(collections)]

#![feature(plugin)]
#![plugin(regex_macros)]
extern crate regex;
extern crate git2;
extern crate core;
extern crate "rustc-serialize" as rustc_serialize;
extern crate docopt;

use git2::{Repository, Commit, Diff, DiffFormat, Oid};
use docopt::Docopt;
use std::collections::HashMap;
// use std::old_io::BufferedReader;
// use std::old_io::File;
use std::str;
// use regex::Regex;
use rustc_serialize::json;
use std::fmt::Display;
use std::path::Path;

// Write the Docopt usage string.
static USAGE: &'static str = "
Usage: transit <repo> [<old> <new>]

If no commits are given, transit will revwalk from latest to oldest. Output is in compact JSON.
";

#[derive(RustcDecodable, Debug)]
struct Args {
    arg_repo: String,
    arg_old: Option<String>,
    arg_new: Option<String>,
}

fn main() {
    // Parse the args above or die.
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());
    // Pull up the revwalk.
    let path = Path::new(&args.arg_repo);
    let repo = Repository::discover(&path)
        .ok().expect("Unable to find repo.");
    // If we can destructures the two optional args into real things.
    if let (Some(old_string), Some(new_string)) = (args.arg_old, args.arg_new) {
        // Compare a specific commit pair.
        // Fist, get the commits. (Error checked)
        let old = Oid::from_str(&old_string[..]).and_then(|oid| repo.find_commit(oid));
        let new = Oid::from_str(&new_string[..]).and_then(|oid| repo.find_commit(oid));
        if old.is_ok() && new.is_ok() {
            let output = find_moves(&repo, &old.unwrap(), &new.unwrap()).unwrap();
            make_json(vec![output]);
        } else {
            panic!("Commit ids were not valid.");
        }
    } else {
        // Revwalk.
        let mut revwalk = repo.revwalk()
            .ok().expect("Unable to get revwalk.");
        // Setup some options.
        revwalk.simplify_first_parent(); // TODO: Maybe remove?
        let mut flags = git2::Sort::empty();
        flags.insert(git2::SORT_TIME);
        flags.insert(git2::SORT_TOPOLOGICAL);
        revwalk.set_sorting(flags);
        // Push HEAD to the revwalk.
        revwalk.push_head()
            .ok().expect("Unable to push HEAD.");
        // We sadly must collect here to use `.windows()`
        let history = revwalk.filter_map(|id| repo.find_commit(id).ok())
            .collect::<Vec<Commit>>();
        let mut output = vec![];
        // Walk through each pair of commits.
        for pair in history.windows(2) {
            let (old, new) = (&pair[1], &pair[0]);
            let detected = find_moves(&repo, old.clone(), new.clone()).unwrap();
            output.push(detected);
        }
        make_json(output);
    }
}

fn make_json(output: Vec<Vec<Output>>) {
    let out = json::as_pretty_json(&output).indent(4);
    println!("{}", out);
}

#[derive(Debug, PartialEq, Eq)]
enum FoundState {
    Added, Deleted
}

fn format_key(key: String) -> String {
    let remove_whitespace = regex!(r"\s{2,}"); // 2 or more whitespaces    // TODO Removes whitespace from a string.
    let trim = regex!(r"^[\s]+|[\s]+$");
    let result = remove_whitespace.replace_all(key.as_slice(), "");
    trim.replace_all(result.as_slice(), "")
}

#[derive(Debug)]
struct Found {
    filename: String,
    key: String,
    state: FoundState,
    start_position: u32,
    line_count: u32,
}

fn find_additions_and_deletions(diff: Diff) -> Vec<Found> {

    #[derive(Debug)]
    enum State {
        Other, Addition, Deletion
    }

    let mut founds: Vec<Found> = Vec::new();

    let mut state = State::Other;
    let mut added = String::new();
    let mut deleted = String::new();
    let mut old_path = String::new();
    let mut new_path = String::new();

    let mut line_count: u32 = 0;
    let mut start_position: u32 = 0;

    // Read about this function in http://alexcrichton.com/git2-rs/git2/struct.Diff.html#method.print
    // It's a bit weird, but I think it will provide the necessary information.
    diff.print(DiffFormat::Patch, |delta, maybe_hunk, line| -> bool {

        // if delta.nfiles() != 2 {
        //     // This is diff with only one side, and thus can't have a move.
        //     return true;
        // }
        // assert!(delta.nfiles() == 2, "This only works on diffs between exactly 2 files. Found {} files.", delta.nfiles());

        // Thinking:
        //  * If is not a hunk, keep going.
        //  * If it's a hunk, do regex magic.
        //  * Stick regex output into a hashmap as a hash.
        //  * Later, we will iterate through and output pased on the values.
        // Filter out all the boring context lines.
        // If we're not interested in this line just return since it will iterate to the next.
        if maybe_hunk.is_none() { return true }; // Return early.

        //dump_diffline(&line);
        //dump_diffdelta(&delta);
        //dump_diffhunk(&maybe_hunk.unwrap());

        old_path = match delta.old_file().path()
        .and_then(|x| x.to_str()) {
            Some(path) => String::from_str(path),
            None => return false,
        };
        new_path = match delta.new_file().path()
        .and_then(|x| x.to_str()) {
            Some(path) => String::from_str(path),
            None => return false,
        };

        match line.origin() {
            // Additions
            '+' | '>' => {
                added.push_str(str::from_utf8(line.content())
                    .ok().expect("Couldn't parse line content for added"));

                match state {
                    State::Deletion => {
                        founds.push(Found {
                            filename: old_path.clone(),
                            key: format_key(deleted.clone()),
                            state: FoundState::Deleted,
                            start_position: start_position,
                            line_count: line_count,
                        });
                        deleted = String::new();
                        line_count = 0;
                        start_position = match line.new_lineno() {
                            Some(lineno) => lineno,
                            None => return false, // Can't be a move if deleted.
                        }
                    },
                    State::Addition => {
                        line_count += 1;
                    },
                    State::Other => {
                        line_count = 1;
                        start_position = match line.new_lineno() {
                            Some(lineno) => lineno,
                            None => return false, // Can't be a move if deleted.
                        }
                    },
                }

                state = State::Addition;
                true
            },
            // Deletions
            '-' | '<' => {
                deleted.push_str(str::from_utf8(line.content())
                    .ok().expect("Couldn't parse line content for deleted"));

                match state {
                    State::Addition => {
                        founds.push(Found {
                            filename: new_path.clone(),
                            key: format_key(added.clone()),
                            state: FoundState::Added,
                            start_position: start_position,
                            line_count: line_count,
                        });
                        added = String::new();
                        line_count = 0;
                        start_position = match line.old_lineno() {
                            Some(lineno) => lineno,
                            None => return false, // Can't be a move if deleted.
                        }
                    },
                    State::Deletion => {
                        line_count += 1;
                    },
                    State::Other => {
                        line_count = 1;
                        start_position = match line.old_lineno() {
                            Some(lineno) => lineno,
                            None => return false, // Can't be a move if deleted.
                        }
                    },
                }

                state = State::Deletion;
                true
            },
            // Other
            _         => {
                match state {
                    State::Addition => {
                        founds.push(Found {
                            filename: new_path.clone(),
                            key: format_key(added.clone()),
                            state: FoundState::Added,
                            start_position: start_position,
                            line_count: line_count,
                        });
                        added = String::new();
                    },
                    State::Deletion => {
                        founds.push(Found {
                            filename: old_path.clone(),
                            key: format_key(deleted.clone()),
                            state: FoundState::Deleted,
                            start_position: start_position,
                            line_count: line_count,
                        });
                        deleted = String::new();
                    },
                    _ => (),
                }

                state = State::Other;
                true
            }
        }
    }).ok(); // We don't care if we exit early. That's fine.

    // Grab last one.
    match state {
        State::Addition => {
            if added.len() > 0 {
                founds.push(Found {
                    filename: new_path.clone(),
                    key: format_key(added.clone()),
                    state: FoundState::Added,
                    start_position: start_position,
                    line_count: line_count,
                });
            }
        },
        State::Deletion => {
            if deleted.len() > 0 {
                founds.push(Found {
                    filename: old_path.clone(),
                    key: format_key(deleted.clone()),
                    state: FoundState::Deleted,
                    start_position: start_position,
                    line_count: line_count,
                });
            }
        },
        _ => (),
    }

    return founds;
}

fn find_moves(repo: &Repository, old: &Commit, new: &Commit) -> Result<Vec<Output>, git2::Error> {
    let old_tree = try!(old.tree());
    let new_tree = try!(new.tree());
    // Build up a diff of the two trees.
    let diff = try!(Diff::tree_to_tree(repo, Some(&old_tree), Some(&new_tree), None));

    let founds: Vec<Found> = find_additions_and_deletions(diff);

    let mut moves: Vec<Output> = Vec::new();
    let mut map: HashMap<String, Found> = HashMap::new();

    for f in founds {
        if f.key.len() == 0 { continue; }

        if map.contains_key(&f.key) {
            let q = map.get(&f.key).unwrap();

            // If both states are added, there are no moves.
            // assert!(f.state != q.state, format!("States {:?}, {:?}. Should be Addition/Deletion ", f.state, q.state));
            if f.state == q.state {
                return Ok(Vec::<Output>::new())
            }

            let output: Output;

            match f.state {
                FoundState::Added => {
                    output = Output {
                        old_commit: TransitOid(old.id()),
                        new_commit: TransitOid(new.id()),
                        old_filename: q.filename.clone(),
                        new_filename: f.filename.clone(),
                        origin_line: q.start_position,
                        destination_line: f.start_position,
                        num_lines: f.line_count,
                    };
                },
                FoundState::Deleted => {
                    output = Output {
                        old_commit: TransitOid(old.id()),
                        new_commit: TransitOid(new.id()),
                        old_filename: f.filename.clone(),
                        new_filename: q.filename.clone(),
                        origin_line: f.start_position,
                        destination_line: q.start_position,
                        num_lines: f.line_count,
                    };
                },
            }

            moves.push(output);
        } else {
            map.insert(f.key.clone(), f);
        }
    }

    return Ok(moves);
}

#[derive(Debug, RustcEncodable)]
struct Output {
    old_commit: TransitOid,
    new_commit: TransitOid,
    old_filename: String,
    new_filename: String,
    origin_line: u32,
    destination_line: u32,
    num_lines: u32,
}

#[derive(Debug)]
struct TransitOid(Oid);
impl Display for TransitOid {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        Display::fmt(&self.0, f)
    }
}

impl rustc_serialize::Encodable for TransitOid {
    fn encode<S: rustc_serialize::Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        s.emit_str(&format!("{}", self)[..])
    }
}
<commit_msg>More consistent output.<commit_after>#![feature(core)]
#![feature(path)]
#![feature(collections)]

#![feature(plugin)]
#![plugin(regex_macros)]
extern crate regex;
extern crate git2;
extern crate core;
extern crate "rustc-serialize" as rustc_serialize;
extern crate docopt;

use git2::{Repository, Commit, Diff, DiffFormat, Oid};
use docopt::Docopt;
use std::collections::HashMap;
// use std::old_io::BufferedReader;
// use std::old_io::File;
use std::str;
// use regex::Regex;
use rustc_serialize::json;
use std::fmt::Display;
use std::path::Path;

// Write the Docopt usage string.
static USAGE: &'static str = "
Usage: transit <repo> [<old> <new>]

If no commits are given, transit will revwalk from latest to oldest. Output is in compact JSON.
";

#[derive(RustcDecodable, Debug)]
struct Args {
    arg_repo: String,
    arg_old: Option<String>,
    arg_new: Option<String>,
}

fn main() {
    // Parse the args above or die.
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());
    // Pull up the revwalk.
    let path = Path::new(&args.arg_repo);
    let repo = Repository::discover(&path)
        .ok().expect("Unable to find repo.");
    // If we can destructures the two optional args into real things.
    if let (Some(old_string), Some(new_string)) = (args.arg_old, args.arg_new) {
        // Compare a specific commit pair.
        // Fist, get the commits. (Error checked)
        let old_id = Oid::from_str(&old_string[..])
            .ok().expect("Couldn't parse old ID");
        let old = repo.find_commit(old_id);
        let new_id = Oid::from_str(&new_string[..])
            .ok().expect("Couldn't parse new ID");
        let new = repo.find_commit(new_id);
        if old.is_ok() && new.is_ok() {
            let output = find_moves(&repo, &old.unwrap(), &new.unwrap()).unwrap();
            make_json(vec![OutputSet {
                old: TransitOid(old_id),
                new: TransitOid(new_id),
                outputs: output,
            }]);
        } else {
            panic!("Commit ids were not valid.");
        }
    } else {
        // Revwalk.
        let mut revwalk = repo.revwalk()
            .ok().expect("Unable to get revwalk.");
        // Setup some options.
        revwalk.simplify_first_parent(); // TODO: Maybe remove?
        let mut flags = git2::Sort::empty();
        flags.insert(git2::SORT_TIME);
        flags.insert(git2::SORT_TOPOLOGICAL);
        revwalk.set_sorting(flags);
        // Push HEAD to the revwalk.
        revwalk.push_head()
            .ok().expect("Unable to push HEAD.");
        // We sadly must collect here to use `.windows()`
        let history = revwalk.collect::<Vec<Oid>>();
        let mut output = Vec::with_capacity(history.len());
        // Walk through each pair of commits.
        for pair in history.windows(2) {
            let (old_id, new_id) = (pair[0], pair[1]);
            if let (Ok(old), Ok(new)) = (repo.find_commit(old_id), repo.find_commit(new_id)) {
                let detected = find_moves(&repo, &old, &new).unwrap();
                output.push(OutputSet {
                    old: TransitOid(old_id),
                    new: TransitOid(new_id),
                    outputs: detected,
                });
            } else {
                continue;
            }
        }
        make_json(output);
    }
}

fn make_json(output: Vec<OutputSet>) {
    let out = json::as_pretty_json(&output).indent(4);
    println!("{}", out);
}

#[derive(Debug, PartialEq, Eq)]
enum FoundState {
    Added, Deleted
}

fn format_key(key: String) -> String {
    let remove_whitespace = regex!(r"\s{2,}"); // 2 or more whitespaces    // TODO Removes whitespace from a string.
    let trim = regex!(r"^[\s]+|[\s]+$");
    let result = remove_whitespace.replace_all(key.as_slice(), "");
    trim.replace_all(result.as_slice(), "")
}

#[derive(Debug)]
struct Found {
    filename: String,
    key: String,
    state: FoundState,
    start_position: u32,
    line_count: u32,
}

fn find_additions_and_deletions(diff: Diff) -> Vec<Found> {

    #[derive(Debug)]
    enum State {
        Other, Addition, Deletion
    }

    let mut founds: Vec<Found> = Vec::new();

    let mut state = State::Other;
    let mut added = String::new();
    let mut deleted = String::new();
    let mut old_path = String::new();
    let mut new_path = String::new();

    let mut line_count: u32 = 0;
    let mut start_position: u32 = 0;

    // Read about this function in http://alexcrichton.com/git2-rs/git2/struct.Diff.html#method.print
    // It's a bit weird, but I think it will provide the necessary information.
    diff.print(DiffFormat::Patch, |delta, maybe_hunk, line| -> bool {

        // if delta.nfiles() != 2 {
        //     // This is diff with only one side, and thus can't have a move.
        //     return true;
        // }
        // assert!(delta.nfiles() == 2, "This only works on diffs between exactly 2 files. Found {} files.", delta.nfiles());

        // Thinking:
        //  * If is not a hunk, keep going.
        //  * If it's a hunk, do regex magic.
        //  * Stick regex output into a hashmap as a hash.
        //  * Later, we will iterate through and output pased on the values.
        // Filter out all the boring context lines.
        // If we're not interested in this line just return since it will iterate to the next.
        if maybe_hunk.is_none() { return true }; // Return early.

        //dump_diffline(&line);
        //dump_diffdelta(&delta);
        //dump_diffhunk(&maybe_hunk.unwrap());

        old_path = match delta.old_file().path()
        .and_then(|x| x.to_str()) {
            Some(path) => String::from_str(path),
            None => return false,
        };
        new_path = match delta.new_file().path()
        .and_then(|x| x.to_str()) {
            Some(path) => String::from_str(path),
            None => return false,
        };

        match line.origin() {
            // Additions
            '+' | '>' => {
                added.push_str(str::from_utf8(line.content())
                    .ok().expect("Couldn't parse line content for added"));

                match state {
                    State::Deletion => {
                        founds.push(Found {
                            filename: old_path.clone(),
                            key: format_key(deleted.clone()),
                            state: FoundState::Deleted,
                            start_position: start_position,
                            line_count: line_count,
                        });
                        deleted = String::new();
                        line_count = 0;
                        start_position = match line.new_lineno() {
                            Some(lineno) => lineno,
                            None => return false, // Can't be a move if deleted.
                        }
                    },
                    State::Addition => {
                        line_count += 1;
                    },
                    State::Other => {
                        line_count = 1;
                        start_position = match line.new_lineno() {
                            Some(lineno) => lineno,
                            None => return false, // Can't be a move if deleted.
                        }
                    },
                }

                state = State::Addition;
                true
            },
            // Deletions
            '-' | '<' => {
                deleted.push_str(str::from_utf8(line.content())
                    .ok().expect("Couldn't parse line content for deleted"));

                match state {
                    State::Addition => {
                        founds.push(Found {
                            filename: new_path.clone(),
                            key: format_key(added.clone()),
                            state: FoundState::Added,
                            start_position: start_position,
                            line_count: line_count,
                        });
                        added = String::new();
                        line_count = 0;
                        start_position = match line.old_lineno() {
                            Some(lineno) => lineno,
                            None => return false, // Can't be a move if deleted.
                        }
                    },
                    State::Deletion => {
                        line_count += 1;
                    },
                    State::Other => {
                        line_count = 1;
                        start_position = match line.old_lineno() {
                            Some(lineno) => lineno,
                            None => return false, // Can't be a move if deleted.
                        }
                    },
                }

                state = State::Deletion;
                true
            },
            // Other
            _         => {
                match state {
                    State::Addition => {
                        founds.push(Found {
                            filename: new_path.clone(),
                            key: format_key(added.clone()),
                            state: FoundState::Added,
                            start_position: start_position,
                            line_count: line_count,
                        });
                        added = String::new();
                    },
                    State::Deletion => {
                        founds.push(Found {
                            filename: old_path.clone(),
                            key: format_key(deleted.clone()),
                            state: FoundState::Deleted,
                            start_position: start_position,
                            line_count: line_count,
                        });
                        deleted = String::new();
                    },
                    _ => (),
                }

                state = State::Other;
                true
            }
        }
    }).ok(); // We don't care if we exit early. That's fine.

    // Grab last one.
    match state {
        State::Addition => {
            if added.len() > 0 {
                founds.push(Found {
                    filename: new_path.clone(),
                    key: format_key(added.clone()),
                    state: FoundState::Added,
                    start_position: start_position,
                    line_count: line_count,
                });
            }
        },
        State::Deletion => {
            if deleted.len() > 0 {
                founds.push(Found {
                    filename: old_path.clone(),
                    key: format_key(deleted.clone()),
                    state: FoundState::Deleted,
                    start_position: start_position,
                    line_count: line_count,
                });
            }
        },
        _ => (),
    }

    return founds;
}

fn find_moves(repo: &Repository, old: &Commit, new: &Commit) -> Result<Vec<Output>, git2::Error> {
    let old_tree = try!(old.tree());
    let new_tree = try!(new.tree());
    // Build up a diff of the two trees.
    let diff = try!(Diff::tree_to_tree(repo, Some(&old_tree), Some(&new_tree), None));

    let founds: Vec<Found> = find_additions_and_deletions(diff);

    let mut moves: Vec<Output> = Vec::new();
    let mut map: HashMap<String, Found> = HashMap::new();

    for f in founds {
        if f.key.len() == 0 { continue; }

        if map.contains_key(&f.key) {
            let q = map.get(&f.key).unwrap();

            // If both states are added, there are no moves.
            // assert!(f.state != q.state, format!("States {:?}, {:?}. Should be Addition/Deletion ", f.state, q.state));
            if f.state == q.state {
                return Ok(Vec::<Output>::new())
            }

            let output: Output;

            match f.state {
                FoundState::Added => {
                    output = Output {
                        old_filename: q.filename.clone(),
                        new_filename: f.filename.clone(),
                        origin_line: q.start_position,
                        destination_line: f.start_position,
                        num_lines: f.line_count,
                    };
                },
                FoundState::Deleted => {
                    output = Output {
                        old_filename: f.filename.clone(),
                        new_filename: q.filename.clone(),
                        origin_line: f.start_position,
                        destination_line: q.start_position,
                        num_lines: f.line_count,
                    };
                },
            }

            moves.push(output);
        } else {
            map.insert(f.key.clone(), f);
        }
    }

    return Ok(moves);
}

#[derive(Debug, RustcEncodable)]
struct OutputSet {
    old: TransitOid,
    new: TransitOid,
    outputs: Vec<Output>,
}

#[derive(Debug, RustcEncodable)]
struct Output {
    old_filename: String,
    new_filename: String,
    origin_line: u32,
    destination_line: u32,
    num_lines: u32,
}

#[derive(Debug, Hash, PartialEq, Eq)]
struct TransitOid(Oid);
impl Display for TransitOid {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        Display::fmt(&self.0, f)
    }
}

impl rustc_serialize::Encodable for TransitOid {
    fn encode<S: rustc_serialize::Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        s.emit_str(&format!("{}", self)[..])
    }
}
<|endoftext|>


<commit_before>#![feature(libc)]
extern crate libc;

use std::cmp::min;
use std::env::args;
use std::fs::File;
use std::io::BufRead;
use std::io::BufReader;
use libc::types::os::arch::c95::c_int;
use libc::consts::os::posix88::SIGINT;
use libc::funcs::posix01::signal::signal;

static mut exit: bool = false;

type Map = Vec<Vec<Cell>>;

struct Cell {
	alive:	bool,
	lives:	bool,
}

fn print_usage() {
	println!("usage: gol genmap SIZE_V SIZE_H  (generates an empty map)");
	println!("       gol play FILE [TIME_MS]   (plays the game)\n");
	println!("       maps: must be rectangular");
	println!("             '·' is a dead cell, anything else is a living cell");
	println!("         ^C: exit");
}

fn print_new_map(size_args: &[String]) {
	let sizev = size_args[0].parse::<usize>().unwrap();
	let sizeh = size_args[1].parse::<usize>().unwrap();
	let map_line = std::iter::repeat('·').take(sizeh).collect::<String>();
	for _ in 0..sizev { println!("{}", map_line); }
}

fn get_map(filename: &String) -> Option<Map> {
	let file = match File::open(filename) {
		Ok(file)	=> file,
		Err(error)	=> { println!("{}: {}", filename, error); return None },
	};
	let reader = BufReader::new(file);
	Some(reader.lines().map(|l| l.unwrap().chars().map(|c| match c { '·' => Cell { alive: false, lives: false }, _ => Cell { alive: true, lives: true } }).collect()).collect())
}

fn iterate(map: &mut Map) {
	let i_max = map.len();
	let j_max = map[0].len();
	let mut live_neighbours: usize;
	for i in 0..i_max { for j in 0..j_max {
		live_neighbours = 0;
		for m in i.saturating_sub(1)..min(i + 2, i_max) {
			for n in j.saturating_sub(1)..min(j + 2, j_max) {
				if map[m][n].alive && (m != i || n !=  j) { live_neighbours += 1; }
			}}
		if !map[i][j].alive { if live_neighbours == 3  { map[i][j].lives = true } }
		else if live_neighbours < 2 || 3 < live_neighbours { map[i][j].lives = false }
	}}
	for i in 0..map.len() { for j in 0..map[0].len() {
		map[i][j].alive = map[i][j].lives;
	}}
}

fn display_map(map: &Map) {
	let mut screen = String::with_capacity(map.len() * (map[0].len() * 3 + 1) + 7);
	screen.push_str("\x1B[2J\x1B[H");
	for i in 0..map.len() {
		for j in 0..map[0].len() {
			if map[i][j].alive { screen.push_str(" X"); }
			else { screen.push_str(" ·"); }
		}
		screen.push('\n');
	}
	print!("{}{}x{}, ", screen, map.len(), map[0].len());
}

fn play_map(filename: &String, pause_time_ms: u32) {
	unsafe { let handler = interrupt as *const u64; signal(SIGINT, handler as u64); }
	let mut map = get_map(filename).unwrap();
	let size_row = map[0].len();
	for row in map.iter() { if row.len() != size_row { println!("error: map is not a rectangle"); return } }
	let mut niter = 0usize;
	print!("\x1B[?47h\x1B[?25l");
	loop {
		display_map(&map);
		println!("iteration: {}", niter);
		iterate(&mut map);
		niter += 1;
		std::thread::sleep_ms(pause_time_ms);
		unsafe { if exit { print!("\x1B[?47l\x1B[?25h"); return } }
	}
}

fn interrupt(_: c_int) {
	unsafe { exit = true; }
}

fn main() {
	let args: Vec<_> = args().collect();
	if args.len() == 4 && args[1] == "genmap" { print_new_map(&args[2..4]); }
	else if args.len() == 3 && args[1] == "play" { play_map(&args[2], 400); }
	else if args.len() == 4 && args[1] == "play" { play_map(&args[2], args[3].parse::<u32>().unwrap()); }
	else { print_usage(); }
}
<commit_msg>add explanatory comments to ANSI escape codes<commit_after>#![feature(libc)]
extern crate libc;

use std::cmp::min;
use std::env::args;
use std::fs::File;
use std::io::BufRead;
use std::io::BufReader;
use libc::types::os::arch::c95::c_int;
use libc::consts::os::posix88::SIGINT;
use libc::funcs::posix01::signal::signal;

static mut exit: bool = false;

type Map = Vec<Vec<Cell>>;

struct Cell {
	alive:	bool,
	lives:	bool,
}

fn print_usage() {
	println!("usage: gol genmap SIZE_V SIZE_H  (generates an empty map)");
	println!("       gol play FILE [TIME_MS]   (plays the game)\n");
	println!("       maps: must be rectangular");
	println!("             '·' is a dead cell, anything else is a living cell");
	println!("         ^C: exit");
}

fn print_new_map(size_args: &[String]) {
	let sizev = size_args[0].parse::<usize>().unwrap();
	let sizeh = size_args[1].parse::<usize>().unwrap();
	let map_line = std::iter::repeat('·').take(sizeh).collect::<String>();
	for _ in 0..sizev { println!("{}", map_line); }
}

fn get_map(filename: &String) -> Option<Map> {
	let file = match File::open(filename) {
		Ok(file)	=> file,
		Err(error)	=> { println!("{}: {}", filename, error); return None },
	};
	let reader = BufReader::new(file);
	Some(reader.lines().map(|l| l.unwrap().chars().map(|c| match c { '·' => Cell { alive: false, lives: false }, _ => Cell { alive: true, lives: true } }).collect()).collect())
}

fn iterate(map: &mut Map) {
	let i_max = map.len();
	let j_max = map[0].len();
	let mut live_neighbours: usize;
	for i in 0..i_max { for j in 0..j_max {
		live_neighbours = 0;
		for m in i.saturating_sub(1)..min(i + 2, i_max) {
			for n in j.saturating_sub(1)..min(j + 2, j_max) {
				if map[m][n].alive && (m != i || n !=  j) { live_neighbours += 1; }
			}}
		if !map[i][j].alive { if live_neighbours == 3  { map[i][j].lives = true } }
		else if live_neighbours < 2 || 3 < live_neighbours { map[i][j].lives = false }
	}}
	for i in 0..map.len() { for j in 0..map[0].len() {
		map[i][j].alive = map[i][j].lives;
	}}
}

fn display_map(map: &Map) {
	let mut screen = String::with_capacity(map.len() * (map[0].len() * 3 + 1) + 7);
	screen.push_str("\x1B[2J\x1B[H"); // clears screen and moves cursor to 1;1
	for i in 0..map.len() {
		for j in 0..map[0].len() {
			if map[i][j].alive { screen.push_str(" X"); }
			else { screen.push_str(" ·"); }
		}
		screen.push('\n');
	}
	print!("{}{}x{}, ", screen, map.len(), map[0].len());
}

fn play_map(filename: &String, pause_time_ms: u32) {
	unsafe { let handler = interrupt as *const u64; signal(SIGINT, handler as u64); }
	let mut map = get_map(filename).unwrap();
	let size_row = map[0].len();
	for row in map.iter() { if row.len() != size_row { println!("error: map is not a rectangle"); return } }
	let mut niter = 0usize;
	print!("\x1B[?47h\x1B[?25l"); // saves screen and hides cursor
	loop {
		display_map(&map);
		println!("iteration: {}", niter);
		iterate(&mut map);
		niter += 1;
		std::thread::sleep_ms(pause_time_ms);
		unsafe { if exit { print!("\x1B[?47l\x1B[?25h"); return } } // restores screen and shows cursor
	}
}

fn interrupt(_: c_int) {
	unsafe { exit = true; }
}

fn main() {
	let args: Vec<_> = args().collect();
	if args.len() == 4 && args[1] == "genmap" { print_new_map(&args[2..4]); }
	else if args.len() == 3 && args[1] == "play" { play_map(&args[2], 400); }
	else if args.len() == 4 && args[1] == "play" { play_map(&args[2], args[3].parse::<u32>().unwrap()); }
	else { print_usage(); }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;
extern crate pretty_env_logger;
extern crate clap;
extern crate libmodbus_rs;
extern crate iron;
extern crate router;
extern crate staticfile;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate ctrlc;
extern crate retry;
extern crate hex_slice;

use std::fs;
use std::path::Path;
use std::os::unix::fs::FileTypeExt;
use std::sync::{Arc, Mutex};
use std::convert::From;
use std::sync::atomic::{AtomicBool, Ordering};

use clap::{App, Arg};

use iron::Iron;
use iron::prelude::*;
use iron::status;
use iron::middleware::Handler;
use router::Router;
use staticfile::Static;

mod sun_saver;
use sun_saver::{SunSaverConnection, FileSunSaverConnection, ModbusSunSaverConnection, SunSaverResponse};

#[derive(Debug, Clone, Serialize)]
struct ApiResponse {
    battery_voltage_filtered: f32,
    solar_input_voltage_filtered: f32,
    load_voltage_filtered: f32,
}

impl From<SunSaverResponse> for ApiResponse {
    fn from(response: SunSaverResponse) -> Self {
        ApiResponse {
            battery_voltage_filtered: response.battery_voltage_filtered(),
            solar_input_voltage_filtered: response.solar_input_voltage_filtered(),
            load_voltage_filtered: response.load_voltage_filtered(),
        }
    }
}

#[derive(Clone)]
struct ApiHandler {
    connection: Arc<Mutex<Box<SunSaverConnection>>>,
}

impl ApiHandler {
    fn new(connection: Box<SunSaverConnection>) -> ApiHandler {
        ApiHandler {
            connection: Arc::new(Mutex::new(connection)),
        }
    }
}

unsafe impl Send for ApiHandler {}
unsafe impl Sync for ApiHandler {}

impl Handler for ApiHandler {
    fn handle(&self, _req: &mut Request) -> IronResult<Response> {
        let connection = self.connection.clone();
        let mut unlocked_connection = connection.lock().unwrap();
        let a = ApiResponse::from(unlocked_connection.read_response());
        let b = serde_json::to_string_pretty(&a).unwrap();
        Ok(Response::with((status::Ok, b)))
    }
}

fn is_socket(path: &str) -> bool {
    let metadata = fs::metadata(path).unwrap();
    let file_type = metadata.file_type();
    debug!("is_socket for {} had metadata {:?}", path, metadata);
    debug!("is_socket for {} is_block_device: {}, is_char_device: {}, is_fifo: {}, is_socket: {}", path, file_type.is_block_device(), file_type.is_char_device(), file_type.is_fifo(), file_type.is_socket());
    metadata.file_type().is_char_device()
}

fn main() {
    assert!(pretty_env_logger::init().is_ok());

    let matches = App::new("simple-client")
        .version(env!("CARGO_PKG_VERSION"))
        .about("HTTP RESTful server for SunSaver MPPT ModBus data")
        .author("Guy Taylor <thebiggerguy.co.uk@gmail.com>")
        .arg(Arg::with_name("device")
            .help("Serial device e.g. /dev/ttyUSB0")
            .long("device")
            .short("d")
            .takes_value(true)
            .required(true))
        .get_matches();

    let serial_interface = matches.value_of("device").unwrap();

    let mut connection: Box<SunSaverConnection> = if is_socket(serial_interface) {
        info!("Device is a socket. Using Modbus");
        Box::new(ModbusSunSaverConnection::open(serial_interface))
    } else {
        info!("Device is not a socket. Using File");
        Box::new(FileSunSaverConnection::open(serial_interface))
    };

    debug!("Response: {:?}", connection.read_response());

    let api_handler = ApiHandler::new(connection);

    let mut router = Router::new();
    router.get("/", Static::new(Path::new("web")), "index");
    router.get("/api", api_handler, "api");

    let running = Arc::new(AtomicBool::new(true));
    let r = running.clone();
    ctrlc::set_handler(move || {
        r.store(false, Ordering::SeqCst);
        info!("Cought Ctrl-C");
    }).expect("Error setting Ctrl-C handler");

    info!("Starting server ...");
    let bind_address = format!("0.0.0.0:{}", env!("PORT"));
    let mut listening = Iron::new(router).http(&bind_address).unwrap();
    info!("Started server {}", bind_address);

    info!("Use Ctrl-C to stop");
    while running.load(Ordering::SeqCst) {}
    listening.close().unwrap();
}
<commit_msg>Fix so tests can be run without port env<commit_after>#[macro_use]
extern crate log;
extern crate pretty_env_logger;
extern crate clap;
extern crate libmodbus_rs;
extern crate iron;
extern crate router;
extern crate staticfile;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate ctrlc;
extern crate retry;
extern crate hex_slice;

use std::fs;
use std::path::Path;
use std::os::unix::fs::FileTypeExt;
use std::sync::{Arc, Mutex};
use std::convert::From;
use std::sync::atomic::{AtomicBool, Ordering};

use clap::{App, Arg};

use iron::Iron;
use iron::prelude::*;
use iron::status;
use iron::middleware::Handler;
use router::Router;
use staticfile::Static;

mod sun_saver;
use sun_saver::{SunSaverConnection, FileSunSaverConnection, ModbusSunSaverConnection, SunSaverResponse};

#[derive(Debug, Clone, Serialize)]
struct ApiResponse {
    battery_voltage_filtered: f32,
    solar_input_voltage_filtered: f32,
    load_voltage_filtered: f32,
}

impl From<SunSaverResponse> for ApiResponse {
    fn from(response: SunSaverResponse) -> Self {
        ApiResponse {
            battery_voltage_filtered: response.battery_voltage_filtered(),
            solar_input_voltage_filtered: response.solar_input_voltage_filtered(),
            load_voltage_filtered: response.load_voltage_filtered(),
        }
    }
}

#[derive(Clone)]
struct ApiHandler {
    connection: Arc<Mutex<Box<SunSaverConnection>>>,
}

impl ApiHandler {
    fn new(connection: Box<SunSaverConnection>) -> ApiHandler {
        ApiHandler {
            connection: Arc::new(Mutex::new(connection)),
        }
    }
}

unsafe impl Send for ApiHandler {}
unsafe impl Sync for ApiHandler {}

impl Handler for ApiHandler {
    fn handle(&self, _req: &mut Request) -> IronResult<Response> {
        let connection = self.connection.clone();
        let mut unlocked_connection = connection.lock().unwrap();
        let a = ApiResponse::from(unlocked_connection.read_response());
        let b = serde_json::to_string_pretty(&a).unwrap();
        Ok(Response::with((status::Ok, b)))
    }
}

fn is_socket(path: &str) -> bool {
    let metadata = fs::metadata(path).unwrap();
    let file_type = metadata.file_type();
    debug!("is_socket for {} had metadata {:?}", path, metadata);
    debug!("is_socket for {} is_block_device: {}, is_char_device: {}, is_fifo: {}, is_socket: {}", path, file_type.is_block_device(), file_type.is_char_device(), file_type.is_fifo(), file_type.is_socket());
    metadata.file_type().is_char_device()
}

fn main() {
    assert!(pretty_env_logger::init().is_ok());

    let matches = App::new("simple-client")
        .version(env!("CARGO_PKG_VERSION"))
        .about("HTTP RESTful server for SunSaver MPPT ModBus data")
        .author("Guy Taylor <thebiggerguy.co.uk@gmail.com>")
        .arg(Arg::with_name("device")
            .help("Serial device e.g. /dev/ttyUSB0")
            .long("device")
            .short("d")
            .takes_value(true)
            .required(true))
        .get_matches();

    let serial_interface = matches.value_of("device").unwrap();

    let mut connection: Box<SunSaverConnection> = if is_socket(serial_interface) {
        info!("Device is a socket. Using Modbus");
        Box::new(ModbusSunSaverConnection::open(serial_interface))
    } else {
        info!("Device is not a socket. Using File");
        Box::new(FileSunSaverConnection::open(serial_interface))
    };

    debug!("Response: {:?}", connection.read_response());

    let api_handler = ApiHandler::new(connection);

    let mut router = Router::new();
    router.get("/", Static::new(Path::new("web")), "index");
    router.get("/api", api_handler, "api");

    let running = Arc::new(AtomicBool::new(true));
    let r = running.clone();
    ctrlc::set_handler(move || {
        r.store(false, Ordering::SeqCst);
        info!("Cought Ctrl-C");
    }).expect("Error setting Ctrl-C handler");

    info!("Starting server ...");
    let bind_address = format!("0.0.0.0:{}", option_env!("PORT").unwrap_or("8080"));
    let mut listening = Iron::new(router).http(&bind_address).unwrap();
    info!("Started server {}", bind_address);

    info!("Use Ctrl-C to stop");
    while running.load(Ordering::SeqCst) {}
    listening.close().unwrap();
}
<|endoftext|>


<commit_before>extern crate mmap;
extern crate time;
extern crate timely;
extern crate columnar;
extern crate docopt;

use docopt::Docopt;

use std::thread;

use timely::progress::timestamp::RootTimestamp;
use timely::progress::scope::Scope;
use timely::progress::nested::Summary::Local;
use timely::example_shared::*;
use timely::example_shared::operators::*;
use timely::communication::*;
use timely::communication::pact::Exchange;

use timely::networking::initialize_networking;
use timely::networking::initialize_networking_from_file;

use timely::drain::DrainExt;

use columnar::Columnar;

mod typedrw;
mod graphmap;
use graphmap::GraphMMap;

mod sorting;
use sorting::{SegmentList, radix_sort_32};

static USAGE: &'static str = "
Usage: pagerank <source> [options] [<arguments>...]

Options:
    -w <arg>, --workers <arg>    number of workers per process [default: 1]
    -p <arg>, --processid <arg>  identity of this process      [default: 0]
    -n <arg>, --processes <arg>  number of processes involved  [default: 1]
    -h <arg>, --hosts <arg>      file containing list of host:port for workers
";

#[derive(Copy, Clone, Debug)]
struct NodeRank { node: u32, rank: f32, }
impl Columnar for NodeRank { type Stack = Vec<NodeRank>; }

fn main () {
    let args = Docopt::new(USAGE).and_then(|dopt| dopt.parse()).unwrap_or_else(|e| e.exit());

    let source = args.get_str("<source>").to_owned();

    let workers: u64 = if let Ok(threads) = args.get_str("-w").parse() { threads }
                       else { panic!("invalid setting for --workers: {}", args.get_str("-t")) };
    let process_id: u64 = if let Ok(proc_id) = args.get_str("-p").parse() { proc_id }
                          else { panic!("invalid setting for --processid: {}", args.get_str("-p")) };
    let processes: u64 = if let Ok(processes) = args.get_str("-n").parse() { processes }
                         else { panic!("invalid setting for --processes: {}", args.get_str("-n")) };

    println!("Starting pagerank dataflow with");
    println!("\tworkers:\t{}", workers);
    println!("\tprocesses:\t{}", processes);
    println!("\tprocessid:\t{}", process_id);

    // vector holding communicators to use; one per local worker.
    if processes > 1 {
        println!("Initializing BinaryCommunicator");

        let hosts = args.get_str("-h");
        let communicators = if hosts != "" {
            initialize_networking_from_file(hosts, process_id, workers).ok().expect("error initializing networking")
        }
        else {
            let addresses = (0..processes).map(|index| format!("localhost:{}", 2101 + index).to_string()).collect();
            initialize_networking(addresses, process_id, workers).ok().expect("error initializing networking")
        };

        pagerank_spawn(communicators, source);
    }
    else if workers > 1 { pagerank_spawn(ProcessCommunicator::new_vector(workers), source); }
    else { pagerank_spawn(vec![ThreadCommunicator], source); };
}

fn pagerank_spawn<C>(communicators: Vec<C>, filename: String)
where C: Communicator+Send {
    let mut guards = Vec::new();
    let workers = communicators.len();
    for communicator in communicators.into_iter() {
        let filename = filename.clone();
        guards.push(thread::Builder::new().name(format!("timely worker {}", communicator.index()))
                                          .spawn(move || pagerank_thread(communicator, filename, workers))
                                          .unwrap());
    }

    for guard in guards { guard.join().unwrap(); }
}

// returns [src/peers] degrees, (dst, deg) pairs, and a list of [src/peers] endpoints
fn transpose(mut edges: Vec<Vec<(u32, u32)>>, peers: usize, nodes: usize) -> (Vec<u32>, Vec<(u32, u32)>, Vec<u32>)  {

    let mut deg = vec![0; (nodes as usize / peers) + 1];
    for list in &edges {
        for &(s, _) in list {
            deg[s as usize / peers] += 1;
        }
    }

    // let start = time::precise_time_s();
    radix_sort_32(&mut edges, &mut Vec::new(), &|&(_,d)| d);
    // println!("sorted in {}s", time::precise_time_s() - start);

    let mut rev = Vec::<(u32,u32)>::with_capacity(deg.len());
    let mut trn = Vec::with_capacity(edges.len() * 1024);
    for list in edges {
        for (s,d) in list {
            let len = rev.len();
            if (len == 0) || (rev[len-1].0 < d) {
                rev.push((d, 0u32));
            }

            let len = rev.len();
            rev[len-1].1 += 1;
            trn.push(s / peers as u32);
        }
    }

    return (deg, rev, trn);
}

// pagerank dataflow graph has a set of edges as input, and a binary vertex that for each epoch of
// received edges initiates an iterative subcomputation to compute the pagerank.

fn pagerank_thread<C>(communicator: C, filename: String, _workers: usize)
where C: Communicator {
    let index = communicator.index() as usize;
    let peers = communicator.peers() as usize;

    let mut root = GraphRoot::new(communicator);

    let start = time::precise_time_s();
    let mut going = start;

    let nodes = GraphMMap::new(&filename).nodes();

    let mut segments = SegmentList::new(1024); // list of edge segments

    let mut src = vec![];   // holds ranks
    let mut deg = vec![];   // holds source degrees
    let mut rev = vec![];   // holds (dst, deg) pairs
    let mut trn = vec![];   // holds transposed sources

    let mut accounted = 0.0;
    let mut accounted_inner = 0.0;

    let mut input = root.subcomputation(|builder| {

        let (input, edges) = builder.new_input::<(u32, u32)>();
        let (cycle, ranks) = builder.loop_variable::<NodeRank>(RootTimestamp::new(20), Local(1));

        edges.binary_notify(&ranks,
                            Exchange::new(|x: &(u32,u32)| x.0 as u64),
                            Exchange::new(|x: &NodeRank| x.node as u64),
                            format!("pagerank"),
                            vec![RootTimestamp::new(0)],
                            move |input1, input2, output, notificator| {

            // receive incoming edges
            while let Some((_index, data)) = input1.pull() {
                segments.push(data.drain_temp());
            }

            while let Some((iter, _)) = notificator.next() {
                // if the very first iteration, prepare some stuff
                if iter.inner == 0 {
                    // println!("received edges in {}s", time::precise_time_s() - start);
                    // (deg, rev, trn) = transpose(srcs, dsts, peers);
                    let (a, b, c) = transpose(segments.finalize(), peers, nodes);
                    deg = a;
                    rev = b;
                    trn = c;
                    src = vec![0.0f32; deg.len()];
                    if index == 0 { println!("transformed; {} x {} shape", deg.len(), rev.len()); }
                }

                if iter.inner == 10 { going = time::precise_time_s(); }
                if iter.inner == 20 && index == 0 { println!("avg: {}", (time::precise_time_s() - going) / 10.0);
                    println!("rcv: {}, {}", accounted_inner / 20.0, accounted / 20.0); }

                let iter_start = time::precise_time_s();

                for s in 0..src.len() { src[s] = 0.15 + 0.85 * src[s] / deg[s] as f32; }

                let mut trn_slice = &trn[..];
                let mut rev_slice = &rev[..];
                while rev_slice.len() > 0 {
                    // TODO: session should just flush...
                    let mut session = output.session(&iter);
                    let next = std::cmp::min(100_000, rev_slice.len());
                    for &(dst, deg) in &rev_slice[..next] {
                        let mut accum = 0.0;
                        for &s in &trn_slice[..deg as usize] {
                            accum += src[s as usize];
                        }
                        trn_slice = &trn_slice[deg as usize..];
                        session.give(NodeRank { node: dst, rank: accum });
                    }
                    rev_slice = &rev_slice[next..];
                }

                for s in &mut src { *s = 0.0; }

                if index == 0 { println!("iter: {} took {}s", iter.inner, time::precise_time_s() - iter_start); }
            }

            let start = time::precise_time_s();
            while let Some((iter, data)) = input2.pull() {
                let start_inner = time::precise_time_s();
                notificator.notify_at(&iter);
                for x in data.drain_temp() {
                    src[x.node as usize / peers] += x.rank;
                }
                accounted_inner += time::precise_time_s() -start_inner;
            }
            accounted += time::precise_time_s() - start;
        })
        .connect_loop(cycle);

        input
    });

    {
        let graph = GraphMMap::new(&filename);

        let mut edges = Vec::new();
        for node in 0..graph.nodes() {
            if node % peers == index {
                for dst in graph.edges(node) {
                    edges.push((node as u32, *dst as u32));
                }
                if edges.len() > 1024 {
                    input.send_at(0, edges.drain_temp());
                    root.step();
                }
            }
        }

        input.send_at(0, edges.drain_temp());
    }
    input.close();
    while root.step() { }

    if index == 0 { println!("elapsed: {}", time::precise_time_s() - start); }
}

    // .unary_notify(
    //     Exchange::new(move |x: &(u32, f32)| (workers * (index / workers)) as u64 + (x.0 as u64 % workers as u64)),
    //     format!("Aggregation"),
    //     vec![],
    //     move |input, output, iterator| {
    //         while let Some((iter, data)) = input.pull() {
    //             iterator.notify_at(&iter);
    //             for (node, rank) in data.drain_temp() {
    //                 acc[node as usize / workers] += rank;
    //             }
    //         }
    //
    //         while let Some((item, _)) = iterator.next() {
    //
    //             output.give_at(&item, acc.drain_temp().enumerate().filter(|x| x.1 != 0.0)
    //                                      .map(|(u,f)| (((u * workers + local_index) as u32), f)));
    //
    //             for _ in 0..(1 + (nodes/workers)) { acc.push(0.0); }
    //             assert!(acc.len() == (1 + (nodes/workers)));
    //         }
    //     }
    // )
<commit_msg>timings for all workers<commit_after>extern crate mmap;
extern crate time;
extern crate timely;
extern crate columnar;
extern crate docopt;

use docopt::Docopt;

use std::thread;

use timely::progress::timestamp::RootTimestamp;
use timely::progress::scope::Scope;
use timely::progress::nested::Summary::Local;
use timely::example_shared::*;
use timely::example_shared::operators::*;
use timely::communication::*;
use timely::communication::pact::Exchange;

use timely::networking::initialize_networking;
use timely::networking::initialize_networking_from_file;

use timely::drain::DrainExt;

use columnar::Columnar;

mod typedrw;
mod graphmap;
use graphmap::GraphMMap;

mod sorting;
use sorting::{SegmentList, radix_sort_32};

static USAGE: &'static str = "
Usage: pagerank <source> [options] [<arguments>...]

Options:
    -w <arg>, --workers <arg>    number of workers per process [default: 1]
    -p <arg>, --processid <arg>  identity of this process      [default: 0]
    -n <arg>, --processes <arg>  number of processes involved  [default: 1]
    -h <arg>, --hosts <arg>      file containing list of host:port for workers
";

#[derive(Copy, Clone, Debug)]
struct NodeRank { node: u32, rank: f32, }
impl Columnar for NodeRank { type Stack = Vec<NodeRank>; }

fn main () {
    let args = Docopt::new(USAGE).and_then(|dopt| dopt.parse()).unwrap_or_else(|e| e.exit());

    let source = args.get_str("<source>").to_owned();

    let workers: u64 = if let Ok(threads) = args.get_str("-w").parse() { threads }
                       else { panic!("invalid setting for --workers: {}", args.get_str("-t")) };
    let process_id: u64 = if let Ok(proc_id) = args.get_str("-p").parse() { proc_id }
                          else { panic!("invalid setting for --processid: {}", args.get_str("-p")) };
    let processes: u64 = if let Ok(processes) = args.get_str("-n").parse() { processes }
                         else { panic!("invalid setting for --processes: {}", args.get_str("-n")) };

    println!("Starting pagerank dataflow with");
    println!("\tworkers:\t{}", workers);
    println!("\tprocesses:\t{}", processes);
    println!("\tprocessid:\t{}", process_id);

    // vector holding communicators to use; one per local worker.
    if processes > 1 {
        println!("Initializing BinaryCommunicator");

        let hosts = args.get_str("-h");
        let communicators = if hosts != "" {
            initialize_networking_from_file(hosts, process_id, workers).ok().expect("error initializing networking")
        }
        else {
            let addresses = (0..processes).map(|index| format!("localhost:{}", 2101 + index).to_string()).collect();
            initialize_networking(addresses, process_id, workers).ok().expect("error initializing networking")
        };

        pagerank_spawn(communicators, source);
    }
    else if workers > 1 { pagerank_spawn(ProcessCommunicator::new_vector(workers), source); }
    else { pagerank_spawn(vec![ThreadCommunicator], source); };
}

fn pagerank_spawn<C>(communicators: Vec<C>, filename: String)
where C: Communicator+Send {
    let mut guards = Vec::new();
    let workers = communicators.len();
    for communicator in communicators.into_iter() {
        let filename = filename.clone();
        guards.push(thread::Builder::new().name(format!("timely worker {}", communicator.index()))
                                          .spawn(move || pagerank_thread(communicator, filename, workers))
                                          .unwrap());
    }

    for guard in guards { guard.join().unwrap(); }
}

// returns [src/peers] degrees, (dst, deg) pairs, and a list of [src/peers] endpoints
fn transpose(mut edges: Vec<Vec<(u32, u32)>>, peers: usize, nodes: usize) -> (Vec<u32>, Vec<(u32, u32)>, Vec<u32>)  {

    let mut deg = vec![0; (nodes as usize / peers) + 1];
    for list in &edges {
        for &(s, _) in list {
            deg[s as usize / peers] += 1;
        }
    }

    // let start = time::precise_time_s();
    radix_sort_32(&mut edges, &mut Vec::new(), &|&(_,d)| d);
    // println!("sorted in {}s", time::precise_time_s() - start);

    let mut rev = Vec::<(u32,u32)>::with_capacity(deg.len());
    let mut trn = Vec::with_capacity(edges.len() * 1024);
    for list in edges {
        for (s,d) in list {
            let len = rev.len();
            if (len == 0) || (rev[len-1].0 < d) {
                rev.push((d, 0u32));
            }

            let len = rev.len();
            rev[len-1].1 += 1;
            trn.push(s / peers as u32);
        }
    }

    return (deg, rev, trn);
}

// pagerank dataflow graph has a set of edges as input, and a binary vertex that for each epoch of
// received edges initiates an iterative subcomputation to compute the pagerank.

fn pagerank_thread<C>(communicator: C, filename: String, _workers: usize)
where C: Communicator {
    let index = communicator.index() as usize;
    let peers = communicator.peers() as usize;

    let mut root = GraphRoot::new(communicator);

    let start = time::precise_time_s();

    let nodes = GraphMMap::new(&filename).nodes();

    let mut segments = SegmentList::new(1024); // list of edge segments

    let mut src = vec![];   // holds ranks
    let mut deg = vec![];   // holds source degrees
    let mut rev = vec![];   // holds (dst, deg) pairs
    let mut trn = vec![];   // holds transposed sources

    let mut input = root.subcomputation(|builder| {

        let (input, edges) = builder.new_input::<(u32, u32)>();
        let (cycle, ranks) = builder.loop_variable::<NodeRank>(RootTimestamp::new(20), Local(1));

        edges.binary_notify(&ranks,
                            Exchange::new(|x: &(u32,u32)| x.0 as u64),
                            Exchange::new(|x: &NodeRank| x.node as u64),
                            format!("pagerank"),
                            vec![RootTimestamp::new(0)],
                            move |input1, input2, output, notificator| {

            // receive incoming edges
            while let Some((_index, data)) = input1.pull() {
                segments.push(data.drain_temp());
            }

            while let Some((iter, _)) = notificator.next() {

                // if the very first iteration, prepare some stuff
                if iter.inner == 0 {
                    let (a, b, c) = transpose(segments.finalize(), peers, nodes);
                    deg = a; rev = b; trn = c;
                    src = vec![0.0f32; deg.len()];
                }

                println!("{}\tworker {}: notify[{}] begin", time::precise_time_s() - start, index, iter.inner);

                for s in 0..src.len() { src[s] = 0.15 + 0.85 * src[s] / deg[s] as f32; }

                let mut trn_slice = &trn[..];
                let mut rev_slice = &rev[..];
                while rev_slice.len() > 0 {
                    // TODO: session should just flush...
                    let mut session = output.session(&iter);
                    let next = std::cmp::min(100_000, rev_slice.len());
                    for &(dst, deg) in &rev_slice[..next] {
                        let mut accum = 0.0;
                        for &s in &trn_slice[..deg as usize] {
                            accum += src[s as usize];
                        }
                        trn_slice = &trn_slice[deg as usize..];
                        session.give(NodeRank { node: dst, rank: accum });
                    }
                    rev_slice = &rev_slice[next..];
                }

                for s in &mut src { *s = 0.0; }

                println!("{}\tworker {}: notify[{}] ended", time::precise_time_s() - start, index, iter.inner);
            }

            while let Some((iter, data)) = input2.pull() {
                notificator.notify_at(&iter);
                for x in data.drain_temp() {
                    src[x.node as usize / peers] += x.rank;
                }
            }
        })
        .connect_loop(cycle);

        input
    });

    {
        let graph = GraphMMap::new(&filename);

        let mut edges = Vec::new();
        for node in 0..graph.nodes() {
            if node % peers == index {
                for dst in graph.edges(node) {
                    edges.push((node as u32, *dst as u32));
                }
                if edges.len() > 1024 {
                    input.send_at(0, edges.drain_temp());
                    root.step();
                }
            }
        }

        input.send_at(0, edges.drain_temp());
    }
    input.close();
    while root.step() { }

    if index == 0 { println!("elapsed: {}", time::precise_time_s() - start); }
}

    // .unary_notify(
    //     Exchange::new(move |x: &(u32, f32)| (workers * (index / workers)) as u64 + (x.0 as u64 % workers as u64)),
    //     format!("Aggregation"),
    //     vec![],
    //     move |input, output, iterator| {
    //         while let Some((iter, data)) = input.pull() {
    //             iterator.notify_at(&iter);
    //             for (node, rank) in data.drain_temp() {
    //                 acc[node as usize / workers] += rank;
    //             }
    //         }
    //
    //         while let Some((item, _)) = iterator.next() {
    //
    //             output.give_at(&item, acc.drain_temp().enumerate().filter(|x| x.1 != 0.0)
    //                                      .map(|(u,f)| (((u * workers + local_index) as u32), f)));
    //
    //             for _ in 0..(1 + (nodes/workers)) { acc.push(0.0); }
    //             assert!(acc.len() == (1 + (nodes/workers)));
    //         }
    //     }
    // )
<|endoftext|>