<commit_before>mod render;
mod menu;
mod button;
mod geom;
mod component;
mod event;

use self::render::*;
use super::module::*;
use self::menu::{Menu, MenuUpdate, MenuView};
use self::button::*;
use self::geom::*;
use self::component::*;
use self::event::*;

use glutin::{self, ContextBuilder, EventsLoop, GlContext, WindowBuilder};
use modular_flow as mf;

use std::time::Instant;
use std::collections::VecDeque;
use std::sync::{Arc, Mutex};
use std::cmp::Ordering;

use gfx::Device;
use gfx_window_glutin as gfx_glutin;
use gfx_device_gl as gl;

type OwnedModule = Mutex<Box<GuiComponent<GuiModuleUpdate>>>;
type Graph = mf::Graph<OwnedModule>;
type Node = mf::Node<OwnedModule>;

/// Model holds info about GUI state
/// and program state
pub struct Model {
    ctx: RenderContext,
    time: f32,
    graph: Arc<Graph>,
    window_size: Pt2,
    mouse_pos: Pt2,
    module_types: Vec<mf::MetaModule<OwnedModule>>,
    context_menu: Option<MenuView>,
}

impl Model {
    fn new(ctx: RenderContext) -> Model {
        Model {
            graph: Graph::new(),
            time: 0.0,
            window_size: Pt2::fill(0.0),
            mouse_pos: Pt2::fill(0.0),
            module_types: load_metamodules(ctx.clone()),
            context_menu: None,
            ctx,
        }
    }

    fn handle_mouse_input(&mut self, state: ButtonState, button: MouseButton) {
        let event = Event {
            time: self.time,
            data: EventData::Click(self.mouse_pos, button.into(), state.into()),
        };
        // intersect menu
        if let Some(menu) = self.context_menu.as_mut() {
            if menu.intersect(self.mouse_pos) {
                let status = menu.handle(&event);
                match status {
                    MenuUpdate::Select(path) => {
                        let name = path[0].as_ref();
                        let module = self.module_types.iter().find(|ty| ty.name == name).unwrap();
                        self.new_module(module, Rect2::new(self.mouse_pos, Pt2::fill(256.0)));
                        self.context_menu = None;
                    }
                    _ => (),
                }
                return;
            }
        }

        // intersect nodes
        let mut nodes = self.graph.nodes();
        nodes.sort_by(Self::compare_node_z);
        for node in &nodes {
            let mut module = node.module().lock().unwrap();
            if module.intersect(self.mouse_pos) {
                let status = module.handle(&event);
                drop(module);
                match status {
                    GuiModuleUpdate::Closed => {
                        self.graph.remove_node(node.id()).unwrap();
                    }
                    _ => {}
                }
                self.move_to_front(node.id());
                break;
            }
        }

        // right click - open menu
        if ButtonState::Pressed == state && MouseButton::Right == button {
            self.open_new_module_menu();
        }
        // left click - abort menu
        if ButtonState::Pressed == state && MouseButton::Left == button {
            self.context_menu = None;
        }
    }

    fn compare_node_z(a: &Arc<Node>, b: &Arc<Node>) -> Ordering {
        let a_z = a.module().lock().unwrap().bounds().pos.z;
        let b_z = b.module().lock().unwrap().bounds().pos.z;
        a_z.partial_cmp(&b_z).unwrap()
    }

    fn move_to_front(&self, id: mf::NodeId) {
        let mut nodes = self.graph.nodes();
        nodes.sort_by(|a, b| {
            // force given id to front
            if a.id() == id {
                Ordering::Less
            } else if b.id() == id {
                Ordering::Greater
            } else {
                Self::compare_node_z(a, b)
            }
        });
        let max = nodes.len() as f32;
        for (idx, node) in nodes.iter().enumerate() {
            let mut module = node.module().lock().unwrap();
            let mut bounds = module.bounds();
            bounds.pos.z = idx as f32 / max;
            bounds.size.z = 1.0 / max;
            module.set_bounds(bounds);
        }
    }

    fn new_module(&self, meta: &mf::MetaModule<OwnedModule>, rect: Rect2) {
        // dummy z, overwritten by move_to_front
        let bounds = Box3::new(rect.pos.with_z(0.0), rect.size.with_z(0.0));
        let node = self.graph.add_node(meta, bounds);
        self.move_to_front(node.id());
    }

    fn open_new_module_menu(&mut self) {
        self.context_menu = Some(MenuView::new(
            self.ctx.clone(),
            Box3::new(
                self.mouse_pos.with_z(0.0),
                (self.window_size - self.mouse_pos).with_z(0.0),
            ),
            Menu::new(&self.module_types
                .iter()
                .map(|ty| menu::item(&ty.name))
                .collect::<Vec<_>>()),
        ));
    }

    fn generate_event(&mut self, data: EventData) {
        let event = Event {
            time: self.time,
            data,
        };
        for node in self.graph.nodes() {
            let mut module = node.module().lock().unwrap();
            module.handle(&event);
        }
        if let Some(menu) = self.context_menu.as_mut() {
            menu.handle(&event);
        }
    }

    fn handle(&mut self, event: &glutin::Event) {
        use glutin::WindowEvent::*;
        //println!("{:?}", event);
        match event {
            glutin::Event::WindowEvent {
                window_id: _,
                event,
            } => match event {
                Resized(w, h) => {
                    self.window_size = Pt2::new(*w as f32, *h as f32);
                }
                CursorMoved {
                    device_id: _,
                    position,
                    modifiers: _,
                } => {
                    self.mouse_pos = Pt2::new((position.0 as f32).floor(), (position.1 as f32).floor());
                    self.generate_event(EventData::MouseMove(self.mouse_pos));
                }
                MouseInput {
                    device_id: _,
                    state,
                    button,
                    modifiers: _,
                } => {
                    self.handle_mouse_input(state.into(), button.into());
                }
                _ => (),
            },
            _ => (),
        }
    }

    fn render(&mut self, ctx: &mut RenderContext, device: &mut gl::Device) {
        // render nodes
        let graph_nodes = self.graph.node_map();
        for (id, node) in &graph_nodes {
            let mut module = node.module().lock().unwrap();
            module.render(device, ctx);
        }

        // render global widgets
        if let Some(menu) = self.context_menu.as_mut() {
            menu.render(device, ctx);
        }
    }
}

fn load_metamodules(ctx: RenderContext) -> Vec<mf::MetaModule<OwnedModule>> {
    let mut modules = Vec::new();
    let mod_ctx = ctx;
    let test_module = mf::MetaModule::new(
        "TestModule",
        Arc::new(move |ifc, bounds| {
            Mutex::new(Box::new(GuiModuleWrapper::new(
                TestModule::new(ifc),
                mod_ctx.clone(),
                bounds,
            )) as Box<GuiComponent<GuiModuleUpdate>>)
        }),
    );
    modules.push(test_module);
    modules
}

pub fn gui_main() {
    // init window
    let mut events_loop = EventsLoop::new();
    let context = ContextBuilder::new().with_gl_profile(glutin::GlProfile::Core);
    let builder = WindowBuilder::new().with_title(String::from("flow-synth"));
    let (window, mut device, factory, main_color, main_depth) =
        gfx_glutin::init::<ColorFormat, DepthFormat>(builder, context, &events_loop);

    let mut target = Target {
        color: main_color,
        depth: main_depth,
    };

    // init rendering pipeline
    let mut ctx = RenderContext::new(factory.clone());

    let mut model = Model::new(ctx.clone());

    // begin main loop
    let mut running = true;
    let timer = Instant::now();
    let mut frames = VecDeque::new();
    while running {
        // update fps
        let now = timer.elapsed();
        model.time = now.as_secs() as f32 + now.subsec_nanos() as f32 / 1_000_000_000.0;
        frames.push_back(model.time);
        while let Some(&old_frame) = frames.front() {
            if old_frame < model.time - 1.0 {
                frames.pop_front();
            } else {
                break;
            }
        }

        // handle events
        events_loop.poll_events(|event| {
            model.handle(&event);
            use glutin::WindowEvent::*;
            match event {
                glutin::Event::WindowEvent {
                    window_id: _,
                    event,
                } => match event {
                    Closed => running = false,
                    Resized(_, _) => {
                        gfx_glutin::update_views(&window, &mut target.color, &mut target.depth);
                    }
                    _ => (),
                },
                _ => (),
            }
        });

        ctx.begin_frame(&target);

        model.render(&mut ctx, &mut device);

        // debug text
        ctx.draw_text(
            &format!("FPS={} Time={}", frames.len(), model.time),
            Pt3::new(0.0, 0.0, 0.0),
            [1.0, 1.0, 1.0],
        );

        ctx.end_frame(&mut device, &target);
        window.swap_buffers().unwrap();
        device.cleanup();
    }
}

const TITLE_BAR_HEIGHT: f32 = 24.0;
const BORDER_SIZE: f32 = 1.0;

struct GuiModuleWrapper<T: Module> {
    module: T,

    target: TextureTarget,

    delete_button: Button,
    bounds: Box3,
    drag: Option<Pt2>,
    dirty: bool,
}

impl<T: Module> GuiModuleWrapper<T> {
    fn new(module: T, ctx: RenderContext, bounds: Box3) -> GuiModuleWrapper<T> {
        let target = TextureTarget::new(ctx.clone(), bounds.size.drop_z());

        GuiModuleWrapper {
            module,
            target,
            delete_button: Button::new(
                ctx,
                "X".into(),
                Box3 {
                    pos: Pt3::new(
                        bounds.size.x - TITLE_BAR_HEIGHT - BORDER_SIZE,
                        BORDER_SIZE,
                        0.0,
                    ),
                    size: Pt3::new(TITLE_BAR_HEIGHT, TITLE_BAR_HEIGHT, 0.0),
                },
            ),
            bounds,
            drag: None,
            dirty: true,
        }
    }
    fn render_self(&mut self) {
        let title = &self.title();
        let ctx = self.target.ctx();
        // borders
        ctx.draw_rect(
            Rect3::new(Pt3::new(0.0, 0.0, 1.0), self.bounds.size.drop_z()),
            [1.0, 1.0, 1.0],
        );
        // background
        ctx.draw_rect(
            Rect3::new(
                Pt3::new(BORDER_SIZE, BORDER_SIZE + TITLE_BAR_HEIGHT, 0.9),
                self.bounds.size.drop_z() - Pt2::new(BORDER_SIZE * 2.0, BORDER_SIZE * 2.0 + TITLE_BAR_HEIGHT),
            ),
            [0.1, 0.1, 0.1],
        );
        // title bar
        ctx.draw_rect(
            Rect3::new(
                Pt3::new(BORDER_SIZE, BORDER_SIZE, 0.9),
                Pt2::new(self.bounds.size.x - BORDER_SIZE * 2.0, TITLE_BAR_HEIGHT),
            ),
            [0.0, 0.0, 0.0],
        );
        ctx.draw_text(title, Pt3::new(4.0, 4.0, 0.8), [1.0, 1.0, 1.0]);
    }
}

enum GuiModuleUpdate {
    Unchanged,
    Closed,
}

impl<T> GuiComponent<GuiModuleUpdate> for GuiModuleWrapper<T>
where
    T: Module,
{
    fn bounds(&self) -> Box3 {
        self.bounds
    }
    fn set_bounds(&mut self, bounds: Box3) {
        self.bounds = bounds;
    }
    fn intersect(&self, pos: Pt2) -> bool {
        self.bounds.flatten().drop_z().intersect(pos)
    }
    fn render(&mut self, device: &mut gl::Device, ctx: &mut RenderContext) {
        if self.dirty {
            self.target.begin_frame();
            self.render_self();
            self.delete_button.render(device, self.target.ctx());
            self.target.end_frame(device);
            self.dirty = false;
        }

        ctx.draw_textured_rect(self.bounds.flatten(), self.target.shader_resource().clone());
    }
    fn handle(&mut self, event: &Event) -> GuiModuleUpdate {
        let origin = self.bounds.pos.drop_z();
        match event.data {
            EventData::MouseMove(pos) => {
                self.dirty |=
                    ButtonUpdate::NeedRender == self.delete_button.handle(&event.translate(-origin));
                if let Some(drag) = self.drag {
                    self.bounds.pos.x = -drag.x + pos.x;
                    self.bounds.pos.y = -drag.y + pos.y;
                }
                GuiModuleUpdate::Unchanged
            }
            EventData::Click(pos, button, state) => {
                if self.delete_button.intersect(pos - origin) {
                    if ButtonUpdate::Clicked == self.delete_button.handle(&event.translate(-origin)) {
                        GuiModuleUpdate::Closed
                    } else {
                        GuiModuleUpdate::Unchanged
                    }
                } else {
                    match button {
                        MouseButton::Left => match state {
                            ButtonState::Pressed => {
                                let mut title_rect = self.bounds.flatten().drop_z();
                                title_rect.size = Pt2::new(title_rect.size.x, TITLE_BAR_HEIGHT + BORDER_SIZE);
                                if title_rect.intersect(pos) {
                                    self.drag = Some(pos - origin);
                                }
                            }
                            ButtonState::Released => {
                                self.drag = None;
                            }
                        },
                        _ => {}
                    }
                    GuiModuleUpdate::Unchanged
                }
            }
        }
    }
}
impl<T> Module for GuiModuleWrapper<T>
where
    T: Module,
{
    fn start(&mut self) {
        T::start(&mut self.module);
    }
    fn title(&self) -> String {
        T::title(&self.module)
    }
}
<commit_msg>Don't render any frames after the window has closed<commit_after>mod render;
mod menu;
mod button;
mod geom;
mod component;
mod event;

use self::render::*;
use super::module::*;
use self::menu::{Menu, MenuUpdate, MenuView};
use self::button::*;
use self::geom::*;
use self::component::*;
use self::event::*;

use glutin::{self, ContextBuilder, EventsLoop, GlContext, WindowBuilder};
use modular_flow as mf;

use std::time::Instant;
use std::collections::VecDeque;
use std::sync::{Arc, Mutex};
use std::cmp::Ordering;

use gfx::Device;
use gfx_window_glutin as gfx_glutin;
use gfx_device_gl as gl;

type OwnedModule = Mutex<Box<GuiComponent<GuiModuleUpdate>>>;
type Graph = mf::Graph<OwnedModule>;
type Node = mf::Node<OwnedModule>;

/// Model holds info about GUI state
/// and program state
pub struct Model {
    ctx: RenderContext,
    time: f32,
    graph: Arc<Graph>,
    window_size: Pt2,
    mouse_pos: Pt2,
    module_types: Vec<mf::MetaModule<OwnedModule>>,
    context_menu: Option<MenuView>,
}

impl Model {
    fn new(ctx: RenderContext) -> Model {
        Model {
            graph: Graph::new(),
            time: 0.0,
            window_size: Pt2::fill(0.0),
            mouse_pos: Pt2::fill(0.0),
            module_types: load_metamodules(ctx.clone()),
            context_menu: None,
            ctx,
        }
    }

    fn handle_mouse_input(&mut self, state: ButtonState, button: MouseButton) {
        let event = Event {
            time: self.time,
            data: EventData::Click(self.mouse_pos, button.into(), state.into()),
        };
        // intersect menu
        if let Some(menu) = self.context_menu.as_mut() {
            if menu.intersect(self.mouse_pos) {
                let status = menu.handle(&event);
                match status {
                    MenuUpdate::Select(path) => {
                        let name = path[0].as_ref();
                        let module = self.module_types.iter().find(|ty| ty.name == name).unwrap();
                        self.new_module(module, Rect2::new(self.mouse_pos, Pt2::fill(256.0)));
                        self.context_menu = None;
                    }
                    _ => (),
                }
                return;
            }
        }

        // intersect nodes
        let mut nodes = self.graph.nodes();
        nodes.sort_by(Self::compare_node_z);
        for node in &nodes {
            let mut module = node.module().lock().unwrap();
            if module.intersect(self.mouse_pos) {
                let status = module.handle(&event);
                drop(module);
                match status {
                    GuiModuleUpdate::Closed => {
                        self.graph.remove_node(node.id()).unwrap();
                    }
                    _ => {}
                }
                self.move_to_front(node.id());
                break;
            }
        }

        // right click - open menu
        if ButtonState::Pressed == state && MouseButton::Right == button {
            self.open_new_module_menu();
        }
        // left click - abort menu
        if ButtonState::Pressed == state && MouseButton::Left == button {
            self.context_menu = None;
        }
    }

    fn compare_node_z(a: &Arc<Node>, b: &Arc<Node>) -> Ordering {
        let a_z = a.module().lock().unwrap().bounds().pos.z;
        let b_z = b.module().lock().unwrap().bounds().pos.z;
        a_z.partial_cmp(&b_z).unwrap()
    }

    fn move_to_front(&self, id: mf::NodeId) {
        let mut nodes = self.graph.nodes();
        nodes.sort_by(|a, b| {
            // force given id to front
            if a.id() == id {
                Ordering::Less
            } else if b.id() == id {
                Ordering::Greater
            } else {
                Self::compare_node_z(a, b)
            }
        });
        let max = nodes.len() as f32;
        for (idx, node) in nodes.iter().enumerate() {
            let mut module = node.module().lock().unwrap();
            let mut bounds = module.bounds();
            bounds.pos.z = idx as f32 / max;
            bounds.size.z = 1.0 / max;
            module.set_bounds(bounds);
        }
    }

    fn new_module(&self, meta: &mf::MetaModule<OwnedModule>, rect: Rect2) {
        // dummy z, overwritten by move_to_front
        let bounds = Box3::new(rect.pos.with_z(0.0), rect.size.with_z(0.0));
        let node = self.graph.add_node(meta, bounds);
        self.move_to_front(node.id());
    }

    fn open_new_module_menu(&mut self) {
        self.context_menu = Some(MenuView::new(
            self.ctx.clone(),
            Box3::new(
                self.mouse_pos.with_z(0.0),
                (self.window_size - self.mouse_pos).with_z(0.0),
            ),
            Menu::new(&self.module_types
                .iter()
                .map(|ty| menu::item(&ty.name))
                .collect::<Vec<_>>()),
        ));
    }

    fn generate_event(&mut self, data: EventData) {
        let event = Event {
            time: self.time,
            data,
        };
        for node in self.graph.nodes() {
            let mut module = node.module().lock().unwrap();
            module.handle(&event);
        }
        if let Some(menu) = self.context_menu.as_mut() {
            menu.handle(&event);
        }
    }

    fn handle(&mut self, event: &glutin::Event) {
        use glutin::WindowEvent::*;
        //println!("{:?}", event);
        match event {
            glutin::Event::WindowEvent {
                window_id: _,
                event,
            } => match event {
                Resized(w, h) => {
                    self.window_size = Pt2::new(*w as f32, *h as f32);
                }
                CursorMoved {
                    device_id: _,
                    position,
                    modifiers: _,
                } => {
                    self.mouse_pos = Pt2::new((position.0 as f32).floor(), (position.1 as f32).floor());
                    self.generate_event(EventData::MouseMove(self.mouse_pos));
                }
                MouseInput {
                    device_id: _,
                    state,
                    button,
                    modifiers: _,
                } => {
                    self.handle_mouse_input(state.into(), button.into());
                }
                _ => (),
            },
            _ => (),
        }
    }

    fn render(&mut self, ctx: &mut RenderContext, device: &mut gl::Device) {
        // render nodes
        let graph_nodes = self.graph.node_map();
        for (id, node) in &graph_nodes {
            let mut module = node.module().lock().unwrap();
            module.render(device, ctx);
        }

        // render global widgets
        if let Some(menu) = self.context_menu.as_mut() {
            menu.render(device, ctx);
        }
    }
}

fn load_metamodules(ctx: RenderContext) -> Vec<mf::MetaModule<OwnedModule>> {
    let mut modules = Vec::new();
    let mod_ctx = ctx;
    let test_module = mf::MetaModule::new(
        "TestModule",
        Arc::new(move |ifc, bounds| {
            Mutex::new(Box::new(GuiModuleWrapper::new(
                TestModule::new(ifc),
                mod_ctx.clone(),
                bounds,
            )) as Box<GuiComponent<GuiModuleUpdate>>)
        }),
    );
    modules.push(test_module);
    modules
}

pub fn gui_main() {
    // init window
    let mut events_loop = EventsLoop::new();
    let context = ContextBuilder::new().with_gl_profile(glutin::GlProfile::Core);
    let builder = WindowBuilder::new().with_title(String::from("flow-synth"));
    let (window, mut device, factory, main_color, main_depth) =
        gfx_glutin::init::<ColorFormat, DepthFormat>(builder, context, &events_loop);

    let mut target = Target {
        color: main_color,
        depth: main_depth,
    };

    // init rendering pipeline
    let mut ctx = RenderContext::new(factory.clone());

    let mut model = Model::new(ctx.clone());

    // begin main loop
    let mut running = true;
    let timer = Instant::now();
    let mut frames = VecDeque::new();
    loop {
        // update fps
        let now = timer.elapsed();
        model.time = now.as_secs() as f32 + now.subsec_nanos() as f32 / 1_000_000_000.0;
        frames.push_back(model.time);
        while let Some(&old_frame) = frames.front() {
            if old_frame < model.time - 1.0 {
                frames.pop_front();
            } else {
                break;
            }
        }

        // handle events
        events_loop.poll_events(|event| {
            model.handle(&event);
            use glutin::WindowEvent::*;
            match event {
                glutin::Event::WindowEvent {
                    window_id: _,
                    event,
                } => match event {
                    Closed => running = false,
                    Resized(_, _) => {
                        gfx_glutin::update_views(&window, &mut target.color, &mut target.depth);
                    }
                    _ => (),
                },
                _ => (),
            }
        });

        if !running {
            break;
        }

        ctx.begin_frame(&target);

        model.render(&mut ctx, &mut device);

        // debug text
        ctx.draw_text(
            &format!("FPS={} Time={}", frames.len(), model.time),
            Pt3::new(0.0, 0.0, 0.0),
            [1.0, 1.0, 1.0],
        );

        ctx.end_frame(&mut device, &target);
        window.swap_buffers().unwrap();
        device.cleanup();
    }
}

const TITLE_BAR_HEIGHT: f32 = 24.0;
const BORDER_SIZE: f32 = 1.0;

struct GuiModuleWrapper<T: Module> {
    module: T,

    target: TextureTarget,

    delete_button: Button,
    bounds: Box3,
    drag: Option<Pt2>,
    dirty: bool,
}

impl<T: Module> GuiModuleWrapper<T> {
    fn new(module: T, ctx: RenderContext, bounds: Box3) -> GuiModuleWrapper<T> {
        let target = TextureTarget::new(ctx.clone(), bounds.size.drop_z());

        GuiModuleWrapper {
            module,
            target,
            delete_button: Button::new(
                ctx,
                "X".into(),
                Box3 {
                    pos: Pt3::new(
                        bounds.size.x - TITLE_BAR_HEIGHT - BORDER_SIZE,
                        BORDER_SIZE,
                        0.0,
                    ),
                    size: Pt3::new(TITLE_BAR_HEIGHT, TITLE_BAR_HEIGHT, 0.0),
                },
            ),
            bounds,
            drag: None,
            dirty: true,
        }
    }
    fn render_self(&mut self) {
        let title = &self.title();
        let ctx = self.target.ctx();
        // borders
        ctx.draw_rect(
            Rect3::new(Pt3::new(0.0, 0.0, 1.0), self.bounds.size.drop_z()),
            [1.0, 1.0, 1.0],
        );
        // background
        ctx.draw_rect(
            Rect3::new(
                Pt3::new(BORDER_SIZE, BORDER_SIZE + TITLE_BAR_HEIGHT, 0.9),
                self.bounds.size.drop_z() - Pt2::new(BORDER_SIZE * 2.0, BORDER_SIZE * 2.0 + TITLE_BAR_HEIGHT),
            ),
            [0.1, 0.1, 0.1],
        );
        // title bar
        ctx.draw_rect(
            Rect3::new(
                Pt3::new(BORDER_SIZE, BORDER_SIZE, 0.9),
                Pt2::new(self.bounds.size.x - BORDER_SIZE * 2.0, TITLE_BAR_HEIGHT),
            ),
            [0.0, 0.0, 0.0],
        );
        ctx.draw_text(title, Pt3::new(4.0, 4.0, 0.8), [1.0, 1.0, 1.0]);
    }
}

enum GuiModuleUpdate {
    Unchanged,
    Closed,
}

impl<T> GuiComponent<GuiModuleUpdate> for GuiModuleWrapper<T>
where
    T: Module,
{
    fn bounds(&self) -> Box3 {
        self.bounds
    }
    fn set_bounds(&mut self, bounds: Box3) {
        self.bounds = bounds;
    }
    fn intersect(&self, pos: Pt2) -> bool {
        self.bounds.flatten().drop_z().intersect(pos)
    }
    fn render(&mut self, device: &mut gl::Device, ctx: &mut RenderContext) {
        if self.dirty {
            self.target.begin_frame();
            self.render_self();
            self.delete_button.render(device, self.target.ctx());
            self.target.end_frame(device);
            self.dirty = false;
        }

        ctx.draw_textured_rect(self.bounds.flatten(), self.target.shader_resource().clone());
    }
    fn handle(&mut self, event: &Event) -> GuiModuleUpdate {
        let origin = self.bounds.pos.drop_z();
        match event.data {
            EventData::MouseMove(pos) => {
                self.dirty |=
                    ButtonUpdate::NeedRender == self.delete_button.handle(&event.translate(-origin));
                if let Some(drag) = self.drag {
                    self.bounds.pos.x = -drag.x + pos.x;
                    self.bounds.pos.y = -drag.y + pos.y;
                }
                GuiModuleUpdate::Unchanged
            }
            EventData::Click(pos, button, state) => {
                if self.delete_button.intersect(pos - origin) {
                    if ButtonUpdate::Clicked == self.delete_button.handle(&event.translate(-origin)) {
                        GuiModuleUpdate::Closed
                    } else {
                        GuiModuleUpdate::Unchanged
                    }
                } else {
                    match button {
                        MouseButton::Left => match state {
                            ButtonState::Pressed => {
                                let mut title_rect = self.bounds.flatten().drop_z();
                                title_rect.size = Pt2::new(title_rect.size.x, TITLE_BAR_HEIGHT + BORDER_SIZE);
                                if title_rect.intersect(pos) {
                                    self.drag = Some(pos - origin);
                                }
                            }
                            ButtonState::Released => {
                                self.drag = None;
                            }
                        },
                        _ => {}
                    }
                    GuiModuleUpdate::Unchanged
                }
            }
        }
    }
}
impl<T> Module for GuiModuleWrapper<T>
where
    T: Module,
{
    fn start(&mut self) {
        T::start(&mut self.module);
    }
    fn title(&self) -> String {
        T::title(&self.module)
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use std::result::Result;
use std::rc::Rc;
use std::cell::RefCell;
use handle_table::{Handle};
use ::io::{AsyncRead, AsyncWrite, try_read_internal, write_internal,
           FdObserver, HasHandle, register_new_handle,
           Error};
use {EventLoop, Promise, WaitScope};
use private::{with_current_event_loop};

pub struct Stream {
    stream: ::mio::unix::UnixStream,
    handle: Handle,
    no_send: ::std::marker::PhantomData<*mut ()>, // impl !Send for Stream
}

pub struct Listener {
    listener: ::mio::unix::UnixListener,
    handle: Handle,
    no_send: ::std::marker::PhantomData<*mut ()>, // impl !Send for Listener
}

impl Drop for Listener {
    fn drop(&mut self) {
        with_current_event_loop(move |event_loop| {
            event_loop.event_port.borrow_mut().handler.observers.remove(self.handle);
        })
    }
}

impl Listener {
    pub fn bind<P: AsRef<::std::path::Path>>(addr: P) -> Result<Listener, ::std::io::Error> {
        let listener = try!(::mio::unix::UnixListener::bind(&addr));
        let handle = FdObserver::new();

        with_current_event_loop(move |event_loop| {
            try!(event_loop.event_port.borrow_mut().reactor.register(&listener, ::mio::Token(handle.val),
                                                                         ::mio::EventSet::readable(),
                                                                         ::mio::PollOpt::edge()));
            Ok(Listener { listener: listener, handle: handle, no_send: ::std::marker::PhantomData })
        })
    }

    fn accept_internal(self) -> Promise<(Listener, Stream), Error<Listener>> {
        let accept_result = match self.listener.accept() {
            Err(e) => return Promise::err((Error::new(self, e))),
            Ok(v) => v,
        };
        match accept_result {
            Some(stream) => {
                let handle = match register_new_handle(&stream) {
                    Err(e) => return Promise::err(Error::new(self, e)),
                    Ok(v) => v,
                };
                Promise::ok((self, Stream::new(stream, handle)))
            }
            None => {
                with_current_event_loop(move |event_loop| {
                    let promise =
                        event_loop.event_port.borrow_mut().handler.observers[self.handle].when_becomes_readable();
                    promise.then_else(move |r| match r {
                        Ok(()) => self.accept_internal(),
                        Err(e) => Promise::err(Error::new(self, e))
                    })
                })
            }
        }
    }

    pub fn accept(self) -> Promise<(Listener, Stream), Error<Listener>> {
        Promise::ok(()).then(move |()| self.accept_internal())
    }
}

impl ::std::io::Read for Stream {
    fn read(&mut self, buf: &mut [u8]) -> ::std::io::Result<usize> {
        use std::io::Read;
        self.stream.read(buf)
    }
}

impl ::std::io::Write for Stream {
    fn write(&mut self, buf: &[u8]) -> ::std::io::Result<usize> {
        use std::io::Write;
        self.stream.write(buf)
    }
    fn flush(&mut self) -> ::std::io::Result<()> { Ok(()) }
}

impl HasHandle for Stream {
    fn get_handle(&self) -> Handle { self.handle }
}

impl Drop for Stream {
    fn drop(&mut self) {
        with_current_event_loop(move |event_loop| {
            event_loop.event_port.borrow_mut().handler.observers.remove(self.handle);
        })
    }
}

impl Stream {
    fn new(stream: ::mio::unix::UnixStream, handle: Handle) -> Stream {
        Stream { stream: stream, handle: handle, no_send: ::std::marker::PhantomData }
    }

    pub fn connect<P: AsRef<::std::path::Path>>(addr: P) -> Promise<Stream, ::std::io::Error> {
        let connect_result = ::mio::unix::UnixStream::connect(&addr);
        Promise::ok(()).then(move |()| {
            let stream = pry!(connect_result);

            // TODO: if we're not already connected, maybe only register writable interest,
            // and then reregister with read/write interested once we successfully connect.

            let handle = pry!(register_new_handle(&stream));

            with_current_event_loop(move |event_loop| {
                let promise =
                    event_loop.event_port.borrow_mut().handler.observers[handle].when_becomes_writable();
                promise.map(move |()| {
                    //try!(stream.take_socket_error());
                    Ok(Stream::new(stream, handle))
                })
            })
        })
    }

    pub fn new_pair() -> Result<(Stream, Stream), ::std::io::Error> {
        use nix::sys::socket::{socketpair, AddressFamily, SockType, SOCK_CLOEXEC, SOCK_NONBLOCK};
        use std::os::unix::io::FromRawFd;

        let (fd1, fd2) =
            try!(socketpair(AddressFamily::Unix, SockType::Stream, 0, SOCK_NONBLOCK | SOCK_CLOEXEC)
                 .map_err(|_| ::std::io::Error::new(::std::io::ErrorKind::Other,
                                                    "failed to create socketpair")));

        unsafe { Ok((try!(Stream::from_raw_fd(fd1)), try!(Stream::from_raw_fd(fd2)))) }
    }

    pub fn try_clone(&self) -> Result<Stream, ::std::io::Error> {
        let stream = try!(self.stream.try_clone());
        let handle = try!(register_new_handle(&stream));
        Ok(Stream::new(stream, handle))
    }

    pub fn split(self) -> (Reader, Writer) {
        let inner = Rc::new(RefCell::new(self));
        (Reader { stream: inner.clone() }, Writer { stream: inner })
    }

    pub unsafe fn from_raw_fd(fd: ::std::os::unix::io::RawFd) -> Result<Stream, ::std::io::Error> {
        let stream = ::std::os::unix::io::FromRawFd::from_raw_fd(fd);
        let handle = try!(register_new_handle(&stream));
        Ok(Stream::new(stream, handle))
    }
}

impl AsyncRead for Stream {
    fn try_read<T>(self, buf: T,
                   min_bytes: usize) -> Promise<(Self, T, usize), Error<(Self, T)>>
        where T: AsMut<[u8]>
    {
        try_read_internal(self, buf, 0, min_bytes)
    }
}

impl AsyncWrite for Stream {
    fn write<T>(self, buf: T) -> Promise<(Self, T), Error<(Self, T)>> where T: AsRef<[u8]> {
        write_internal(self, buf, 0)
    }
}

/// Creates a new thread and sets up a socket pair that can be used to communicate with it.
/// Passes one of the sockets to the thread's start function and returns the other socket.
/// The new thread will already have an active event loop when `start_func` is called.
pub fn spawn<F>(start_func: F) -> Result<(::std::thread::JoinHandle<()>, Stream), Box<::std::error::Error>>
    where F: FnOnce(Stream, &WaitScope) -> Result<(), Box<::std::error::Error>>,
          F: Send + 'static
{
    use nix::sys::socket::{socketpair, AddressFamily, SockType, SOCK_CLOEXEC, SOCK_NONBLOCK};
    use std::os::unix::io::FromRawFd;

    let (fd0, fd1) =
        // eh... the trait `std::error::Error` is not implemented for the type `nix::Error`
        match socketpair(AddressFamily::Unix, SockType::Stream, 0, SOCK_NONBLOCK | SOCK_CLOEXEC) {
            Ok(v) => v,
            Err(_) => {
                return Err(Box::new(::std::io::Error::new(::std::io::ErrorKind::Other,
                                                          "failed to create socketpair")))
            }
        };

    let socket_stream = try!(unsafe { Stream::from_raw_fd(fd0) });

    let join_handle = ::std::thread::spawn(move || {
        let _result = EventLoop::top_level(move |wait_scope| {
            let socket_stream = try!(unsafe { Stream::from_raw_fd(fd1) });
            start_func(socket_stream, &wait_scope)
        });
    });

    return Ok((join_handle, socket_stream));
}

pub struct Reader {
    stream: Rc<RefCell<Stream>>
}

impl ::std::io::Read for Reader {
    fn read(&mut self, buf: &mut [u8]) -> ::std::io::Result<usize> {
        use std::io::Read;
        self.stream.borrow_mut().stream.read(buf)
    }
}

impl HasHandle for Reader {
    fn get_handle(&self) -> Handle { self.stream.borrow().handle }
}

impl AsyncRead for Reader {
    fn try_read<T>(self, buf: T, min_bytes: usize) -> Promise<(Self, T, usize), Error<(Self, T)>>
        where T: AsMut<[u8]>
    {
        try_read_internal(self, buf, 0, min_bytes)
    }
}

pub struct Writer {
    stream: Rc<RefCell<Stream>>
}

impl ::std::io::Write for Writer {
    fn write(&mut self, buf: &[u8]) -> ::std::io::Result<usize> {
        use std::io::Write;
        self.stream.borrow_mut().stream.write(buf)
    }
    fn flush(&mut self) -> ::std::io::Result<()> { Ok(()) }
}

impl HasHandle for Writer {
    fn get_handle(&self) -> Handle { self.stream.borrow().handle }
}

impl AsyncWrite for Writer {
    fn write<T>(self, buf: T) -> Promise<(Self, T), Error<(Self, T)>> where T: AsRef<[u8]> {
        write_internal(self, buf, 0)
    }
}
<commit_msg>nix::Error now implements std::error::Error<commit_after>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use std::result::Result;
use std::rc::Rc;
use std::cell::RefCell;
use handle_table::{Handle};
use ::io::{AsyncRead, AsyncWrite, try_read_internal, write_internal,
           FdObserver, HasHandle, register_new_handle,
           Error};
use {EventLoop, Promise, WaitScope};
use private::{with_current_event_loop};

pub struct Stream {
    stream: ::mio::unix::UnixStream,
    handle: Handle,
    no_send: ::std::marker::PhantomData<*mut ()>, // impl !Send for Stream
}

pub struct Listener {
    listener: ::mio::unix::UnixListener,
    handle: Handle,
    no_send: ::std::marker::PhantomData<*mut ()>, // impl !Send for Listener
}

impl Drop for Listener {
    fn drop(&mut self) {
        with_current_event_loop(move |event_loop| {
            event_loop.event_port.borrow_mut().handler.observers.remove(self.handle);
        })
    }
}

impl Listener {
    pub fn bind<P: AsRef<::std::path::Path>>(addr: P) -> Result<Listener, ::std::io::Error> {
        let listener = try!(::mio::unix::UnixListener::bind(&addr));
        let handle = FdObserver::new();

        with_current_event_loop(move |event_loop| {
            try!(event_loop.event_port.borrow_mut().reactor.register(&listener, ::mio::Token(handle.val),
                                                                         ::mio::EventSet::readable(),
                                                                         ::mio::PollOpt::edge()));
            Ok(Listener { listener: listener, handle: handle, no_send: ::std::marker::PhantomData })
        })
    }

    fn accept_internal(self) -> Promise<(Listener, Stream), Error<Listener>> {
        let accept_result = match self.listener.accept() {
            Err(e) => return Promise::err((Error::new(self, e))),
            Ok(v) => v,
        };
        match accept_result {
            Some(stream) => {
                let handle = match register_new_handle(&stream) {
                    Err(e) => return Promise::err(Error::new(self, e)),
                    Ok(v) => v,
                };
                Promise::ok((self, Stream::new(stream, handle)))
            }
            None => {
                with_current_event_loop(move |event_loop| {
                    let promise =
                        event_loop.event_port.borrow_mut().handler.observers[self.handle].when_becomes_readable();
                    promise.then_else(move |r| match r {
                        Ok(()) => self.accept_internal(),
                        Err(e) => Promise::err(Error::new(self, e))
                    })
                })
            }
        }
    }

    pub fn accept(self) -> Promise<(Listener, Stream), Error<Listener>> {
        Promise::ok(()).then(move |()| self.accept_internal())
    }
}

impl ::std::io::Read for Stream {
    fn read(&mut self, buf: &mut [u8]) -> ::std::io::Result<usize> {
        use std::io::Read;
        self.stream.read(buf)
    }
}

impl ::std::io::Write for Stream {
    fn write(&mut self, buf: &[u8]) -> ::std::io::Result<usize> {
        use std::io::Write;
        self.stream.write(buf)
    }
    fn flush(&mut self) -> ::std::io::Result<()> { Ok(()) }
}

impl HasHandle for Stream {
    fn get_handle(&self) -> Handle { self.handle }
}

impl Drop for Stream {
    fn drop(&mut self) {
        with_current_event_loop(move |event_loop| {
            event_loop.event_port.borrow_mut().handler.observers.remove(self.handle);
        })
    }
}

impl Stream {
    fn new(stream: ::mio::unix::UnixStream, handle: Handle) -> Stream {
        Stream { stream: stream, handle: handle, no_send: ::std::marker::PhantomData }
    }

    pub fn connect<P: AsRef<::std::path::Path>>(addr: P) -> Promise<Stream, ::std::io::Error> {
        let connect_result = ::mio::unix::UnixStream::connect(&addr);
        Promise::ok(()).then(move |()| {
            let stream = pry!(connect_result);

            // TODO: if we're not already connected, maybe only register writable interest,
            // and then reregister with read/write interested once we successfully connect.

            let handle = pry!(register_new_handle(&stream));

            with_current_event_loop(move |event_loop| {
                let promise =
                    event_loop.event_port.borrow_mut().handler.observers[handle].when_becomes_writable();
                promise.map(move |()| {
                    //try!(stream.take_socket_error());
                    Ok(Stream::new(stream, handle))
                })
            })
        })
    }

    pub fn new_pair() -> Result<(Stream, Stream), ::std::io::Error> {
        use nix::sys::socket::{socketpair, AddressFamily, SockType, SOCK_CLOEXEC, SOCK_NONBLOCK};
        use std::os::unix::io::FromRawFd;

        let (fd1, fd2) =
            try!(socketpair(AddressFamily::Unix, SockType::Stream, 0, SOCK_NONBLOCK | SOCK_CLOEXEC)
                 .map_err(|_| ::std::io::Error::new(::std::io::ErrorKind::Other,
                                                    "failed to create socketpair")));

        unsafe { Ok((try!(Stream::from_raw_fd(fd1)), try!(Stream::from_raw_fd(fd2)))) }
    }

    pub fn try_clone(&self) -> Result<Stream, ::std::io::Error> {
        let stream = try!(self.stream.try_clone());
        let handle = try!(register_new_handle(&stream));
        Ok(Stream::new(stream, handle))
    }

    pub fn split(self) -> (Reader, Writer) {
        let inner = Rc::new(RefCell::new(self));
        (Reader { stream: inner.clone() }, Writer { stream: inner })
    }

    pub unsafe fn from_raw_fd(fd: ::std::os::unix::io::RawFd) -> Result<Stream, ::std::io::Error> {
        let stream = ::std::os::unix::io::FromRawFd::from_raw_fd(fd);
        let handle = try!(register_new_handle(&stream));
        Ok(Stream::new(stream, handle))
    }
}

impl AsyncRead for Stream {
    fn try_read<T>(self, buf: T,
                   min_bytes: usize) -> Promise<(Self, T, usize), Error<(Self, T)>>
        where T: AsMut<[u8]>
    {
        try_read_internal(self, buf, 0, min_bytes)
    }
}

impl AsyncWrite for Stream {
    fn write<T>(self, buf: T) -> Promise<(Self, T), Error<(Self, T)>> where T: AsRef<[u8]> {
        write_internal(self, buf, 0)
    }
}

/// Creates a new thread and sets up a socket pair that can be used to communicate with it.
/// Passes one of the sockets to the thread's start function and returns the other socket.
/// The new thread will already have an active event loop when `start_func` is called.
pub fn spawn<F>(start_func: F) -> Result<(::std::thread::JoinHandle<()>, Stream), Box<::std::error::Error>>
    where F: FnOnce(Stream, &WaitScope) -> Result<(), Box<::std::error::Error>>,
          F: Send + 'static
{
    use nix::sys::socket::{socketpair, AddressFamily, SockType, SOCK_CLOEXEC, SOCK_NONBLOCK};
    use std::os::unix::io::FromRawFd;

    let (fd0, fd1) =
        try!(socketpair(AddressFamily::Unix, SockType::Stream, 0, SOCK_NONBLOCK | SOCK_CLOEXEC));

    let socket_stream = try!(unsafe { Stream::from_raw_fd(fd0) });

    let join_handle = ::std::thread::spawn(move || {
        let _result = EventLoop::top_level(move |wait_scope| {
            let socket_stream = try!(unsafe { Stream::from_raw_fd(fd1) });
            start_func(socket_stream, &wait_scope)
        });
    });

    return Ok((join_handle, socket_stream));
}

pub struct Reader {
    stream: Rc<RefCell<Stream>>
}

impl ::std::io::Read for Reader {
    fn read(&mut self, buf: &mut [u8]) -> ::std::io::Result<usize> {
        use std::io::Read;
        self.stream.borrow_mut().stream.read(buf)
    }
}

impl HasHandle for Reader {
    fn get_handle(&self) -> Handle { self.stream.borrow().handle }
}

impl AsyncRead for Reader {
    fn try_read<T>(self, buf: T, min_bytes: usize) -> Promise<(Self, T, usize), Error<(Self, T)>>
        where T: AsMut<[u8]>
    {
        try_read_internal(self, buf, 0, min_bytes)
    }
}

pub struct Writer {
    stream: Rc<RefCell<Stream>>
}

impl ::std::io::Write for Writer {
    fn write(&mut self, buf: &[u8]) -> ::std::io::Result<usize> {
        use std::io::Write;
        self.stream.borrow_mut().stream.write(buf)
    }
    fn flush(&mut self) -> ::std::io::Result<()> { Ok(()) }
}

impl HasHandle for Writer {
    fn get_handle(&self) -> Handle { self.stream.borrow().handle }
}

impl AsyncWrite for Writer {
    fn write<T>(self, buf: T) -> Promise<(Self, T), Error<(Self, T)>> where T: AsRef<[u8]> {
        write_internal(self, buf, 0)
    }
}
<|endoftext|>


<commit_before>use amq_protocol::frame::{GenError, Offset, gen_frame, parse_frame};
use log::{error, trace};
use mio::{Evented, Events, Poll, PollOpt, Ready, Registration, SetReadiness, Token};
use parking_lot::Mutex;

use std::{
  io::{self, Read, Write},
  sync::{
    Arc,
    atomic::{AtomicBool, Ordering},
  },
  thread::{self, Builder as ThreadBuilder, JoinHandle},
  time::{Duration, Instant},
};

use crate::{
  buffer::Buffer,
  connection::Connection,
  connection_status::ConnectionState,
  error::{Error, ErrorKind},
};

const SOCKET:   Token = Token(1);
const DATA:     Token = Token(2);
const CONTINUE: Token = Token(3);

const FRAMES_STORAGE: usize = 32;

#[derive(Clone, Debug)]
pub(crate) struct IoLoopHandle {
  handle: Arc<Mutex<Option<JoinHandle<Result<(), Error>>>>>,
}

impl Default for IoLoopHandle {
  fn default() -> Self {
    Self { handle: Arc::new(Mutex::new(None)) }
  }
}

impl IoLoopHandle {
  pub(crate) fn register(&self, handle: JoinHandle<Result<(), Error>>) {
    *self.handle.lock() = Some(handle);
  }

  pub(crate) fn wait(&self) -> Result<(), Error> {
    if let Some(handle) = self.handle.lock().take() {
      handle.join().expect("io loop")?
    }
    Ok(())
  }
}

#[derive(Debug, PartialEq)]
enum Status {
  Initial,
  Setup,
  Stop,
}

pub struct IoLoop<T> {
  connection:     Connection,
  socket:         T,
  status:         Status,
  poll:           Poll,
  registration:   Registration,
  set_readiness:  SetReadiness,
  hb_handle:      Option<JoinHandle<()>>,
  frame_size:     usize,
  receive_buffer: Buffer,
  send_buffer:    Buffer,
  can_write:      bool,
  can_read:       bool,
  has_data:       bool,
  send_heartbeat: Arc<AtomicBool>,
  poll_timeout:   Option<Duration>,
}

impl<T: Evented + Read + Write + Send + 'static> IoLoop<T> {
  pub(crate) fn new(connection: Connection, socket: T) -> Result<Self, Error> {
    let frame_size = std::cmp::max(8192, connection.configuration().frame_max() as usize);
    let (registration, set_readiness) = Registration::new2();
    let inner = Self {
      connection,
      socket,
      status:         Status::Initial,
      poll:           Poll::new().map_err(ErrorKind::IOError)?,
      registration,
      set_readiness,
      hb_handle:      None,
      frame_size,
      receive_buffer: Buffer::with_capacity(FRAMES_STORAGE * frame_size),
      send_buffer:    Buffer::with_capacity(FRAMES_STORAGE * frame_size),
      can_write:      false,
      can_read:       false,
      has_data:       false,
      send_heartbeat: Arc::new(AtomicBool::new(false)),
      poll_timeout:   None,
    };
    inner.poll.register(&inner.socket, SOCKET, Ready::all(), PollOpt::edge()).map_err(ErrorKind::IOError)?;
    inner.poll.register(&inner.connection, DATA, Ready::readable(), PollOpt::edge()).map_err(ErrorKind::IOError)?;
    inner.poll.register(&inner.registration, CONTINUE, Ready::readable(), PollOpt::edge()).map_err(ErrorKind::IOError)?;
    Ok(inner)
  }

  fn start_heartbeat(&mut self, interval: Duration) -> Result<(), Error> {
    let connection    = self.connection.clone();
    let send_hartbeat = self.send_heartbeat.clone();
    let hb_handle = ThreadBuilder::new().name("heartbeat".to_owned()).spawn(move || {
      while connection.status().connected() {
        let start         = Instant::now();
        let mut remaining = interval;

        loop {
          thread::park_timeout(remaining);
          let elapsed = start.elapsed();
          if elapsed >= remaining {
            break
          }
          remaining -= interval - elapsed;
        }

        send_hartbeat.store(true, Ordering::Relaxed);
      }
    }).map_err(ErrorKind::IOError)?;
    self.hb_handle = Some(hb_handle);
    Ok(())
  }

  fn heartbeat(&mut self) -> Result<(), Error> {
    trace!("send heartbeat");
    self.connection.send_heartbeat()?;
    self.send_heartbeat.store(false, Ordering::Relaxed);
    Ok(())
  }

  fn ensure_setup(&mut self) -> Result<(), Error> {
    if self.status != Status::Setup && self.connection.status().connected() {
      let frame_max = self.connection.configuration().frame_max() as usize;
      self.frame_size = std::cmp::max(self.frame_size, frame_max);
      self.receive_buffer.grow(FRAMES_STORAGE * self.frame_size);
      self.send_buffer.grow(FRAMES_STORAGE * self.frame_size);
      let heartbeat = self.connection.configuration().heartbeat();
      if heartbeat != 0 {
        trace!("io_loop: start heartbeat");
        let heartbeat = Duration::from_secs(heartbeat as u64);
        self.start_heartbeat(heartbeat)?;
        self.poll_timeout = Some(heartbeat);
        trace!("io_loop: heartbeat started");
      }
      self.status = Status::Setup;
    }
    Ok(())
  }

  fn wants_to_write(&self) -> bool {
    self.can_write && self.has_data
  }

  fn wants_to_read(&self) -> bool {
    self.can_read
  }

  fn should_continue(&self) -> bool {
    let connection_status = self.connection.status();
    (self.status == Status::Initial || connection_status.connected() || connection_status.closing()) && self.status != Status::Stop && !connection_status.errored()
  }

  pub fn run(mut self) -> Result<(), Error> {
    self.connection.clone().set_io_loop(ThreadBuilder::new().name("io_loop".to_owned()).spawn(move || {
      let mut events = Events::with_capacity(1024);
      while self.should_continue() {
        self.do_run(&mut events)?;
      }
      if let Some(hb_handle) = self.hb_handle.take() {
        hb_handle.thread().unpark();
        hb_handle.join().expect("heartbeat loop failed");
      }
      Ok(())
    }).map_err(ErrorKind::IOError)?);
    Ok(())
  }

  fn do_run(&mut self, events: &mut Events) -> Result<(), Error> {
    // First, update our internal state
    trace!("io_loop run");
    self.ensure_setup()?;
    trace!("io_loop poll");
    self.poll.poll(events, self.poll_timeout).map_err(ErrorKind::IOError)?;
    trace!("io_loop poll done");
    for event in events.iter() {
      match event.token() {
        SOCKET    => {
          if event.readiness().is_readable() {
            self.can_read = true;
          }
          if event.readiness().is_writable() {
            self.can_write = true;
          }
        },
        DATA      => self.has_data = true,
        _         => {},
      }
    }

    // Then, actually run an iteration of the event loop
    trace!("io_loop do_run; can_read={}, can_write={}, has_data={}", self.can_read, self.can_write, self.has_data);
    loop {
      if self.send_heartbeat.load(Ordering::Relaxed) {
        self.heartbeat()?;
      }
      if self.wants_to_write() && !self.connection.status().blocked() {
        if let Err(e) = self.write_to_stream() {
          match e.kind() {
            ErrorKind::IOError(e) if e.kind() == io::ErrorKind::WouldBlock => self.can_write = false,
            _ => {
              error!("error writing: {:?}", e);
              if let ConnectionState::SentProtocolHeader(wait_handle, ..) = self.connection.status().state() {
                wait_handle.error(ErrorKind::ConnectionRefused.into());
                self.status = Status::Stop;
              }
              self.connection.set_error()?;
              return Err(e);
            }
          }
        }
        self.send_buffer.shift_unless_available(self.frame_size);
      }
      if self.connection.status().closed() {
        self.status = Status::Stop;
      }
      if self.should_continue() && self.wants_to_read() {
        if let Err(e) = self.read_from_stream() {
          match e.kind() {
            ErrorKind::IOError(e) if e.kind() == io::ErrorKind::WouldBlock => self.can_read = false,
            _ => {
              error!("error reading: {:?}", e);
              self.connection.set_error()?;
              return Err(e);
            }
          }
        }
        self.receive_buffer.shift_unless_available(self.frame_size);
      }
      if self.can_parse() {
        self.parse()?;
      }
      if !self.wants_to_read() || !self.wants_to_write() || self.status == Status::Stop || self.connection.status().errored() || self.connection.status().blocked() {
        if self.status != Status::Stop && !self.connection.status().blocked() && (self.wants_to_read() || self.can_parse() || self.has_data) {
          trace!("io_loop send continue; can_read={}, can_write={}, has_data={}", self.can_read, self.can_write, self.has_data);
          self.set_readiness.set_readiness(Ready::readable()).map_err(ErrorKind::IOError)?;
        }
        break;
      }
    }
    trace!("io_loop do_run done; can_read={}, can_write={}, has_data={}, status={:?}", self.can_read, self.can_write, self.has_data, self.status);
    Ok(())
  }

  fn can_parse(&self) -> bool {
    self.receive_buffer.available_data() > 0
  }

  fn write_to_stream(&mut self) -> Result<(), Error> {
    self.serialize()?;

    self.socket.write(&self.send_buffer.data()).map(|sz| {
      trace!("wrote {} bytes", sz);
      self.send_buffer.consume(sz);
    }).map_err(|e| ErrorKind::IOError(e).into())
  }

  fn read_from_stream(&mut self) -> Result<(), Error> {
    match self.connection.status().state() {
      ConnectionState::Closed => Ok(()),
      ConnectionState::Error  => Err(ErrorKind::InvalidConnectionState(ConnectionState::Error).into()),
      _                       => self.socket.read(&mut self.receive_buffer.space()).map(|sz| {
        trace!("read {} bytes", sz);
        self.receive_buffer.fill(sz);
      }).map_err(|e| ErrorKind::IOError(e).into()),
    }
  }

  fn serialize(&mut self) -> Result<(), Error> {
    if let Some((send_id, next_msg)) = self.connection.next_frame() {
      trace!("will write to buffer: {:?}", next_msg);
      match gen_frame(self.send_buffer.space(), &next_msg).map(|tup| tup.0) {
        Ok(sz) => {
          self.send_buffer.fill(sz);
          self.connection.mark_sent(send_id);
          Ok(())
        },
        Err(e) => {
          match e {
            GenError::BufferTooSmall(_) => {
              // Requeue msg
              self.connection.requeue_frame(send_id, next_msg)?;
              self.send_buffer.shift();
              Ok(())
            },
            GenError::InvalidOffset | GenError::CustomError(_) | GenError::NotYetImplemented => {
              error!("error generating frame: {:?}", e);
              self.connection.set_error()?;
              Err(ErrorKind::SerialisationError(e).into())
            }
          }
        }
      }
    } else {
      self.has_data = false;
      Ok(())
    }
  }

  fn parse(&mut self) -> Result<(), Error> {
    match parse_frame(self.receive_buffer.data()) {
      Ok((i, f)) => {
        let consumed = self.receive_buffer.data().offset(i);
        self.receive_buffer.consume(consumed);

        if let Err(e) = self.connection.handle_frame(f) {
          self.connection.set_error()?;
          Err(e)
        } else {
          Ok(())
        }
      },
      Err(e) => {
        if e.is_incomplete() {
          self.receive_buffer.shift();
          Ok(())
        } else {
          error!("parse error: {:?}", e);
          self.connection.set_error()?;
          Err(ErrorKind::ParsingError(format!("{:?}", e)).into())
        }
      }
    }
  }
}
<commit_msg>io_loop: fix condition for CONTINUE<commit_after>use amq_protocol::frame::{GenError, Offset, gen_frame, parse_frame};
use log::{error, trace};
use mio::{Evented, Events, Poll, PollOpt, Ready, Registration, SetReadiness, Token};
use parking_lot::Mutex;

use std::{
  io::{self, Read, Write},
  sync::{
    Arc,
    atomic::{AtomicBool, Ordering},
  },
  thread::{self, Builder as ThreadBuilder, JoinHandle},
  time::{Duration, Instant},
};

use crate::{
  buffer::Buffer,
  connection::Connection,
  connection_status::ConnectionState,
  error::{Error, ErrorKind},
};

const SOCKET:   Token = Token(1);
const DATA:     Token = Token(2);
const CONTINUE: Token = Token(3);

const FRAMES_STORAGE: usize = 32;

#[derive(Clone, Debug)]
pub(crate) struct IoLoopHandle {
  handle: Arc<Mutex<Option<JoinHandle<Result<(), Error>>>>>,
}

impl Default for IoLoopHandle {
  fn default() -> Self {
    Self { handle: Arc::new(Mutex::new(None)) }
  }
}

impl IoLoopHandle {
  pub(crate) fn register(&self, handle: JoinHandle<Result<(), Error>>) {
    *self.handle.lock() = Some(handle);
  }

  pub(crate) fn wait(&self) -> Result<(), Error> {
    if let Some(handle) = self.handle.lock().take() {
      handle.join().expect("io loop")?
    }
    Ok(())
  }
}

#[derive(Debug, PartialEq)]
enum Status {
  Initial,
  Setup,
  Stop,
}

pub struct IoLoop<T> {
  connection:     Connection,
  socket:         T,
  status:         Status,
  poll:           Poll,
  registration:   Registration,
  set_readiness:  SetReadiness,
  hb_handle:      Option<JoinHandle<()>>,
  frame_size:     usize,
  receive_buffer: Buffer,
  send_buffer:    Buffer,
  can_write:      bool,
  can_read:       bool,
  has_data:       bool,
  send_heartbeat: Arc<AtomicBool>,
  poll_timeout:   Option<Duration>,
}

impl<T: Evented + Read + Write + Send + 'static> IoLoop<T> {
  pub(crate) fn new(connection: Connection, socket: T) -> Result<Self, Error> {
    let frame_size = std::cmp::max(8192, connection.configuration().frame_max() as usize);
    let (registration, set_readiness) = Registration::new2();
    let inner = Self {
      connection,
      socket,
      status:         Status::Initial,
      poll:           Poll::new().map_err(ErrorKind::IOError)?,
      registration,
      set_readiness,
      hb_handle:      None,
      frame_size,
      receive_buffer: Buffer::with_capacity(FRAMES_STORAGE * frame_size),
      send_buffer:    Buffer::with_capacity(FRAMES_STORAGE * frame_size),
      can_write:      false,
      can_read:       false,
      has_data:       false,
      send_heartbeat: Arc::new(AtomicBool::new(false)),
      poll_timeout:   None,
    };
    inner.poll.register(&inner.socket, SOCKET, Ready::all(), PollOpt::edge()).map_err(ErrorKind::IOError)?;
    inner.poll.register(&inner.connection, DATA, Ready::readable(), PollOpt::edge()).map_err(ErrorKind::IOError)?;
    inner.poll.register(&inner.registration, CONTINUE, Ready::readable(), PollOpt::edge()).map_err(ErrorKind::IOError)?;
    Ok(inner)
  }

  fn start_heartbeat(&mut self, interval: Duration) -> Result<(), Error> {
    let connection    = self.connection.clone();
    let send_hartbeat = self.send_heartbeat.clone();
    let hb_handle = ThreadBuilder::new().name("heartbeat".to_owned()).spawn(move || {
      while connection.status().connected() {
        let start         = Instant::now();
        let mut remaining = interval;

        loop {
          thread::park_timeout(remaining);
          let elapsed = start.elapsed();
          if elapsed >= remaining {
            break
          }
          remaining -= interval - elapsed;
        }

        send_hartbeat.store(true, Ordering::Relaxed);
      }
    }).map_err(ErrorKind::IOError)?;
    self.hb_handle = Some(hb_handle);
    Ok(())
  }

  fn heartbeat(&mut self) -> Result<(), Error> {
    trace!("send heartbeat");
    self.connection.send_heartbeat()?;
    self.send_heartbeat.store(false, Ordering::Relaxed);
    Ok(())
  }

  fn ensure_setup(&mut self) -> Result<(), Error> {
    if self.status != Status::Setup && self.connection.status().connected() {
      let frame_max = self.connection.configuration().frame_max() as usize;
      self.frame_size = std::cmp::max(self.frame_size, frame_max);
      self.receive_buffer.grow(FRAMES_STORAGE * self.frame_size);
      self.send_buffer.grow(FRAMES_STORAGE * self.frame_size);
      let heartbeat = self.connection.configuration().heartbeat();
      if heartbeat != 0 {
        trace!("io_loop: start heartbeat");
        let heartbeat = Duration::from_secs(heartbeat as u64);
        self.start_heartbeat(heartbeat)?;
        self.poll_timeout = Some(heartbeat);
        trace!("io_loop: heartbeat started");
      }
      self.status = Status::Setup;
    }
    Ok(())
  }

  fn wants_to_write(&self) -> bool {
    self.can_write && self.has_data
  }

  fn wants_to_read(&self) -> bool {
    self.can_read
  }

  fn should_continue(&self) -> bool {
    let connection_status = self.connection.status();
    (self.status == Status::Initial || connection_status.connected() || connection_status.closing()) && self.status != Status::Stop && !connection_status.errored()
  }

  pub fn run(mut self) -> Result<(), Error> {
    self.connection.clone().set_io_loop(ThreadBuilder::new().name("io_loop".to_owned()).spawn(move || {
      let mut events = Events::with_capacity(1024);
      while self.should_continue() {
        self.do_run(&mut events)?;
      }
      if let Some(hb_handle) = self.hb_handle.take() {
        hb_handle.thread().unpark();
        hb_handle.join().expect("heartbeat loop failed");
      }
      Ok(())
    }).map_err(ErrorKind::IOError)?);
    Ok(())
  }

  fn do_run(&mut self, events: &mut Events) -> Result<(), Error> {
    // First, update our internal state
    trace!("io_loop run");
    self.ensure_setup()?;
    trace!("io_loop poll");
    self.poll.poll(events, self.poll_timeout).map_err(ErrorKind::IOError)?;
    trace!("io_loop poll done");
    for event in events.iter() {
      match event.token() {
        SOCKET    => {
          if event.readiness().is_readable() {
            self.can_read = true;
          }
          if event.readiness().is_writable() {
            self.can_write = true;
          }
        },
        DATA      => self.has_data = true,
        _         => {},
      }
    }

    // Then, actually run an iteration of the event loop
    trace!("io_loop do_run; can_read={}, can_write={}, has_data={}", self.can_read, self.can_write, self.has_data);
    loop {
      if self.send_heartbeat.load(Ordering::Relaxed) {
        self.heartbeat()?;
      }
      if self.wants_to_write() && !self.connection.status().blocked() {
        if let Err(e) = self.write_to_stream() {
          match e.kind() {
            ErrorKind::IOError(e) if e.kind() == io::ErrorKind::WouldBlock => self.can_write = false,
            _ => {
              error!("error writing: {:?}", e);
              if let ConnectionState::SentProtocolHeader(wait_handle, ..) = self.connection.status().state() {
                wait_handle.error(ErrorKind::ConnectionRefused.into());
                self.status = Status::Stop;
              }
              self.connection.set_error()?;
              return Err(e);
            }
          }
        }
        self.send_buffer.shift_unless_available(self.frame_size);
      }
      if self.connection.status().closed() {
        self.status = Status::Stop;
      }
      if self.should_continue() && self.wants_to_read() {
        if let Err(e) = self.read_from_stream() {
          match e.kind() {
            ErrorKind::IOError(e) if e.kind() == io::ErrorKind::WouldBlock => self.can_read = false,
            _ => {
              error!("error reading: {:?}", e);
              self.connection.set_error()?;
              return Err(e);
            }
          }
        }
        self.receive_buffer.shift_unless_available(self.frame_size);
      }
      if self.can_parse() {
        self.parse()?;
      }
      if !self.wants_to_read() || !self.wants_to_write() || self.status == Status::Stop || self.connection.status().errored() || self.connection.status().blocked() {
        if self.status != Status::Stop && !self.connection.status().blocked() && (self.wants_to_read() || self.can_parse() || self.wants_to_write()) {
          trace!("io_loop send continue; can_read={}, can_write={}, has_data={}", self.can_read, self.can_write, self.has_data);
          self.set_readiness.set_readiness(Ready::readable()).map_err(ErrorKind::IOError)?;
        }
        break;
      }
    }
    trace!("io_loop do_run done; can_read={}, can_write={}, has_data={}, status={:?}", self.can_read, self.can_write, self.has_data, self.status);
    Ok(())
  }

  fn can_parse(&self) -> bool {
    self.receive_buffer.available_data() > 0
  }

  fn write_to_stream(&mut self) -> Result<(), Error> {
    self.serialize()?;

    self.socket.write(&self.send_buffer.data()).map(|sz| {
      trace!("wrote {} bytes", sz);
      self.send_buffer.consume(sz);
    }).map_err(|e| ErrorKind::IOError(e).into())
  }

  fn read_from_stream(&mut self) -> Result<(), Error> {
    match self.connection.status().state() {
      ConnectionState::Closed => Ok(()),
      ConnectionState::Error  => Err(ErrorKind::InvalidConnectionState(ConnectionState::Error).into()),
      _                       => self.socket.read(&mut self.receive_buffer.space()).map(|sz| {
        trace!("read {} bytes", sz);
        self.receive_buffer.fill(sz);
      }).map_err(|e| ErrorKind::IOError(e).into()),
    }
  }

  fn serialize(&mut self) -> Result<(), Error> {
    if let Some((send_id, next_msg)) = self.connection.next_frame() {
      trace!("will write to buffer: {:?}", next_msg);
      match gen_frame(self.send_buffer.space(), &next_msg).map(|tup| tup.0) {
        Ok(sz) => {
          self.send_buffer.fill(sz);
          self.connection.mark_sent(send_id);
          Ok(())
        },
        Err(e) => {
          match e {
            GenError::BufferTooSmall(_) => {
              // Requeue msg
              self.connection.requeue_frame(send_id, next_msg)?;
              self.send_buffer.shift();
              Ok(())
            },
            GenError::InvalidOffset | GenError::CustomError(_) | GenError::NotYetImplemented => {
              error!("error generating frame: {:?}", e);
              self.connection.set_error()?;
              Err(ErrorKind::SerialisationError(e).into())
            }
          }
        }
      }
    } else {
      self.has_data = false;
      Ok(())
    }
  }

  fn parse(&mut self) -> Result<(), Error> {
    match parse_frame(self.receive_buffer.data()) {
      Ok((i, f)) => {
        let consumed = self.receive_buffer.data().offset(i);
        self.receive_buffer.consume(consumed);

        if let Err(e) = self.connection.handle_frame(f) {
          self.connection.set_error()?;
          Err(e)
        } else {
          Ok(())
        }
      },
      Err(e) => {
        if e.is_incomplete() {
          self.receive_buffer.shift();
          Ok(())
        } else {
          error!("parse error: {:?}", e);
          self.connection.set_error()?;
          Err(ErrorKind::ParsingError(format!("{:?}", e)).into())
        }
      }
    }
  }
}
<|endoftext|>


<commit_before>//! IPC for way-cooler

use std::thread;
use std::env;
use std::path::Path;
use std::fs;

use unix_socket::UnixListener;

mod channel;

/// Versions are incremented.
pub const VERSION: u64 = 0u64; // Increment to 1 on release.

/// Very much not cross-platform!
/// Submit an issue when Wayland is ported to Windoze.
pub const TEMP_FOLDER: &'static str = "/tmp/way-cooler";
/// Socket over which synchronous communication is made with clients.
pub const COMMAND_SOCKET: &'static str = "command";
/// Socket over which events are sent to clients.
pub const EVENT_SOCKET: &'static str = "event";

/// We need random folder names to place sockets in, but they don't need
/// to be _that_ random.
pub fn unique_ish_id() -> u32 {
    use std::hash::{Hash, Hasher, SipHasher};
    use std::time::Instant;

    // If you shift a u64 hash right by this you get a "checksum",
    // a number which retains some of the entropy of the hash but
    // is small enough to fit a more comfortable file name.
    const MAGIC_SHIFT_NUMBER: u64 = 0b110000;

    // Instant doesn't implement hash, and it's supposed to be an opaque
    // struct, but it does implement debug...
    let now = Instant::now();
    let mut hasher = SipHasher::new();
    format!("{:?}", now).hash(&mut hasher);
    hasher.finish();
}

/// Initialize the Lua server.
pub fn init() {
    trace!("Initializing way-cooler IPC...");
    let id = unique_ish_id();
    info!("Starting IPC with unique ID {}", id);

    let server_socket_path = Path::new(SERVER_SOCKET_PATH_NAME);
    let event_socket_path  = Path::new(EVENT_SOCKET_PATH_NAME);
    // Ensure /tmp folder exists - should we do this elsewhere?
    // What else are we going to put in /tmp/way-cooler?
    fs::DirBuilder::new().create("/tmp/way-cooler").ok();
    // Remove the socket if it already exists
    fs::remove_file(server_socket_path).ok();
    fs::remove_file(event_socket_path).ok();

    let server_socket = UnixListener::bind(server_socket_path)
        .expect("Unable to open server socket!");

    let event_socket = UnixListener::bind(event_socket_path)
        .expect("Unable to open event socket!");

    debug!("IPC initialized, now listening for clients.");

    let _server_handle = thread::Builder::new()
        .name("Server socket listener".to_string())
        .spawn(move || { server_thread(server_socket) });

    let _event_handle = thread::Builder::new()
        .name("Event socket listener".to_string())
        .spawn(move || { event_thread(event_socket) });

    trace!("IPC initialized.");
}

fn server_thread(socket: UnixListener) {
    for stream in socket.incoming() {
        trace!("Sever: new connection: {:?}", stream);
        match stream {
            Ok(stream) => {
                info!("Server: connected to {:?}", stream);
                let _handle = thread::Builder::new()
                    .name("IPC server helper".to_string())
                    .spawn(move || channel::handle_command(stream));
            },
            Err(err) => {
                info!("Error receiving a stream: {}", err);
            }
        }
    }
}

fn event_thread(socket: UnixListener) {
    for stream in socket.incoming() {
        trace!("Event: new connection: {:?}", stream);
        match stream {
            Ok(stream) => {
                info!("Event: connected to {:?}", stream);
                let _handle = thread::Builder::new()
                    .name("IPC evemt helper".to_string())
                    .spawn(move || channel::handle_event(stream));
            },
            Err(err) => {
                info!("Error receiving a stream: {}", err);
            }
        }
    }
}
<commit_msg>Store sockets in unique tempfile per instance<commit_after>//! IPC for way-cooler

use std::thread;
use std::env;
use std::path::PathBuf;
use std::fs;

use unix_socket::UnixListener;

mod channel;

/// Versions are incremented.
pub const VERSION: u64 = 0u64; // Increment to 1 on release.

/// Very much not cross-platform!
/// Submit an issue when Wayland is ported to Windoze.
pub const TEMP_FOLDER: &'static str = "/tmp/way-cooler/";
/// Socket over which synchronous communication is made with clients.
pub const COMMAND_SOCKET: &'static str = "command";
/// Socket over which events are sent to clients.
pub const EVENT_SOCKET: &'static str = "event";
/// Folder in which sockets are created
pub const PATH_VAR: &'static str = "WAY_COOLER_TEMPFOLDER";
/// We need random folder names to place sockets in, but they don't need
/// to be _that_ random.
pub fn unique_ish_id() -> u32 {
    use std::hash::{Hash, Hasher, SipHasher};
    use std::time::Instant;

    // If you shift a u64 hash right by this you get a "checksum",
    // a number which retains some of the entropy of the hash but
    // is small enough to fit a more comfortable file name.
    const MAGIC_SHIFT_NUMBER: u64 = 0b110000;

    // Instant doesn't implement hash, and it's supposed to be an opaque
    // struct, but it does implement debug...
    let now = Instant::now();
    let mut hasher = SipHasher::new();
    format!("{:?}", now).hash(&mut hasher);
    (hasher.finish() << MAGIC_SHIFT_NUMBER) as u32
}

/// Initialize the Lua server.
pub fn init() {
    trace!("Initializing way-cooler IPC...");
    let id = unique_ish_id();
    info!("Starting IPC with unique ID {}", id);

    let mut path = PathBuf::from(TEMP_FOLDER);
    path.push(id.to_string());

    env::set_var(PATH_VAR, path.clone());

    if let Err(ioerr) = fs::create_dir_all(path.clone()) {
        // How can we handle not having a socket?
        // In the future, we could log and continue.
        // We could have a config option to not create/create-if-possible
        error!("Unable to create temp folder: {:?}", ioerr);
        return;
    }
    else {
        let command_socket = UnixListener::bind(path.join(COMMAND_SOCKET))
            .expect("Unable to open command socket!");

        let event_socket = UnixListener::bind(path.join(EVENT_SOCKET))
            .expect("Unable to open event socket!");

        debug!("IPC initialized, now listening for clients.");

        let _server_handle = thread::Builder::new()
            .name("Command socket listener".to_string())
            .spawn(move || { command_thread(command_socket) });

        let _event_handle = thread::Builder::new()
            .name("Event socket listener".to_string())
            .spawn(move || { event_thread(event_socket) });

        trace!("IPC initialized.");
    }
}

fn command_thread(socket: UnixListener) {
    for stream in socket.incoming() {
        trace!("Sever: new connection: {:?}", stream);
        match stream {
            Ok(stream) => {
                info!("Command: connected to {:?}", stream);
                let _handle = thread::Builder::new()
                    .name("IPC server helper".to_string())
                    .spawn(move || channel::handle_command(stream));
            },
            Err(err) => {
                info!("Error receiving a stream: {}", err);
            }
        }
    }
}

fn event_thread(socket: UnixListener) {
    for stream in socket.incoming() {
        trace!("Event: new connection: {:?}", stream);
        match stream {
            Ok(stream) => {
                info!("Event: connected to {:?}", stream);
                let _handle = thread::Builder::new()
                    .name("IPC evemt helper".to_string())
                    .spawn(move || channel::handle_event(stream));
            },
            Err(err) => {
                info!("Error receiving a stream: {}", err);
            }
        }
    }
}
<|endoftext|>


<commit_before>export rustrt;

native "rust" mod rustrt {
    fn rust_ptr_eq[T](@T a, @T b) -> int;
}

fn ptr_eq[T](@T a, @T b) -> bool { ret rustrt::rust_ptr_eq[T](a, b) != 0; }

<commit_msg>stdlib: export ptr_eq from box, but not rustrt<commit_after>export ptr_eq;

native "rust" mod rustrt {
    fn rust_ptr_eq[T](@T a, @T b) -> int;
}

fn ptr_eq[T](@T a, @T b) -> bool { ret rustrt::rust_ptr_eq[T](a, b) != 0; }

<|endoftext|>


<commit_before>/**
 * At the moment, this is a partial hashmap implementation, not yet fit for
 * use, but useful as a stress test for rustboot.
 */

import std._int;
import std.sys;
import std.util;
import std._vec;

type hashfn[K] = fn(&K) -> uint;
type eqfn[K] = fn(&K, &K) -> bool;

type hashmap[K, V] = obj {
                     fn size() -> uint;
                     fn insert(&K key, &V val) -> bool;
                     fn contains_key(&K key) -> bool;
                     fn get(&K key) -> V;
                     fn find(&K key) -> util.option[V];
                     fn remove(&K key) -> util.option[V];
                     fn rehash();
};

fn mk_hashmap[K, V](&hashfn[K] hasher, &eqfn[K] eqer) -> hashmap[K, V] {

    let uint initial_capacity = 32u; // 2^5
    let util.rational load_factor = rec(num=3, den=4);

    tag bucket[K, V] {
        nil;
        deleted;
        some(K, V);
    }

    fn make_buckets[K, V](uint nbkts) -> vec[mutable bucket[K, V]] {
        ret _vec.init_elt[mutable bucket[K, V]](nil[K, V], nbkts);
    }

    // Derive two hash functions from the one given by taking the upper
    // half and lower half of the uint bits.  Our bucket probing
    // sequence is then defined by
    //
    //   hash(key, i) := hashl(key) + i * hashr(key)   for i = 0, 1, 2, ...
    //
    // Tearing the hash function apart this way is kosher in practice
    // as, assuming 32-bit uints, the table would have to be at 2^32
    // buckets before the resulting pair of hash functions no longer
    // probes all buckets for a fixed key.  Note that hashr is made to
    // output odd numbers (hence coprime to the number of nbkts, which
    // is always a power of 2), so that all buckets are probed for a
    // fixed key.

    fn hashl[K](&hashfn[K] hasher, uint nbkts, &K key) -> uint {
        ret (hasher(key) >>> (sys.rustrt.size_of[uint]() * 8u / 2u));
    }

    fn hashr[K](&hashfn[K] hasher, uint nbkts, &K key) -> uint {
        ret ((((~ 0u) >>> (sys.rustrt.size_of[uint]() * 8u / 2u))
              & hasher(key)) * 2u + 1u);
    }

    fn hash[K](&hashfn[K] hasher, uint nbkts, &K key, uint i) -> uint {
        ret (hashl[K](hasher, nbkts, key)
             + i * hashr[K](hasher, nbkts, key)) % nbkts;
    }

    /**
     * We attempt to never call this with a full table.  If we do, it
     * will fail.
     */
    fn insert_common[K, V](&hashfn[K] hasher,
                           &eqfn[K] eqer,
                           vec[mutable bucket[K, V]] bkts,
                           uint nbkts,
                           &K key,
                           &V val)
        -> bool
        {
            let uint i = 0u;
            while (i < nbkts) {
                let uint j = hash[K](hasher, nbkts, key, i);
                alt (bkts.(j)) {
                    case (some[K, V](?k, _)) {
                        if (eqer(key, k)) {
                            bkts.(j) = some[K, V](k, val);
                            ret false;
                        }
                        i += 1u;
                    }
                    case (_) {
                        bkts.(j) = some[K, V](key, val);
                        ret true;
                    }
                }
            }
            fail; // full table
        }

    fn find_common[K, V](&hashfn[K] hasher,
                         &eqfn[K] eqer,
                         vec[mutable bucket[K, V]] bkts,
                         uint nbkts,
                         &K key)
        -> util.option[V]
        {
            let uint i = 0u;
            while (i < nbkts) {
                let uint j = (hash[K](hasher, nbkts, key, i));
                alt (bkts.(j)) {
                    case (some[K, V](?k, ?v)) {
                        if (eqer(key, k)) {
                            ret util.some[V](v);
                        }
                    }
                    case (nil[K, V]) {
                        ret util.none[V];
                    }
                    case (deleted[K, V]) { }
                }
                i += 1u;
            }
            ret util.none[V];
        }

    fn rehash[K, V](&hashfn[K] hasher,
                    &eqfn[K] eqer,
                    vec[mutable bucket[K, V]] oldbkts, uint noldbkts,
                    vec[mutable bucket[K, V]] newbkts, uint nnewbkts)
        {
            for (bucket[K, V] b in oldbkts) {
                alt (b) {
                    case (some[K, V](?k, ?v)) {
                        insert_common[K, V](hasher, eqer, newbkts,
                                            nnewbkts, k, v);
                    }
                    case (_) { }
                }
            }
        }

    obj hashmap[K, V](hashfn[K] hasher,
                      eqfn[K] eqer,
                      mutable vec[mutable bucket[K, V]] bkts,
                      mutable uint nbkts,
                      mutable uint nelts,
                      util.rational lf)
        {
            fn size() -> uint { ret nelts; }

            fn insert(&K key, &V val) -> bool {
                let util.rational load = rec(num=(nelts + 1u) as int,
                                             den=nbkts as int);
                if (!util.rational_leq(load, lf)) {
                    let uint nnewbkts = _uint.next_power_of_two(nbkts + 1u);
                    let vec[mutable bucket[K, V]] newbkts =
                        make_buckets[K, V](nnewbkts);
                    rehash[K, V](hasher, eqer, bkts, nbkts,
                                 newbkts, nnewbkts);
                    bkts = newbkts;
                    nbkts = nnewbkts;
                }

                if (insert_common[K, V](hasher, eqer, bkts,
                                        nbkts, key, val)) {
                    nelts += 1u;
                    ret true;
                }
                ret false;
            }

            fn contains_key(&K key) -> bool {
                alt (find_common[K, V](hasher, eqer, bkts, nbkts, key)) {
                    case (util.some[V](_)) { ret true; }
                    case (_) { ret false; }
                }
            }

            fn get(&K key) -> V {
                alt (find_common[K, V](hasher, eqer, bkts, nbkts, key)) {
                    case (util.some[V](?val)) { ret val; }
                    case (_) { fail; }
                }
            }

            fn find(&K key) -> util.option[V] {
                be find_common[K, V](hasher, eqer, bkts, nbkts, key);
            }

            fn remove(&K key) -> util.option[V] {
                let uint i = 0u;
                while (i < nbkts) {
                    let uint j = (hash[K](hasher, nbkts, key, i));
                    alt (bkts.(j)) {
                        case (some[K, V](?k, ?v)) {
                            if (eqer(key, k)) {
                                bkts.(j) = deleted[K, V];
                                nelts -= 1u;
                                ret util.some[V](v);
                            }
                        }
                        case (deleted[K, V]) { }
                        case (nil[K, V]) {
                            ret util.none[V];
                        }
                    }
                    i += 1u;
                }
                ret util.none[V];
            }

            fn rehash() {
                let vec[mutable bucket[K, V]] newbkts =
                    make_buckets[K, V](nbkts);
                rehash[K, V](hasher, eqer, bkts, nbkts, newbkts, nbkts);
                bkts = newbkts;
            }
        }

    let vec[mutable bucket[K, V]] bkts =
        make_buckets[K, V](initial_capacity);

    ret hashmap[K, V](hasher, eqer, bkts, initial_capacity, 0u, load_factor);
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>Add 'items' iter to hashmap.<commit_after>/**
 * At the moment, this is a partial hashmap implementation, not yet fit for
 * use, but useful as a stress test for rustboot.
 */

import std._int;
import std.sys;
import std.util;
import std._vec;

type hashfn[K] = fn(&K) -> uint;
type eqfn[K] = fn(&K, &K) -> bool;

type hashmap[K, V] = obj {
                     fn size() -> uint;
                     fn insert(&K key, &V val) -> bool;
                     fn contains_key(&K key) -> bool;
                     fn get(&K key) -> V;
                     fn find(&K key) -> util.option[V];
                     fn remove(&K key) -> util.option[V];
                     fn rehash();
                     iter items() -> tup(K,V);
};

fn mk_hashmap[K, V](&hashfn[K] hasher, &eqfn[K] eqer) -> hashmap[K, V] {

    let uint initial_capacity = 32u; // 2^5
    let util.rational load_factor = rec(num=3, den=4);

    tag bucket[K, V] {
        nil;
        deleted;
        some(K, V);
    }

    fn make_buckets[K, V](uint nbkts) -> vec[mutable bucket[K, V]] {
        ret _vec.init_elt[mutable bucket[K, V]](nil[K, V], nbkts);
    }

    // Derive two hash functions from the one given by taking the upper
    // half and lower half of the uint bits.  Our bucket probing
    // sequence is then defined by
    //
    //   hash(key, i) := hashl(key) + i * hashr(key)   for i = 0, 1, 2, ...
    //
    // Tearing the hash function apart this way is kosher in practice
    // as, assuming 32-bit uints, the table would have to be at 2^32
    // buckets before the resulting pair of hash functions no longer
    // probes all buckets for a fixed key.  Note that hashr is made to
    // output odd numbers (hence coprime to the number of nbkts, which
    // is always a power of 2), so that all buckets are probed for a
    // fixed key.

    fn hashl[K](&hashfn[K] hasher, uint nbkts, &K key) -> uint {
        ret (hasher(key) >>> (sys.rustrt.size_of[uint]() * 8u / 2u));
    }

    fn hashr[K](&hashfn[K] hasher, uint nbkts, &K key) -> uint {
        ret ((((~ 0u) >>> (sys.rustrt.size_of[uint]() * 8u / 2u))
              & hasher(key)) * 2u + 1u);
    }

    fn hash[K](&hashfn[K] hasher, uint nbkts, &K key, uint i) -> uint {
        ret (hashl[K](hasher, nbkts, key)
             + i * hashr[K](hasher, nbkts, key)) % nbkts;
    }

    /**
     * We attempt to never call this with a full table.  If we do, it
     * will fail.
     */
    fn insert_common[K, V](&hashfn[K] hasher,
                           &eqfn[K] eqer,
                           vec[mutable bucket[K, V]] bkts,
                           uint nbkts,
                           &K key,
                           &V val)
        -> bool
        {
            let uint i = 0u;
            while (i < nbkts) {
                let uint j = hash[K](hasher, nbkts, key, i);
                alt (bkts.(j)) {
                    case (some[K, V](?k, _)) {
                        if (eqer(key, k)) {
                            bkts.(j) = some[K, V](k, val);
                            ret false;
                        }
                        i += 1u;
                    }
                    case (_) {
                        bkts.(j) = some[K, V](key, val);
                        ret true;
                    }
                }
            }
            fail; // full table
        }

    fn find_common[K, V](&hashfn[K] hasher,
                         &eqfn[K] eqer,
                         vec[mutable bucket[K, V]] bkts,
                         uint nbkts,
                         &K key)
        -> util.option[V]
        {
            let uint i = 0u;
            while (i < nbkts) {
                let uint j = (hash[K](hasher, nbkts, key, i));
                alt (bkts.(j)) {
                    case (some[K, V](?k, ?v)) {
                        if (eqer(key, k)) {
                            ret util.some[V](v);
                        }
                    }
                    case (nil[K, V]) {
                        ret util.none[V];
                    }
                    case (deleted[K, V]) { }
                }
                i += 1u;
            }
            ret util.none[V];
        }

    fn rehash[K, V](&hashfn[K] hasher,
                    &eqfn[K] eqer,
                    vec[mutable bucket[K, V]] oldbkts, uint noldbkts,
                    vec[mutable bucket[K, V]] newbkts, uint nnewbkts)
        {
            for (bucket[K, V] b in oldbkts) {
                alt (b) {
                    case (some[K, V](?k, ?v)) {
                        insert_common[K, V](hasher, eqer, newbkts,
                                            nnewbkts, k, v);
                    }
                    case (_) { }
                }
            }
        }

    obj hashmap[K, V](hashfn[K] hasher,
                      eqfn[K] eqer,
                      mutable vec[mutable bucket[K, V]] bkts,
                      mutable uint nbkts,
                      mutable uint nelts,
                      util.rational lf)
        {
            fn size() -> uint { ret nelts; }

            fn insert(&K key, &V val) -> bool {
                let util.rational load = rec(num=(nelts + 1u) as int,
                                             den=nbkts as int);
                if (!util.rational_leq(load, lf)) {
                    let uint nnewbkts = _uint.next_power_of_two(nbkts + 1u);
                    let vec[mutable bucket[K, V]] newbkts =
                        make_buckets[K, V](nnewbkts);
                    rehash[K, V](hasher, eqer, bkts, nbkts,
                                 newbkts, nnewbkts);
                    bkts = newbkts;
                    nbkts = nnewbkts;
                }

                if (insert_common[K, V](hasher, eqer, bkts,
                                        nbkts, key, val)) {
                    nelts += 1u;
                    ret true;
                }
                ret false;
            }

            fn contains_key(&K key) -> bool {
                alt (find_common[K, V](hasher, eqer, bkts, nbkts, key)) {
                    case (util.some[V](_)) { ret true; }
                    case (_) { ret false; }
                }
            }

            fn get(&K key) -> V {
                alt (find_common[K, V](hasher, eqer, bkts, nbkts, key)) {
                    case (util.some[V](?val)) { ret val; }
                    case (_) { fail; }
                }
            }

            fn find(&K key) -> util.option[V] {
                be find_common[K, V](hasher, eqer, bkts, nbkts, key);
            }

            fn remove(&K key) -> util.option[V] {
                let uint i = 0u;
                while (i < nbkts) {
                    let uint j = (hash[K](hasher, nbkts, key, i));
                    alt (bkts.(j)) {
                        case (some[K, V](?k, ?v)) {
                            if (eqer(key, k)) {
                                bkts.(j) = deleted[K, V];
                                nelts -= 1u;
                                ret util.some[V](v);
                            }
                        }
                        case (deleted[K, V]) { }
                        case (nil[K, V]) {
                            ret util.none[V];
                        }
                    }
                    i += 1u;
                }
                ret util.none[V];
            }

            fn rehash() {
                let vec[mutable bucket[K, V]] newbkts =
                    make_buckets[K, V](nbkts);
                rehash[K, V](hasher, eqer, bkts, nbkts, newbkts, nbkts);
                bkts = newbkts;
            }

            iter items() -> tup(K,V) {
                for (bucket[K,V] b in bkts) {
                    alt (b) {
                        case(some[K,V](?k,?v)) {
                            put tup(k,v);
                        }
                        case (_) { }
                    }
                }
            }
        }

    let vec[mutable bucket[K, V]] bkts =
        make_buckets[K, V](initial_capacity);

    ret hashmap[K, V](hasher, eqer, bkts, initial_capacity, 0u, load_factor);
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>