<commit_before>//! Create window.

// External crates.
use gfx;
use collections::Deque;
use collections::ringbuf::RingBuf;
use glfw;
use glfw::Context;
use gl;
use piston::input;
use piston::input::{
    keyboard,
    mouse,
};
use piston::{
    Window,
    WindowSettings,
};
use piston::shader_version::opengl::OpenGL;

/// Contains stuff for game window.
pub struct WindowGLFW {
    /// The window.
    pub window: glfw::Window,
    /// Receives events from window.
    events: Receiver<(f64, glfw::WindowEvent)>,
    /// GLFW context.
    pub glfw: glfw::Glfw,
    /// Game window settings.
    settings: WindowSettings,
    event_queue: RingBuf<input::InputEvent>,
    // Used to compute relative mouse movement.
    last_mouse_pos: Option<(f64, f64)>,
}

impl WindowGLFW {
    /// Create a new game window from an existing GLFW window.
    pub fn from_pieces(win: glfw::Window, glfw: glfw::Glfw,
                       events: Receiver<(f64, glfw::WindowEvent)>,
                       exit_on_esc: bool) -> WindowGLFW {
        win.set_all_polling(true);
        win.make_current();

        let (w, h) = win.get_framebuffer_size();
        let fullscreen = win.with_window_mode(|m| match m { glfw::Windowed => true, _ => false });

        WindowGLFW {
            window: win,
            events: events,
            glfw: glfw,
            settings: WindowSettings {
                title: "<unknown window title, created with from_pieces>".to_string(),
                size: [w as u32, h as u32],
                samples: 0, //unknown
                fullscreen: fullscreen,
                exit_on_esc: exit_on_esc,
            },
            event_queue: RingBuf::new(),
            last_mouse_pos: None,
        }
    }

    /// Creates a new game window for GLFW.
    pub fn new(opengl: OpenGL, settings: WindowSettings) -> WindowGLFW {
        use glfw::Context;

        // Initialize GLFW.
        let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

        let (major, minor) = opengl.get_major_minor();

        // Make sure we have the right GL version.
        glfw.window_hint(glfw::ContextVersion(major as u32, minor as u32));
        glfw.window_hint(glfw::OpenglForwardCompat(true));
        glfw.window_hint(glfw::OpenglProfile(glfw::OpenGlCoreProfile));
        glfw.window_hint(glfw::Samples(settings.samples as u32));

        // Create GLFW window.
        let (window, events) = glfw.create_window(
            settings.size[0],
            settings.size[1],
            settings.title.as_slice(), glfw::Windowed
        ).expect("Failed to create GLFW window.");
        window.set_all_polling(true);
        window.make_current();

        // Load the OpenGL function pointers
        gl::load_with(|s| glfw.get_proc_address(s));

        WindowGLFW {
            window: window,
            events: events,
            glfw: glfw,
            settings: settings,
            event_queue: RingBuf::new(),
            last_mouse_pos: None,
        }
    }

    fn flush_messages(&mut self) {
        if self.event_queue.len() != 0 {
            return;
        }

        self.glfw.poll_events();
        for (_, event) in glfw::flush_messages(&self.events) {
            match event {
                glfw::KeyEvent(glfw::KeyEscape, _, glfw::Press, _)
                if self.settings.exit_on_esc => {
                    self.window.set_should_close(true);
                }
                glfw::CharEvent(ch) => {
                    self.event_queue.push(input::Text(ch.to_string()));
                }
                glfw::KeyEvent(key, _, glfw::Press, _) => {
                    self.event_queue.push(
                        input::Press(input::Keyboard(glfw_map_key(key)))
                    );
                }
                glfw::KeyEvent(key, _, glfw::Release, _) => {
                    self.event_queue.push(
                        input::Release(input::Keyboard(glfw_map_key(key)))
                    );
                }
                glfw::MouseButtonEvent(button, glfw::Press, _) => {
                    self.event_queue.push(
                        input::Press(input::Mouse(glfw_map_mouse(button)))
                    );
                }
                glfw::MouseButtonEvent(button, glfw::Release, _) => {
                    self.event_queue.push(
                        input::Release(input::Mouse(glfw_map_mouse(button)))
                    );
                }
                glfw::CursorPosEvent(x, y) => {
                    self.event_queue.push(input::Move(input::MouseCursor(x, y)));
                    match self.last_mouse_pos {
                        Some((lx, ly)) => {
                            self.event_queue.push(
                                input::Move(input::MouseRelative(x - lx, y - ly))
                            )
                        }
                        None => {}
                    };
                    self.last_mouse_pos = Some((x, y));
                }
                glfw::ScrollEvent(x, y) => {
                    self.event_queue.push(input::Move(input::MouseScroll(x, y)));
                }
                glfw::SizeEvent(w, h) => {
                    self.event_queue.push(input::Resize(w as u32, h as u32));
                }
                _ => {}
            }
        }
    }

    /// Creates a gfx device and frame.
    pub fn gfx(&self) -> (gfx::GlDevice, gfx::Frame) {
        let device = gfx::GlDevice::new(|s|
            self.glfw.get_proc_address(s)
        );
        let (w, h) = self.get_size();
        let frame = gfx::Frame::new(w as u16, h as u16);
        (device, frame)
    }
}

impl Window for WindowGLFW {
    fn get_settings<'a>(&'a self) -> &'a WindowSettings {
        &self.settings
    }

    fn get_draw_size(&self) -> (u32, u32) {
        let (w, h) = self.window.get_framebuffer_size();
        (w as u32, h as u32)
    }

    fn should_close(&self) -> bool {
        self.window.should_close()
    }

    fn close(&mut self) {
        self.window.set_should_close(true);
    }

    fn swap_buffers(&self) {
        use glfw::Context;

        self.window.swap_buffers();
    }

    fn capture_cursor(&mut self, enabled: bool) {
        if enabled {
            self.window.set_cursor_mode(glfw::CursorDisabled)
        } else {
            self.window.set_cursor_mode(glfw::CursorNormal);
            self.last_mouse_pos = None;
        }
    }

    fn poll_event(&mut self) -> Option<input::InputEvent> {
        self.flush_messages();

        if self.event_queue.len() != 0 {
            self.event_queue.pop_front()
        } else {
            None
        }
    }
}

fn glfw_map_key(keycode: glfw::Key) -> keyboard::Key {
    match keycode {
        glfw::Key0 => keyboard::D0,
        glfw::Key1 => keyboard::D1,
        glfw::Key2 => keyboard::D2,
        glfw::Key3 => keyboard::D3,
        glfw::Key4 => keyboard::D4,
        glfw::Key5 => keyboard::D5,
        glfw::Key6 => keyboard::D6,
        glfw::Key7 => keyboard::D7,
        glfw::Key8 => keyboard::D8,
        glfw::Key9 => keyboard::D9,
        glfw::KeyA => keyboard::A,
        glfw::KeyB => keyboard::B,
        glfw::KeyC => keyboard::C,
        glfw::KeyD => keyboard::D,
        glfw::KeyE => keyboard::E,
        glfw::KeyF => keyboard::F,
        glfw::KeyG => keyboard::G,
        glfw::KeyH => keyboard::H,
        glfw::KeyI => keyboard::I,
        glfw::KeyJ => keyboard::J,
        glfw::KeyK => keyboard::K,
        glfw::KeyL => keyboard::L,
        glfw::KeyM => keyboard::M,
        glfw::KeyN => keyboard::N,
        glfw::KeyO => keyboard::O,
        glfw::KeyP => keyboard::P,
        glfw::KeyQ => keyboard::Q,
        glfw::KeyR => keyboard::R,
        glfw::KeyS => keyboard::S,
        glfw::KeyT => keyboard::T,
        glfw::KeyU => keyboard::U,
        glfw::KeyV => keyboard::V,
        glfw::KeyW => keyboard::W,
        glfw::KeyX => keyboard::X,
        glfw::KeyY => keyboard::Y,
        glfw::KeyZ => keyboard::Z,
        glfw::KeyApostrophe => keyboard::Unknown,
        glfw::KeyBackslash => keyboard::Backslash,
        glfw::KeyBackspace => keyboard::Backspace,
        glfw::KeyCapsLock => keyboard::CapsLock,
        glfw::KeyDelete => keyboard::Delete,
        glfw::KeyComma => keyboard::Comma,
        glfw::KeyDown => keyboard::Down,
        glfw::KeyEnd => keyboard::End,
        glfw::KeyEnter => keyboard::Return,
        glfw::KeyEqual => keyboard::Equals,
        glfw::KeyEscape => keyboard::Escape,
        glfw::KeyF1 => keyboard::F1,
        glfw::KeyF2 => keyboard::F2,
        glfw::KeyF3 => keyboard::F3,
        glfw::KeyF4 => keyboard::F4,
        glfw::KeyF5 => keyboard::F5,
        glfw::KeyF6 => keyboard::F6,
        glfw::KeyF7 => keyboard::F7,
        glfw::KeyF8 => keyboard::F8,
        glfw::KeyF9 => keyboard::F9,
        glfw::KeyF10 => keyboard::F10,
        glfw::KeyF11 => keyboard::F11,
        glfw::KeyF12 => keyboard::F12,
        glfw::KeyF13 => keyboard::F13,
        glfw::KeyF14 => keyboard::F14,
        glfw::KeyF15 => keyboard::F15,
        glfw::KeyF16 => keyboard::F16,
        glfw::KeyF17 => keyboard::F17,
        glfw::KeyF18 => keyboard::F18,
        glfw::KeyF19 => keyboard::F19,
        glfw::KeyF20 => keyboard::F20,
        glfw::KeyF21 => keyboard::F21,
        glfw::KeyF22 => keyboard::F22,
        glfw::KeyF23 => keyboard::F23,
        glfw::KeyF24 => keyboard::F24,
        // Possibly next code.
        glfw::KeyF25 => keyboard::Unknown,
        glfw::KeyKp0 => keyboard::NumPad0,
        glfw::KeyKp1 => keyboard::NumPad1,
        glfw::KeyKp2 => keyboard::NumPad2,
        glfw::KeyKp3 => keyboard::NumPad3,
        glfw::KeyKp4 => keyboard::NumPad4,
        glfw::KeyKp5 => keyboard::NumPad5,
        glfw::KeyKp6 => keyboard::NumPad6,
        glfw::KeyKp7 => keyboard::NumPad7,
        glfw::KeyKp8 => keyboard::NumPad8,
        glfw::KeyKp9 => keyboard::NumPad9,
        glfw::KeyKpDecimal => keyboard::NumPadDecimal,
        glfw::KeyKpDivide => keyboard::NumPadDivide,
        glfw::KeyKpMultiply => keyboard::NumPadMultiply,
        glfw::KeyKpSubtract => keyboard::NumPadMinus,
        glfw::KeyKpAdd => keyboard::NumPadPlus,
        glfw::KeyKpEnter => keyboard::NumPadEnter,
        glfw::KeyKpEqual => keyboard::NumPadEquals,
        glfw::KeyLeftShift => keyboard::LShift,
        glfw::KeyLeftControl => keyboard::LCtrl,
        glfw::KeyLeftAlt => keyboard::LAlt,
        glfw::KeyLeftSuper => keyboard::LGui,
        glfw::KeyRightShift => keyboard::RShift,
        glfw::KeyRightControl => keyboard::RCtrl,
        glfw::KeyRightAlt => keyboard::RAlt,
        glfw::KeyRightSuper => keyboard::RGui,
        // Map to backslash?
        glfw::KeyGraveAccent => keyboard::Unknown,
        glfw::KeyHome => keyboard::Home,
        glfw::KeyInsert => keyboard::Insert,
        glfw::KeyLeft => keyboard::Left,
        glfw::KeyLeftBracket => keyboard::LeftBracket,
        glfw::KeyMenu => keyboard::Menu,
        glfw::KeyMinus => keyboard::Minus,
        glfw::KeyNumLock => keyboard::NumLockClear,
        glfw::KeyPageDown => keyboard::PageDown,
        glfw::KeyPageUp => keyboard::PageUp,
        glfw::KeyPause => keyboard::Pause,
        glfw::KeyPeriod => keyboard::Period,
        glfw::KeyPrintScreen => keyboard::PrintScreen,
        glfw::KeyRight => keyboard::Right,
        glfw::KeyRightBracket => keyboard::RightBracket,
        glfw::KeyScrollLock => keyboard::ScrollLock,
        glfw::KeySemicolon => keyboard::Semicolon,
        glfw::KeySlash => keyboard::Slash,
        glfw::KeySpace => keyboard::Space,
        glfw::KeyTab => keyboard::Tab,
        glfw::KeyUp => keyboard::Up,
        glfw::KeyWorld1 => keyboard::Unknown,
        glfw::KeyWorld2 => keyboard::Unknown,
        // _ => keyboard::Unknown,
    }
}

fn glfw_map_mouse(mouse_button: glfw::MouseButton) -> mouse::Button {
    match mouse_button {
        glfw::MouseButton1 => mouse::Left,
        glfw::MouseButton2 => mouse::Right,
        glfw::MouseButton3 => mouse::Middle,
        glfw::MouseButton4 => mouse::X1,
        glfw::MouseButton5 => mouse::X2,
        glfw::MouseButton6 => mouse::Button6,
        glfw::MouseButton7 => mouse::Button7,
        glfw::MouseButton8 => mouse::Button8,
    }
}
<commit_msg>Handle focus event<commit_after>//! Create window.

// External crates.
use gfx;
use collections::Deque;
use collections::ringbuf::RingBuf;
use glfw;
use glfw::Context;
use gl;
use piston::input;
use piston::input::{
    keyboard,
    mouse,
};
use piston::{
    Window,
    WindowSettings,
};
use piston::shader_version::opengl::OpenGL;

/// Contains stuff for game window.
pub struct WindowGLFW {
    /// The window.
    pub window: glfw::Window,
    /// Receives events from window.
    events: Receiver<(f64, glfw::WindowEvent)>,
    /// GLFW context.
    pub glfw: glfw::Glfw,
    /// Game window settings.
    settings: WindowSettings,
    event_queue: RingBuf<input::InputEvent>,
    // Used to compute relative mouse movement.
    last_mouse_pos: Option<(f64, f64)>,
}

impl WindowGLFW {
    /// Create a new game window from an existing GLFW window.
    pub fn from_pieces(win: glfw::Window, glfw: glfw::Glfw,
                       events: Receiver<(f64, glfw::WindowEvent)>,
                       exit_on_esc: bool) -> WindowGLFW {
        win.set_all_polling(true);
        win.make_current();

        let (w, h) = win.get_framebuffer_size();
        let fullscreen = win.with_window_mode(|m| match m { glfw::Windowed => true, _ => false });

        WindowGLFW {
            window: win,
            events: events,
            glfw: glfw,
            settings: WindowSettings {
                title: "<unknown window title, created with from_pieces>".to_string(),
                size: [w as u32, h as u32],
                samples: 0, //unknown
                fullscreen: fullscreen,
                exit_on_esc: exit_on_esc,
            },
            event_queue: RingBuf::new(),
            last_mouse_pos: None,
        }
    }

    /// Creates a new game window for GLFW.
    pub fn new(opengl: OpenGL, settings: WindowSettings) -> WindowGLFW {
        use glfw::Context;

        // Initialize GLFW.
        let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

        let (major, minor) = opengl.get_major_minor();

        // Make sure we have the right GL version.
        glfw.window_hint(glfw::ContextVersion(major as u32, minor as u32));
        glfw.window_hint(glfw::OpenglForwardCompat(true));
        glfw.window_hint(glfw::OpenglProfile(glfw::OpenGlCoreProfile));
        glfw.window_hint(glfw::Samples(settings.samples as u32));

        // Create GLFW window.
        let (window, events) = glfw.create_window(
            settings.size[0],
            settings.size[1],
            settings.title.as_slice(), glfw::Windowed
        ).expect("Failed to create GLFW window.");
        window.set_all_polling(true);
        window.make_current();

        // Load the OpenGL function pointers
        gl::load_with(|s| glfw.get_proc_address(s));

        WindowGLFW {
            window: window,
            events: events,
            glfw: glfw,
            settings: settings,
            event_queue: RingBuf::new(),
            last_mouse_pos: None,
        }
    }

    fn flush_messages(&mut self) {
        if self.event_queue.len() != 0 {
            return;
        }

        self.glfw.poll_events();
        for (_, event) in glfw::flush_messages(&self.events) {
            match event {
                glfw::KeyEvent(glfw::KeyEscape, _, glfw::Press, _)
                if self.settings.exit_on_esc => {
                    self.window.set_should_close(true);
                }
                glfw::CharEvent(ch) => {
                    self.event_queue.push(input::Text(ch.to_string()));
                }
                glfw::KeyEvent(key, _, glfw::Press, _) => {
                    self.event_queue.push(
                        input::Press(input::Keyboard(glfw_map_key(key)))
                    );
                }
                glfw::KeyEvent(key, _, glfw::Release, _) => {
                    self.event_queue.push(
                        input::Release(input::Keyboard(glfw_map_key(key)))
                    );
                }
                glfw::MouseButtonEvent(button, glfw::Press, _) => {
                    self.event_queue.push(
                        input::Press(input::Mouse(glfw_map_mouse(button)))
                    );
                }
                glfw::MouseButtonEvent(button, glfw::Release, _) => {
                    self.event_queue.push(
                        input::Release(input::Mouse(glfw_map_mouse(button)))
                    );
                }
                glfw::CursorPosEvent(x, y) => {
                    self.event_queue.push(input::Move(input::MouseCursor(x, y)));
                    match self.last_mouse_pos {
                        Some((lx, ly)) => {
                            self.event_queue.push(
                                input::Move(input::MouseRelative(x - lx, y - ly))
                            )
                        }
                        None => {}
                    };
                    self.last_mouse_pos = Some((x, y));
                }
                glfw::ScrollEvent(x, y) => {
                    self.event_queue.push(input::Move(input::MouseScroll(x, y)));
                }
                glfw::SizeEvent(w, h) => {
                    self.event_queue.push(input::Resize(w as u32, h as u32));
                }
                glfw::FocusEvent(focus) => {
                    self.event_queue.push(input::Focus(focus));
                }
                _ => {}
            }
        }
    }

    /// Creates a gfx device and frame.
    pub fn gfx(&self) -> (gfx::GlDevice, gfx::Frame) {
        let device = gfx::GlDevice::new(|s|
            self.glfw.get_proc_address(s)
        );
        let (w, h) = self.get_size();
        let frame = gfx::Frame::new(w as u16, h as u16);
        (device, frame)
    }
}

impl Window for WindowGLFW {
    fn get_settings<'a>(&'a self) -> &'a WindowSettings {
        &self.settings
    }

    fn get_draw_size(&self) -> (u32, u32) {
        let (w, h) = self.window.get_framebuffer_size();
        (w as u32, h as u32)
    }

    fn should_close(&self) -> bool {
        self.window.should_close()
    }

    fn close(&mut self) {
        self.window.set_should_close(true);
    }

    fn swap_buffers(&self) {
        use glfw::Context;

        self.window.swap_buffers();
    }

    fn capture_cursor(&mut self, enabled: bool) {
        if enabled {
            self.window.set_cursor_mode(glfw::CursorDisabled)
        } else {
            self.window.set_cursor_mode(glfw::CursorNormal);
            self.last_mouse_pos = None;
        }
    }

    fn poll_event(&mut self) -> Option<input::InputEvent> {
        self.flush_messages();

        if self.event_queue.len() != 0 {
            self.event_queue.pop_front()
        } else {
            None
        }
    }
}

fn glfw_map_key(keycode: glfw::Key) -> keyboard::Key {
    match keycode {
        glfw::Key0 => keyboard::D0,
        glfw::Key1 => keyboard::D1,
        glfw::Key2 => keyboard::D2,
        glfw::Key3 => keyboard::D3,
        glfw::Key4 => keyboard::D4,
        glfw::Key5 => keyboard::D5,
        glfw::Key6 => keyboard::D6,
        glfw::Key7 => keyboard::D7,
        glfw::Key8 => keyboard::D8,
        glfw::Key9 => keyboard::D9,
        glfw::KeyA => keyboard::A,
        glfw::KeyB => keyboard::B,
        glfw::KeyC => keyboard::C,
        glfw::KeyD => keyboard::D,
        glfw::KeyE => keyboard::E,
        glfw::KeyF => keyboard::F,
        glfw::KeyG => keyboard::G,
        glfw::KeyH => keyboard::H,
        glfw::KeyI => keyboard::I,
        glfw::KeyJ => keyboard::J,
        glfw::KeyK => keyboard::K,
        glfw::KeyL => keyboard::L,
        glfw::KeyM => keyboard::M,
        glfw::KeyN => keyboard::N,
        glfw::KeyO => keyboard::O,
        glfw::KeyP => keyboard::P,
        glfw::KeyQ => keyboard::Q,
        glfw::KeyR => keyboard::R,
        glfw::KeyS => keyboard::S,
        glfw::KeyT => keyboard::T,
        glfw::KeyU => keyboard::U,
        glfw::KeyV => keyboard::V,
        glfw::KeyW => keyboard::W,
        glfw::KeyX => keyboard::X,
        glfw::KeyY => keyboard::Y,
        glfw::KeyZ => keyboard::Z,
        glfw::KeyApostrophe => keyboard::Unknown,
        glfw::KeyBackslash => keyboard::Backslash,
        glfw::KeyBackspace => keyboard::Backspace,
        glfw::KeyCapsLock => keyboard::CapsLock,
        glfw::KeyDelete => keyboard::Delete,
        glfw::KeyComma => keyboard::Comma,
        glfw::KeyDown => keyboard::Down,
        glfw::KeyEnd => keyboard::End,
        glfw::KeyEnter => keyboard::Return,
        glfw::KeyEqual => keyboard::Equals,
        glfw::KeyEscape => keyboard::Escape,
        glfw::KeyF1 => keyboard::F1,
        glfw::KeyF2 => keyboard::F2,
        glfw::KeyF3 => keyboard::F3,
        glfw::KeyF4 => keyboard::F4,
        glfw::KeyF5 => keyboard::F5,
        glfw::KeyF6 => keyboard::F6,
        glfw::KeyF7 => keyboard::F7,
        glfw::KeyF8 => keyboard::F8,
        glfw::KeyF9 => keyboard::F9,
        glfw::KeyF10 => keyboard::F10,
        glfw::KeyF11 => keyboard::F11,
        glfw::KeyF12 => keyboard::F12,
        glfw::KeyF13 => keyboard::F13,
        glfw::KeyF14 => keyboard::F14,
        glfw::KeyF15 => keyboard::F15,
        glfw::KeyF16 => keyboard::F16,
        glfw::KeyF17 => keyboard::F17,
        glfw::KeyF18 => keyboard::F18,
        glfw::KeyF19 => keyboard::F19,
        glfw::KeyF20 => keyboard::F20,
        glfw::KeyF21 => keyboard::F21,
        glfw::KeyF22 => keyboard::F22,
        glfw::KeyF23 => keyboard::F23,
        glfw::KeyF24 => keyboard::F24,
        // Possibly next code.
        glfw::KeyF25 => keyboard::Unknown,
        glfw::KeyKp0 => keyboard::NumPad0,
        glfw::KeyKp1 => keyboard::NumPad1,
        glfw::KeyKp2 => keyboard::NumPad2,
        glfw::KeyKp3 => keyboard::NumPad3,
        glfw::KeyKp4 => keyboard::NumPad4,
        glfw::KeyKp5 => keyboard::NumPad5,
        glfw::KeyKp6 => keyboard::NumPad6,
        glfw::KeyKp7 => keyboard::NumPad7,
        glfw::KeyKp8 => keyboard::NumPad8,
        glfw::KeyKp9 => keyboard::NumPad9,
        glfw::KeyKpDecimal => keyboard::NumPadDecimal,
        glfw::KeyKpDivide => keyboard::NumPadDivide,
        glfw::KeyKpMultiply => keyboard::NumPadMultiply,
        glfw::KeyKpSubtract => keyboard::NumPadMinus,
        glfw::KeyKpAdd => keyboard::NumPadPlus,
        glfw::KeyKpEnter => keyboard::NumPadEnter,
        glfw::KeyKpEqual => keyboard::NumPadEquals,
        glfw::KeyLeftShift => keyboard::LShift,
        glfw::KeyLeftControl => keyboard::LCtrl,
        glfw::KeyLeftAlt => keyboard::LAlt,
        glfw::KeyLeftSuper => keyboard::LGui,
        glfw::KeyRightShift => keyboard::RShift,
        glfw::KeyRightControl => keyboard::RCtrl,
        glfw::KeyRightAlt => keyboard::RAlt,
        glfw::KeyRightSuper => keyboard::RGui,
        // Map to backslash?
        glfw::KeyGraveAccent => keyboard::Unknown,
        glfw::KeyHome => keyboard::Home,
        glfw::KeyInsert => keyboard::Insert,
        glfw::KeyLeft => keyboard::Left,
        glfw::KeyLeftBracket => keyboard::LeftBracket,
        glfw::KeyMenu => keyboard::Menu,
        glfw::KeyMinus => keyboard::Minus,
        glfw::KeyNumLock => keyboard::NumLockClear,
        glfw::KeyPageDown => keyboard::PageDown,
        glfw::KeyPageUp => keyboard::PageUp,
        glfw::KeyPause => keyboard::Pause,
        glfw::KeyPeriod => keyboard::Period,
        glfw::KeyPrintScreen => keyboard::PrintScreen,
        glfw::KeyRight => keyboard::Right,
        glfw::KeyRightBracket => keyboard::RightBracket,
        glfw::KeyScrollLock => keyboard::ScrollLock,
        glfw::KeySemicolon => keyboard::Semicolon,
        glfw::KeySlash => keyboard::Slash,
        glfw::KeySpace => keyboard::Space,
        glfw::KeyTab => keyboard::Tab,
        glfw::KeyUp => keyboard::Up,
        glfw::KeyWorld1 => keyboard::Unknown,
        glfw::KeyWorld2 => keyboard::Unknown,
        // _ => keyboard::Unknown,
    }
}

fn glfw_map_mouse(mouse_button: glfw::MouseButton) -> mouse::Button {
    match mouse_button {
        glfw::MouseButton1 => mouse::Left,
        glfw::MouseButton2 => mouse::Right,
        glfw::MouseButton3 => mouse::Middle,
        glfw::MouseButton4 => mouse::X1,
        glfw::MouseButton5 => mouse::X2,
        glfw::MouseButton6 => mouse::Button6,
        glfw::MouseButton7 => mouse::Button7,
        glfw::MouseButton8 => mouse::Button8,
    }
}
<|endoftext|>


<commit_before>//! This module contains types for all kinds of errors that can occur when
//! converting between http requests / responses and ruma's representation of
//! matrix API requests / responses.

use std::{
    error::Error as StdError,
    fmt::{self, Debug, Display, Formatter},
};

use thiserror::Error;

use crate::EndpointError;

// FIXME when `!` becomes stable use it
/// Default `EndpointError` for `ruma_api!` macro
#[derive(Clone, Copy, Debug)]
pub enum Void {}

impl EndpointError for Void {
    fn try_from_response(
        response: http::Response<Vec<u8>>,
    ) -> Result<Self, ResponseDeserializationError> {
        Err(ResponseDeserializationError::from_response(response))
    }
}

impl Display for Void {
    fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {}
    }
}

impl StdError for Void {}

/// An error when converting one of ruma's endpoint-specific request or response
/// types to the corresponding http type.
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum IntoHttpError {
    /// Tried to create an authentication request without an access token.
    #[error(
        "This endpoint has to be converted to http::Request using \
         try_into_authenticated_http_request"
    )]
    NeedsAuthentication,

    /// JSON serialization failed.
    #[error("JSON serialization failed: {0}")]
    Json(#[from] serde_json::Error),

    /// Query parameter serialization failed.
    #[error("Query parameter serialization failed: {0}")]
    Query(#[from] ruma_serde::urlencoded::ser::Error),

    /// Header serialization failed.
    #[error("Header serialization failed: {0}")]
    Header(#[from] http::header::InvalidHeaderValue),

    /// HTTP request construction failed.
    #[error("HTTP request construction failed: {0}")]
    Http(#[from] http::Error),
}

/// An error when converting a http request to one of ruma's endpoint-specific request types.
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum FromHttpRequestError {
    /// Deserialization failed
    #[error("deserialization failed: {0}")]
    Deserialization(#[from] RequestDeserializationError),
}

/// An error that occurred when trying to deserialize a request.
#[derive(Debug, Error)]
#[error("{inner}")]
pub struct RequestDeserializationError {
    inner: DeserializationError,
    http_request: http::Request<Vec<u8>>,
}

impl RequestDeserializationError {
    /// Creates a new `RequestDeserializationError` from the given deserialization error and http
    /// request.
    pub fn new(
        inner: impl Into<DeserializationError>,
        http_request: http::Request<Vec<u8>>,
    ) -> Self {
        Self { inner: inner.into(), http_request }
    }
}

/// An error when converting a http response to one of Ruma's endpoint-specific response types.
#[derive(Debug)]
#[non_exhaustive]
pub enum FromHttpResponseError<E> {
    /// Deserialization failed
    Deserialization(ResponseDeserializationError),

    /// The server returned a non-success status
    Http(ServerError<E>),
}

impl<E: Display> Display for FromHttpResponseError<E> {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        match self {
            Self::Deserialization(err) => write!(f, "deserialization failed: {}", err),
            Self::Http(err) => write!(f, "the server returned an error: {}", err),
        }
    }
}

impl<E> From<ServerError<E>> for FromHttpResponseError<E> {
    fn from(err: ServerError<E>) -> Self {
        Self::Http(err)
    }
}

impl<E> From<ResponseDeserializationError> for FromHttpResponseError<E> {
    fn from(err: ResponseDeserializationError) -> Self {
        Self::Deserialization(err)
    }
}

impl<E: StdError> StdError for FromHttpResponseError<E> {}

/// An error that occurred when trying to deserialize a response.
#[derive(Debug)]
pub struct ResponseDeserializationError {
    inner: Option<DeserializationError>,
    http_response: http::Response<Vec<u8>>,
}

impl ResponseDeserializationError {
    /// Creates a new `ResponseDeserializationError` from the given deserialization error and http
    /// response.
    pub fn new(
        inner: impl Into<DeserializationError>,
        http_response: http::Response<Vec<u8>>,
    ) -> Self {
        Self { inner: Some(inner.into()), http_response }
    }

    /// Creates a new `ResponseDeserializationError` without an inner deserialization error.
    pub fn from_response(http_response: http::Response<Vec<u8>>) -> Self {
        Self { http_response, inner: None }
    }
}

impl Display for ResponseDeserializationError {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        if let Some(ref inner) = self.inner {
            Display::fmt(inner, f)
        } else {
            Display::fmt("deserialization error, no error specified", f)
        }
    }
}

impl StdError for ResponseDeserializationError {}

/// An error was reported by the server (HTTP status code 4xx or 5xx)
#[derive(Debug)]
pub enum ServerError<E> {
    /// An error that is expected to happen under certain circumstances and
    /// that has a well-defined structure
    Known(E),

    /// An error of unexpected type of structure
    Unknown(ResponseDeserializationError),
}

impl<E: Display> Display for ServerError<E> {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        match self {
            ServerError::Known(e) => Display::fmt(e, f),
            ServerError::Unknown(res_err) => Display::fmt(res_err, f),
        }
    }
}

impl<E: StdError> StdError for ServerError<E> {}

/// An error when converting a http request / response to one of ruma's endpoint-specific request /
/// response types.
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum DeserializationError {
    /// Encountered invalid UTF-8.
    #[error("{0}")]
    Utf8(#[from] std::str::Utf8Error),

    /// JSON deserialization failed.
    #[error("{0}")]
    Json(#[from] serde_json::Error),

    /// Query parameter deserialization failed.
    #[error("{0}")]
    Query(#[from] ruma_serde::urlencoded::de::Error),

    /// Got an invalid identifier.
    #[error("{0}")]
    Ident(#[from] ruma_identifiers::Error),

    /// Header value deserialization failed.
    #[error("{0}")]
    Header(#[from] http::header::ToStrError),
}

impl From<std::convert::Infallible> for DeserializationError {
    fn from(err: std::convert::Infallible) -> Self {
        match err {}
    }
}
<commit_msg>api: Normalize std::fmt import<commit_after>//! This module contains types for all kinds of errors that can occur when
//! converting between http requests / responses and ruma's representation of
//! matrix API requests / responses.

use std::{error::Error as StdError, fmt};

use thiserror::Error;

use crate::EndpointError;

// FIXME when `!` becomes stable use it
/// Default `EndpointError` for `ruma_api!` macro
#[derive(Clone, Copy, Debug)]
pub enum Void {}

impl EndpointError for Void {
    fn try_from_response(
        response: http::Response<Vec<u8>>,
    ) -> Result<Self, ResponseDeserializationError> {
        Err(ResponseDeserializationError::from_response(response))
    }
}

impl fmt::Display for Void {
    fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {}
    }
}

impl StdError for Void {}

/// An error when converting one of ruma's endpoint-specific request or response
/// types to the corresponding http type.
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum IntoHttpError {
    /// Tried to create an authentication request without an access token.
    #[error(
        "This endpoint has to be converted to http::Request using \
         try_into_authenticated_http_request"
    )]
    NeedsAuthentication,

    /// JSON serialization failed.
    #[error("JSON serialization failed: {0}")]
    Json(#[from] serde_json::Error),

    /// Query parameter serialization failed.
    #[error("Query parameter serialization failed: {0}")]
    Query(#[from] ruma_serde::urlencoded::ser::Error),

    /// Header serialization failed.
    #[error("Header serialization failed: {0}")]
    Header(#[from] http::header::InvalidHeaderValue),

    /// HTTP request construction failed.
    #[error("HTTP request construction failed: {0}")]
    Http(#[from] http::Error),
}

/// An error when converting a http request to one of ruma's endpoint-specific request types.
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum FromHttpRequestError {
    /// Deserialization failed
    #[error("deserialization failed: {0}")]
    Deserialization(#[from] RequestDeserializationError),
}

/// An error that occurred when trying to deserialize a request.
#[derive(Debug, Error)]
#[error("{inner}")]
pub struct RequestDeserializationError {
    inner: DeserializationError,
    http_request: http::Request<Vec<u8>>,
}

impl RequestDeserializationError {
    /// Creates a new `RequestDeserializationError` from the given deserialization error and http
    /// request.
    pub fn new(
        inner: impl Into<DeserializationError>,
        http_request: http::Request<Vec<u8>>,
    ) -> Self {
        Self { inner: inner.into(), http_request }
    }
}

/// An error when converting a http response to one of Ruma's endpoint-specific response types.
#[derive(Debug)]
#[non_exhaustive]
pub enum FromHttpResponseError<E> {
    /// Deserialization failed
    Deserialization(ResponseDeserializationError),

    /// The server returned a non-success status
    Http(ServerError<E>),
}

impl<E: fmt::Display> fmt::Display for FromHttpResponseError<E> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Deserialization(err) => write!(f, "deserialization failed: {}", err),
            Self::Http(err) => write!(f, "the server returned an error: {}", err),
        }
    }
}

impl<E> From<ServerError<E>> for FromHttpResponseError<E> {
    fn from(err: ServerError<E>) -> Self {
        Self::Http(err)
    }
}

impl<E> From<ResponseDeserializationError> for FromHttpResponseError<E> {
    fn from(err: ResponseDeserializationError) -> Self {
        Self::Deserialization(err)
    }
}

impl<E: StdError> StdError for FromHttpResponseError<E> {}

/// An error that occurred when trying to deserialize a response.
#[derive(Debug)]
pub struct ResponseDeserializationError {
    inner: Option<DeserializationError>,
    http_response: http::Response<Vec<u8>>,
}

impl ResponseDeserializationError {
    /// Creates a new `ResponseDeserializationError` from the given deserialization error and http
    /// response.
    pub fn new(
        inner: impl Into<DeserializationError>,
        http_response: http::Response<Vec<u8>>,
    ) -> Self {
        Self { inner: Some(inner.into()), http_response }
    }

    /// Creates a new `ResponseDeserializationError` without an inner deserialization error.
    pub fn from_response(http_response: http::Response<Vec<u8>>) -> Self {
        Self { http_response, inner: None }
    }
}

impl fmt::Display for ResponseDeserializationError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if let Some(ref inner) = self.inner {
            fmt::Display::fmt(inner, f)
        } else {
            fmt::Display::fmt("deserialization error, no error specified", f)
        }
    }
}

impl StdError for ResponseDeserializationError {}

/// An error was reported by the server (HTTP status code 4xx or 5xx)
#[derive(Debug)]
pub enum ServerError<E> {
    /// An error that is expected to happen under certain circumstances and
    /// that has a well-defined structure
    Known(E),

    /// An error of unexpected type of structure
    Unknown(ResponseDeserializationError),
}

impl<E: fmt::Display> fmt::Display for ServerError<E> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            ServerError::Known(e) => fmt::Display::fmt(e, f),
            ServerError::Unknown(res_err) => fmt::Display::fmt(res_err, f),
        }
    }
}

impl<E: StdError> StdError for ServerError<E> {}

/// An error when converting a http request / response to one of ruma's endpoint-specific request /
/// response types.
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum DeserializationError {
    /// Encountered invalid UTF-8.
    #[error("{0}")]
    Utf8(#[from] std::str::Utf8Error),

    /// JSON deserialization failed.
    #[error("{0}")]
    Json(#[from] serde_json::Error),

    /// Query parameter deserialization failed.
    #[error("{0}")]
    Query(#[from] ruma_serde::urlencoded::de::Error),

    /// Got an invalid identifier.
    #[error("{0}")]
    Ident(#[from] ruma_identifiers::Error),

    /// Header value deserialization failed.
    #[error("{0}")]
    Header(#[from] http::header::ToStrError),
}

impl From<std::convert::Infallible> for DeserializationError {
    fn from(err: std::convert::Infallible) -> Self {
        match err {}
    }
}
<|endoftext|>


<commit_before>use std::cell::UnsafeCell;
use std::fmt::Write;
use std::rc::Rc;
use std::time::Duration;
use std::{fmt, net};

use actix_rt::time::{delay_for, delay_until, Delay, Instant};
use bytes::BytesMut;
use futures_util::{future, FutureExt};
use time::OffsetDateTime;

// "Sun, 06 Nov 1994 08:49:37 GMT".len()
const DATE_VALUE_LENGTH: usize = 29;

#[derive(Debug, PartialEq, Clone, Copy)]
/// Server keep-alive setting
pub enum KeepAlive {
    /// Keep alive in seconds
    Timeout(usize),
    /// Relay on OS to shutdown tcp connection
    Os,
    /// Disabled
    Disabled,
}

impl From<usize> for KeepAlive {
    fn from(keepalive: usize) -> Self {
        KeepAlive::Timeout(keepalive)
    }
}

impl From<Option<usize>> for KeepAlive {
    fn from(keepalive: Option<usize>) -> Self {
        if let Some(keepalive) = keepalive {
            KeepAlive::Timeout(keepalive)
        } else {
            KeepAlive::Disabled
        }
    }
}

/// Http service configuration
pub struct ServiceConfig(Rc<Inner>);

struct Inner {
    keep_alive: Option<Duration>,
    client_timeout: u64,
    client_disconnect: u64,
    ka_enabled: bool,
    secure: bool,
    local_addr: Option<std::net::SocketAddr>,
    timer: DateService,
}

impl Clone for ServiceConfig {
    fn clone(&self) -> Self {
        ServiceConfig(self.0.clone())
    }
}

impl Default for ServiceConfig {
    fn default() -> Self {
        Self::new(KeepAlive::Timeout(5), 0, 0, false, None)
    }
}

impl ServiceConfig {
    /// Create instance of `ServiceConfig`
    pub fn new(
        keep_alive: KeepAlive,
        client_timeout: u64,
        client_disconnect: u64,
        secure: bool,
        local_addr: Option<net::SocketAddr>,
    ) -> ServiceConfig {
        let (keep_alive, ka_enabled) = match keep_alive {
            KeepAlive::Timeout(val) => (val as u64, true),
            KeepAlive::Os => (0, true),
            KeepAlive::Disabled => (0, false),
        };
        let keep_alive = if ka_enabled && keep_alive > 0 {
            Some(Duration::from_secs(keep_alive))
        } else {
            None
        };

        ServiceConfig(Rc::new(Inner {
            keep_alive,
            ka_enabled,
            client_timeout,
            client_disconnect,
            secure,
            local_addr,
            timer: DateService::new(),
        }))
    }

    #[inline]
    /// Returns true if connection is secure(https)
    pub fn secure(&self) -> bool {
        self.0.secure
    }

    #[inline]
    /// Returns the local address that this server is bound to.
    pub fn local_addr(&self) -> Option<net::SocketAddr> {
        self.0.local_addr
    }

    #[inline]
    /// Keep alive duration if configured.
    pub fn keep_alive(&self) -> Option<Duration> {
        self.0.keep_alive
    }

    #[inline]
    /// Return state of connection keep-alive funcitonality
    pub fn keep_alive_enabled(&self) -> bool {
        self.0.ka_enabled
    }

    #[inline]
    /// Client timeout for first request.
    pub fn client_timer(&self) -> Option<Delay> {
        let delay_time = self.0.client_timeout;
        if delay_time != 0 {
            Some(delay_until(
                self.0.timer.now() + Duration::from_millis(delay_time),
            ))
        } else {
            None
        }
    }

    /// Client timeout for first request.
    pub fn client_timer_expire(&self) -> Option<Instant> {
        let delay = self.0.client_timeout;
        if delay != 0 {
            Some(self.0.timer.now() + Duration::from_millis(delay))
        } else {
            None
        }
    }

    /// Client disconnect timer
    pub fn client_disconnect_timer(&self) -> Option<Instant> {
        let delay = self.0.client_disconnect;
        if delay != 0 {
            Some(self.0.timer.now() + Duration::from_millis(delay))
        } else {
            None
        }
    }

    #[inline]
    /// Return keep-alive timer delay is configured.
    pub fn keep_alive_timer(&self) -> Option<Delay> {
        if let Some(ka) = self.0.keep_alive {
            Some(delay_until(self.0.timer.now() + ka))
        } else {
            None
        }
    }

    /// Keep-alive expire time
    pub fn keep_alive_expire(&self) -> Option<Instant> {
        if let Some(ka) = self.0.keep_alive {
            Some(self.0.timer.now() + ka)
        } else {
            None
        }
    }

    #[inline]
    pub(crate) fn now(&self) -> Instant {
        self.0.timer.now()
    }

    #[doc(hidden)]
    pub fn set_date(&self, dst: &mut BytesMut) {
        let mut buf: [u8; 39] = [0; 39];
        buf[..6].copy_from_slice(b"date: ");
        self.0
            .timer
            .set_date(|date| buf[6..35].copy_from_slice(&date.bytes));
        buf[35..].copy_from_slice(b"\r\n\r\n");
        dst.extend_from_slice(&buf);
    }

    pub(crate) fn set_date_header(&self, dst: &mut BytesMut) {
        self.0
            .timer
            .set_date(|date| dst.extend_from_slice(&date.bytes));
    }
}

#[derive(Copy, Clone)]
struct Date {
    bytes: [u8; DATE_VALUE_LENGTH],
    pos: usize,
}

impl Date {
    fn new() -> Date {
        let mut date = Date {
            bytes: [0; DATE_VALUE_LENGTH],
            pos: 0,
        };
        date.update();
        date
    }
    fn update(&mut self) {
        self.pos = 0;
        write!(self, "{}", OffsetDateTime::now().format("%a, %d %b %Y %H:%M:%S GMT")).unwrap();
    }
}

impl fmt::Write for Date {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        let len = s.len();
        self.bytes[self.pos..self.pos + len].copy_from_slice(s.as_bytes());
        self.pos += len;
        Ok(())
    }
}

#[derive(Clone)]
struct DateService(Rc<DateServiceInner>);

struct DateServiceInner {
    current: UnsafeCell<Option<(Date, Instant)>>,
}

impl DateServiceInner {
    fn new() -> Self {
        DateServiceInner {
            current: UnsafeCell::new(None),
        }
    }

    fn reset(&self) {
        unsafe { (&mut *self.current.get()).take() };
    }

    fn update(&self) {
        let now = Instant::now();
        let date = Date::new();
        *(unsafe { &mut *self.current.get() }) = Some((date, now));
    }
}

impl DateService {
    fn new() -> Self {
        DateService(Rc::new(DateServiceInner::new()))
    }

    fn check_date(&self) {
        if unsafe { (&*self.0.current.get()).is_none() } {
            self.0.update();

            // periodic date update
            let s = self.clone();
            actix_rt::spawn(delay_for(Duration::from_millis(500)).then(move |_| {
                s.0.reset();
                future::ready(())
            }));
        }
    }

    fn now(&self) -> Instant {
        self.check_date();
        unsafe { (&*self.0.current.get()).as_ref().unwrap().1 }
    }

    fn set_date<F: FnMut(&Date)>(&self, mut f: F) {
        self.check_date();
        f(&unsafe { (&*self.0.current.get()).as_ref().unwrap().0 })
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_date_len() {
        assert_eq!(DATE_VALUE_LENGTH, "Sun, 06 Nov 1994 08:49:37 GMT".len());
    }

    #[actix_rt::test]
    async fn test_date() {
        let settings = ServiceConfig::new(KeepAlive::Os, 0, 0, false, None);
        let mut buf1 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
        settings.set_date(&mut buf1);
        let mut buf2 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
        settings.set_date(&mut buf2);
        assert_eq!(buf1, buf2);
    }
}
<commit_msg>Replace `UnsafeCell` with `Cell` in `DateServiceInner` (#1325)<commit_after>use std::cell::Cell;
use std::fmt::Write;
use std::rc::Rc;
use std::time::Duration;
use std::{fmt, net};

use actix_rt::time::{delay_for, delay_until, Delay, Instant};
use bytes::BytesMut;
use futures_util::{future, FutureExt};
use time::OffsetDateTime;

// "Sun, 06 Nov 1994 08:49:37 GMT".len()
const DATE_VALUE_LENGTH: usize = 29;

#[derive(Debug, PartialEq, Clone, Copy)]
/// Server keep-alive setting
pub enum KeepAlive {
    /// Keep alive in seconds
    Timeout(usize),
    /// Relay on OS to shutdown tcp connection
    Os,
    /// Disabled
    Disabled,
}

impl From<usize> for KeepAlive {
    fn from(keepalive: usize) -> Self {
        KeepAlive::Timeout(keepalive)
    }
}

impl From<Option<usize>> for KeepAlive {
    fn from(keepalive: Option<usize>) -> Self {
        if let Some(keepalive) = keepalive {
            KeepAlive::Timeout(keepalive)
        } else {
            KeepAlive::Disabled
        }
    }
}

/// Http service configuration
pub struct ServiceConfig(Rc<Inner>);

struct Inner {
    keep_alive: Option<Duration>,
    client_timeout: u64,
    client_disconnect: u64,
    ka_enabled: bool,
    secure: bool,
    local_addr: Option<std::net::SocketAddr>,
    timer: DateService,
}

impl Clone for ServiceConfig {
    fn clone(&self) -> Self {
        ServiceConfig(self.0.clone())
    }
}

impl Default for ServiceConfig {
    fn default() -> Self {
        Self::new(KeepAlive::Timeout(5), 0, 0, false, None)
    }
}

impl ServiceConfig {
    /// Create instance of `ServiceConfig`
    pub fn new(
        keep_alive: KeepAlive,
        client_timeout: u64,
        client_disconnect: u64,
        secure: bool,
        local_addr: Option<net::SocketAddr>,
    ) -> ServiceConfig {
        let (keep_alive, ka_enabled) = match keep_alive {
            KeepAlive::Timeout(val) => (val as u64, true),
            KeepAlive::Os => (0, true),
            KeepAlive::Disabled => (0, false),
        };
        let keep_alive = if ka_enabled && keep_alive > 0 {
            Some(Duration::from_secs(keep_alive))
        } else {
            None
        };

        ServiceConfig(Rc::new(Inner {
            keep_alive,
            ka_enabled,
            client_timeout,
            client_disconnect,
            secure,
            local_addr,
            timer: DateService::new(),
        }))
    }

    #[inline]
    /// Returns true if connection is secure(https)
    pub fn secure(&self) -> bool {
        self.0.secure
    }

    #[inline]
    /// Returns the local address that this server is bound to.
    pub fn local_addr(&self) -> Option<net::SocketAddr> {
        self.0.local_addr
    }

    #[inline]
    /// Keep alive duration if configured.
    pub fn keep_alive(&self) -> Option<Duration> {
        self.0.keep_alive
    }

    #[inline]
    /// Return state of connection keep-alive funcitonality
    pub fn keep_alive_enabled(&self) -> bool {
        self.0.ka_enabled
    }

    #[inline]
    /// Client timeout for first request.
    pub fn client_timer(&self) -> Option<Delay> {
        let delay_time = self.0.client_timeout;
        if delay_time != 0 {
            Some(delay_until(
                self.0.timer.now() + Duration::from_millis(delay_time),
            ))
        } else {
            None
        }
    }

    /// Client timeout for first request.
    pub fn client_timer_expire(&self) -> Option<Instant> {
        let delay = self.0.client_timeout;
        if delay != 0 {
            Some(self.0.timer.now() + Duration::from_millis(delay))
        } else {
            None
        }
    }

    /// Client disconnect timer
    pub fn client_disconnect_timer(&self) -> Option<Instant> {
        let delay = self.0.client_disconnect;
        if delay != 0 {
            Some(self.0.timer.now() + Duration::from_millis(delay))
        } else {
            None
        }
    }

    #[inline]
    /// Return keep-alive timer delay is configured.
    pub fn keep_alive_timer(&self) -> Option<Delay> {
        if let Some(ka) = self.0.keep_alive {
            Some(delay_until(self.0.timer.now() + ka))
        } else {
            None
        }
    }

    /// Keep-alive expire time
    pub fn keep_alive_expire(&self) -> Option<Instant> {
        if let Some(ka) = self.0.keep_alive {
            Some(self.0.timer.now() + ka)
        } else {
            None
        }
    }

    #[inline]
    pub(crate) fn now(&self) -> Instant {
        self.0.timer.now()
    }

    #[doc(hidden)]
    pub fn set_date(&self, dst: &mut BytesMut) {
        let mut buf: [u8; 39] = [0; 39];
        buf[..6].copy_from_slice(b"date: ");
        self.0
            .timer
            .set_date(|date| buf[6..35].copy_from_slice(&date.bytes));
        buf[35..].copy_from_slice(b"\r\n\r\n");
        dst.extend_from_slice(&buf);
    }

    pub(crate) fn set_date_header(&self, dst: &mut BytesMut) {
        self.0
            .timer
            .set_date(|date| dst.extend_from_slice(&date.bytes));
    }
}

#[derive(Copy, Clone)]
struct Date {
    bytes: [u8; DATE_VALUE_LENGTH],
    pos: usize,
}

impl Date {
    fn new() -> Date {
        let mut date = Date {
            bytes: [0; DATE_VALUE_LENGTH],
            pos: 0,
        };
        date.update();
        date
    }
    fn update(&mut self) {
        self.pos = 0;
        write!(self, "{}", OffsetDateTime::now().format("%a, %d %b %Y %H:%M:%S GMT")).unwrap();
    }
}

impl fmt::Write for Date {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        let len = s.len();
        self.bytes[self.pos..self.pos + len].copy_from_slice(s.as_bytes());
        self.pos += len;
        Ok(())
    }
}

#[derive(Clone)]
struct DateService(Rc<DateServiceInner>);

struct DateServiceInner {
    current: Cell<Option<(Date, Instant)>>,
}

impl DateServiceInner {
    fn new() -> Self {
        DateServiceInner {
            current: Cell::new(None),
        }
    }

    fn reset(&self) {
        self.current.take();
    }

    fn update(&self) {
        let now = Instant::now();
        let date = Date::new();
        self.current.set(Some((date, now)));
    }
}

impl DateService {
    fn new() -> Self {
        DateService(Rc::new(DateServiceInner::new()))
    }

    fn check_date(&self) {
        if self.0.current.get().is_none() {
            self.0.update();

            // periodic date update
            let s = self.clone();
            actix_rt::spawn(delay_for(Duration::from_millis(500)).then(move |_| {
                s.0.reset();
                future::ready(())
            }));
        }
    }

    fn now(&self) -> Instant {
        self.check_date();
        self.0.current.get().unwrap().1
    }

    fn set_date<F: FnMut(&Date)>(&self, mut f: F) {
        self.check_date();
        f(&self.0.current.get().unwrap().0);
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    // Test modifying the date from within the closure
    // passed to `set_date`
    #[test]
    fn test_evil_date() {
        let service = DateService::new();
        // Make sure that `check_date` doesn't try to spawn a task
        service.0.update();
        service.set_date(|_| {
            service.0.reset()
        });
    }

    #[test]
    fn test_date_len() {
        assert_eq!(DATE_VALUE_LENGTH, "Sun, 06 Nov 1994 08:49:37 GMT".len());
    }

    #[actix_rt::test]
    async fn test_date() {
        let settings = ServiceConfig::new(KeepAlive::Os, 0, 0, false, None);
        let mut buf1 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
        settings.set_date(&mut buf1);
        let mut buf2 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
        settings.set_date(&mut buf2);
        assert_eq!(buf1, buf2);
    }
}
<|endoftext|>


<commit_before>use model::Model;
use signal::Signal;
use pitch::Pitch;

use std::os::raw::c_char;
use std::os::raw::c_void;
use std::mem;
use std::ffi::CString;
use std::slice;
use std::f32;

#[no_mangle]
pub extern "C" fn malloc(size: usize) -> *mut c_void {
    let mut buf = Vec::with_capacity(size);
    let ptr = buf.as_mut_ptr();
    mem::forget(buf);
    return ptr as *mut c_void;
}

#[no_mangle]
pub extern "C" fn free(ptr: *mut c_void, cap: usize) {
    unsafe  {
        // after it's in scope, it can go out of scope in the normal
        // RAII cleanup.
        let _buf = Vec::from_raw_parts(ptr, 0, cap);
    }
}

#[no_mangle]
pub extern "C" fn free_str(ptr: *mut c_char) {
    unsafe {
        let _ = CString::from_raw(ptr);
    }
}

#[no_mangle]
pub extern "C" fn find_fundamental_frequency(signal_ptr: *const f32, signal_length: isize, sample_rate: f32) -> f32 {
    let signal_slice = unsafe {
        &slice::from_raw_parts(signal_ptr, signal_length as usize)
    };
    let signal = Signal::new(signal_slice, sample_rate);
    let model = Model::from_signal(signal);

    model.pitch.map_or(f32::NAN, |p| p.hz)
}

#[no_mangle]
pub extern "C" fn hz_to_cents_error(hz: f32) -> f32 {
    let pitch = Pitch::new(hz);
    pitch.cents_error()
}

#[no_mangle]
pub extern "C" fn hz_to_pitch(hz: f32) -> *mut c_char {
    let pitch = Pitch::new(hz);
    CString::new(format!("{}", pitch))
		.unwrap()
        .into_raw()
}

#[no_mangle]
pub extern "C" fn correlation(signal_ptr: *mut f32, signal_length: isize, sample_rate: f32) {
    let signal_slice = unsafe {
        &slice::from_raw_parts(signal_ptr, signal_length as usize)
    };

    let signal = Signal::new(signal_slice, sample_rate);
    let model = Model::from_signal(signal);

    unsafe {
        for (i, cor) in model.correlation.value.iter().enumerate() {
            *signal_ptr.offset(i as isize) = *cor;
        }
    }
}
<commit_msg>Fixed weird isizes that should have been usizes<commit_after>use model::Model;
use signal::Signal;
use pitch::Pitch;

use std::os::raw::c_char;
use std::os::raw::c_void;
use std::mem;
use std::ffi::CString;
use std::slice;
use std::f32;

#[no_mangle]
pub extern "C" fn malloc(size: usize) -> *mut c_void {
    let mut buf = Vec::with_capacity(size);
    let ptr = buf.as_mut_ptr();
    mem::forget(buf);
    return ptr as *mut c_void;
}

#[no_mangle]
pub extern "C" fn free(ptr: *mut c_void, cap: usize) {
    unsafe  {
        // after it's in scope, it can go out of scope in the normal
        // RAII cleanup.
        let _buf = Vec::from_raw_parts(ptr, 0, cap);
    }
}

#[no_mangle]
pub extern "C" fn free_str(ptr: *mut c_char) {
    unsafe {
        let _ = CString::from_raw(ptr);
    }
}

#[no_mangle]
pub extern "C" fn find_fundamental_frequency(signal_ptr: *const f32, signal_length: usize, sample_rate: f32) -> f32 {
    let signal_slice = unsafe {
        &slice::from_raw_parts(signal_ptr, signal_length)
    };
    let signal = Signal::new(signal_slice, sample_rate);
    let model = Model::from_signal(signal);

    model.pitch.map_or(f32::NAN, |p| p.hz)
}

#[no_mangle]
pub extern "C" fn hz_to_cents_error(hz: f32) -> f32 {
    let pitch = Pitch::new(hz);
    pitch.cents_error()
}

#[no_mangle]
pub extern "C" fn hz_to_pitch(hz: f32) -> *mut c_char {
    let pitch = Pitch::new(hz);
    CString::new(format!("{}", pitch))
		.unwrap()
        .into_raw()
}

#[no_mangle]
pub extern "C" fn correlation(signal_ptr: *mut f32, signal_length: usize, sample_rate: f32) {
    let signal_slice = unsafe {
        &slice::from_raw_parts(signal_ptr, signal_length)
    };

    let signal = Signal::new(signal_slice, sample_rate);
    let model = Model::from_signal(signal);

    unsafe {
        for (i, cor) in model.correlation.value.iter().enumerate() {
            *signal_ptr.offset(i as isize) = *cor;
        }
    }
}
<|endoftext|>


<commit_before>extern crate getopts;
extern crate rustc_serialize;
extern crate csv;

use getopts::Options;
use std::env;
use std::fs::File;
use std::path::Path;
use std::error::Error;
use std::io;

// This struct represents the data in each row of the CSV file
// Type based decoding absolves us of a lot of the nitty gritty error handling
// for example parsing strings as integers or floats
#[derive(Debug, RustcDecodable)]
struct Row {
    country: String,
    city: String,
    accent_city: String,
    region: String,

    // the CSV parser will fill in the correct value for us
    population: Option<u64>,
    latitude: Option<f64>,
    longitude: Option<f64>,
}

struct PopulationCount {
    city: String,
    country: String,
    count: u64,
}

fn print_usage(program: &str, opts: Options) {
    println!("{}", opts.usage(&format!("Usage: {} [options] <city>", program)));
}

fn search<P: AsRef<Path>>(file_path: &Option<P>, city: &str) -> Result<Vec<PopulationCount>, Box<Error>> {
    let mut found = vec![];

    let input: Box<io::Read> = match *file_path {
        None => Box::new(io::stdin()),
        Some(ref file_path) => Box::new(try!(File::open(file_path))),
    };

    let mut rdr = csv::Reader::from_reader(input);
    for row in rdr.decode::<Row>() {
        let row = try!(row);
        match row.population {
            None => { } // skip it
            Some(count) => if row.city == city {
                found.push(PopulationCount {
                    city: row.city,
                    country: row.country,
                    count: count,
                });
            },
        }
    }
    if found.is_empty() {
        Err(From::from("No matching cities with a population were found."))
    }
    else {
        Ok(found)
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = &args[0];

    let mut opts = Options::new();
    opts.optopt("f", "file", "Choose an input file instead of using STDIN.", "NAME");
    opts.optflag("h", "help", "Show this usage message.");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(e) => { panic!(e.to_string()) }
    };

    if matches.opt_present("h") {
        print_usage(&program, opts);
        return;
    }

    let data_path = matches.opt_str("f");

    let city = if !matches.free.is_empty() {
        &matches.free[0]
    }
    else {
        print_usage(&program, opts);
        return;
    };

    match search(data_path, city) {
        Ok(pops) => {
            for pop in pops {
                println!("{}, {}: {:?}", pop.city, pop.country, pop.count);
            }
        },
        Err(err) => println!("{}", err),
    }
}
<commit_msg>[Rust] Effective Rust Case Study - City Population - Improvements<commit_after>extern crate getopts;
extern crate rustc_serialize;
extern crate csv;

use getopts::Options;
use std::env;
use std::fs::File;
use std::path::Path;
use std::error::Error;
use std::io;
use std::process;

// This struct represents the data in each row of the CSV file
// Type based decoding absolves us of a lot of the nitty gritty error handling
// for example parsing strings as integers or floats
#[derive(Debug, RustcDecodable)]
struct Row {
    country: String,
    city: String,
    accent_city: String,
    region: String,

    // the CSV parser will fill in the correct value for us
    population: Option<u64>,
    latitude: Option<f64>,
    longitude: Option<f64>,
}

struct PopulationCount {
    city: String,
    country: String,
    count: u64,
}

// enum with our possible errors
#[derive(Debug)]
enum CliError {
    Io(io::Error),
    Csv(csv::Error),
    NotFound,
}

use std::fmt;

impl fmt::Display for CliError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CliError::Io(ref err) => err.fmt(f),
            CliError::Csv(ref err) => err.fmt(f),
            CliError::NotFound => write!(f, "No matching cities with a population were found."),
        }
    }
}

impl Error for CliError {
    fn description(&self) -> &str {
        match *self {
            CliError::Io(ref err) => err.description(),
            CliError::Csv(ref err) => err.description(),
            CliError::NotFound => "not found",
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            CliError::Io(ref err) => Some(err),
            CliError::Csv(ref err) => Some(err),
            // our custom error currently does not have an underlying cause
            // but we could modify it so that it does
            CliError::NotFound => None,
        }
    }
}

// From implementations for conversions with try!

impl From<io::Error> for CliError {
    fn from(err: io::Error) -> CliError {
        CliError::Io(err)
    }
}

impl From<csv::Error> for CliError {
    fn from(err: csv::Error) -> CliError {
        CliError::Csv(err)
    }
}

fn print_usage(program: &str, opts: Options) {
    println!("{}", opts.usage(&format!("Usage: {} [options] <city>", program)));
}

fn search<P: AsRef<Path>>(file_path: &Option<P>, city: &str) -> Result<Vec<PopulationCount>, CliError> {
    let mut found = vec![];

    let input: Box<io::Read> = match *file_path {
        None => Box::new(io::stdin()),
        Some(ref file_path) => Box::new(try!(File::open(file_path))),
    };

    let mut rdr = csv::Reader::from_reader(input);
    for row in rdr.decode::<Row>() {
        let row = try!(row);
        match row.population {
            None => { } // skip it
            Some(count) => if row.city == city {
                found.push(PopulationCount {
                    city: row.city,
                    country: row.country,
                    count: count,
                });
            },
        }
    }
    if found.is_empty() {
        Err(CliError::NotFound)
    }
    else {
        Ok(found)
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = &args[0];

    let mut opts = Options::new();
    opts.optopt("f", "file", "Choose an input file instead of using STDIN.", "NAME");
    opts.optflag("h", "help", "Show this usage message.");
    opts.optflag("q", "quiet", "Silences errors and warnings.");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(e) => { panic!(e.to_string()) }
    };

    if matches.opt_present("h") {
        print_usage(&program, opts);
        return;
    }

    let data_path = matches.opt_str("f");

    let city = if !matches.free.is_empty() {
        &matches.free[0]
    }
    else {
        print_usage(&program, opts);
        return;
    };

    match search(&data_path, city) {
        Err(CliError::NotFound) if matches.opt_present("q") => process::exit(1),
        Err(err) => panic!("{}", err),
        Ok(pops) => for pop in pops {
            println!("{}, {}: {:?}", pop.city, pop.country, pop.count);
        }
    }
}
<|endoftext|>


<commit_before>#![feature(os)]

extern crate "pkg-config" as pkg_config;

fn main() {
    if std::os::getenv("CARGO_FEATURE_USE_PKGCONFIG").is_some() {
      if build_pkgconfig() { return; }
      panic!("Could not find SDL2 via pkgconfig");
    } else {
      println!("cargo:rustc-flags=-l tcl");
    }
}

fn build_pkgconfig() -> bool {
    let opts = pkg_config::default_options("tcl");
    pkg_config::find_library_opts("tcl", &opts).is_ok()
}
<commit_msg>Updated build.rs to use tcl8.5 for now<commit_after>#![feature(os)]

extern crate "pkg-config" as pkg_config;

fn main() {
    if std::os::getenv("CARGO_FEATURE_USE_PKGCONFIG").is_some() {
      if build_pkgconfig() { return; }
      panic!("Could not find Tcl via pkgconfig");
    } else {
      println!("cargo:rustc-flags=-l tcl8.5");
    }
}

fn build_pkgconfig() -> bool {
    let opts = pkg_config::default_options("tcl8.5");
    pkg_config::find_library_opts("tcl8.5", &opts).is_ok()
}
<|endoftext|>


<commit_before>use nix::unistd::{fork, setsid, ForkResult};
use std::process;

fn main() {
    if let Ok(ForkResult::Child) = fork() {
        let pid = setsid().expect("sesid failed");
        println!("PGID: {}, my pid {}", pid, process::id());
        process::Command::new("sleep")
            .arg("300")
            .output()
            .expect("failed to execute process");
    }
}
<commit_msg>sync Tue Oct 22 22:12:16 CEST 2019<commit_after>use nix::unistd::{fork, setsid, ForkResult};
use std::process;

fn main() {
    if let Ok(ForkResult::Child) = fork() {
        let pid = setsid().expect("sesid failed");
        if let Ok(ForkResult::Child) = fork() {
            println!("PGID: {}, my pid {}", pid, process::id());
            process::Command::new("sleep")
                .arg("300")
                .output()
                .expect("failed to execute process");
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::rc::Rc;
use Token::*;

pub type Value = i32;
pub type ForthResult = Result<(), Error>;

pub struct Forth {
    stack: Vec<Value>,
    /// Stores the definitions of each word
    /// must be initialized to the system default words
    definitions: HashMap<String, Rc<Vec<Token>>>,
}

#[derive(Debug,PartialEq,Eq,Clone)]
enum Token {
    Number(Value),
    Identifier(String),

    Plus,
    Minus,
    Star,
    Slash,
    Colon,
    Semicolon,

    Dup,
    Drop,
    Over,
    Swap,
}

#[derive(Debug, PartialEq)]
pub enum Error {
    DivisionByZero,
    StackUnderflow,
    UnknownWord,
    InvalidWord,
    EndOfDefinitionWithoutStart,
}

impl Forth {
    pub fn new() -> Forth {
        let mut definitions = HashMap::new();
        // create default mappings for pre-defined words
        definitions.insert("drop".to_string(), Rc::new(vec![Drop]));
        definitions.insert("dup".to_string(), Rc::new(vec![Dup]));
        definitions.insert("swap".to_string(), Rc::new(vec![Swap]));
        definitions.insert("over".to_string(), Rc::new(vec![Over]));
        Forth {
            stack: vec![],
            definitions: definitions,
        }
    }

    pub fn format_stack(&self) -> String {
        let mut res = String::new();
        for val in self.stack.as_slice().iter() {
            res.push_str(&format!("{}", val));
            res.push(' ');
        }
        // remove trailing ' ' if at least 1 char
        let l = if res.len() == 0 {
            0
        } else {
            res.len() - 1
        };
        res.truncate(l);
        res
    }

    pub fn eval(&mut self, input: &str) -> ForthResult {
        let tokenizer = ForthTokenizer::new(input);
        try!{self.eval_vec(&tokenizer.collect())};
        Ok(())
    }

    fn get_word_definition(&self, word: &String) -> Result<Rc<Vec<Token>>, Error> {
        if let Some(x) = self.definitions.get(word) {
            Ok(x.clone())
        } else {
            Err(Error::UnknownWord)
        }
    }

    fn eval_vec(&mut self, input: &Vec<Token>) -> ForthResult {
        let mut tokenstream = input.as_slice().iter();
        loop {
            match tokenstream.next() {
                None => break,
                Some(token) => {
                    match token {
                        &Number(n) => self.stack.push(n),

                        // arbitrary identifiers
                        &Identifier(ref iden) => {
                            let tmp = try!{self.get_word_definition(iden)};
                            try!{self.eval_vec(tmp.as_ref())}
                        }

                        &Semicolon => {
                            // may only occur after colon
                            return Err(Error::EndOfDefinitionWithoutStart);
                        }
                        &Colon => {
                            let mut new_word_commands = Vec::new();

                            // must be Identifier
                            let t = tokenstream.next();
                            if let Some(&Identifier(ref id)) = t {
                                // consume all tokens until `;` is reached and append to
                                // `new_word_commands`
                                loop {
                                    match tokenstream.next() {
                                        None => return Err(Error::InvalidWord),
                                        Some(&Semicolon) => {
                                            // end of word, store in hashmap for later reuse
                                            self.definitions
                                                .insert(id.to_string(), Rc::new(new_word_commands));
                                            break;
                                        }
                                        Some(&Identifier(ref subiden)) => {
                                            // compiler mode:
                                            // copy definition of used word into new word
                                            new_word_commands.append(&mut try!{self.get_word_definition(subiden)}.as_ref().clone())
                                        }
                                        Some(token) => new_word_commands.push(token.clone()),
                                    }
                                }

                            } else {
                                // identifier expected but got something else
                                return Err(Error::InvalidWord);
                            }
                        }

                        // Operations with 1 operand
                        &Dup | &Drop => {
                            match self.stack.pop() {
                                Some(v1) => {
                                    match token {
                                        &Dup => {
                                            self.stack.push(v1);
                                            self.stack.push(v1);
                                        }
                                        &Drop => {}
                                        _ => unreachable!(),
                                    }
                                }
                                None => return Err(Error::StackUnderflow),
                            }
                        }

                        // Operations with 2 operand
                        &Plus | &Minus | &Star | &Slash | &Over | &Swap => {
                            match (self.stack.pop(), self.stack.pop()) {
                                (Some(v1), Some(v2)) => {
                                    match token {
                                        &Plus => self.stack.push(v2 + v1),
                                        &Minus => self.stack.push(v2 - v1),
                                        &Star => self.stack.push(v2 * v1),
                                        &Slash => {
                                            if v1 == 0 {
                                                return Err(Error::DivisionByZero);
                                            }
                                            self.stack.push(v2 / v1)
                                        }
                                        &Swap => {
                                            self.stack.push(v1);
                                            self.stack.push(v2);
                                        }
                                        &Over => {
                                            self.stack.push(v2);
                                            self.stack.push(v1);
                                            self.stack.push(v2);
                                        }
                                        _ => unreachable!(),
                                    }
                                }
                                (_, _) => return Err(Error::StackUnderflow),
                            }
                        }
                    }
                }
            }
        }
        Ok(())
    }
}

#[test]
#[allow(unused_must_use)]
fn redefine_word_previously_used() {
    let mut f = Forth::new();
    f.eval(": foo dup ;");
    f.eval(": dup swap ;");
    f.eval("1 2 foo");
    assert_eq!("1 2 2", f.format_stack());
}

#[test]
#[allow(unused_must_use)]
fn redefine_in_loop() {
    let mut f = Forth::new();
    f.eval(": swap dup ;");
    f.eval(": dup swap ;");
    f.eval(": swap dup ;");
    f.eval("1 swap");
    assert_eq!("1 1", f.format_stack());
}

struct ForthTokenizer<'a> {
    data: &'a str,
    buf: String,
}

impl<'a> ForthTokenizer<'a> {
    fn new(data: &'a str) -> ForthTokenizer {
        ForthTokenizer {
            data: data,
            buf: String::with_capacity(32),
        }
    }
}

impl<'a> Iterator for ForthTokenizer<'a> {
    type Item = Token;

    fn next(&mut self) -> Option<Self::Item> {
        // assumption: all data only consists of unicode symbols which are a single char
        // no glyph consisting out of multiple chars

        // reset buffer
        self.buf.truncate(0);

        // generate iterator
        let mut chars = self.data.chars();
        // need to write the for loop on my own, otherwise the iterator would be moved
        // and I cannot restore the &str value below
        loop {
            match chars.next() {
                Some(c) => {
                    // not totally sure this is the correct filter, but seems to pass all the tests
                    if c.is_control() || c.is_whitespace() {
                        // exit if at least one token read
                        if self.buf.len() > 0 {
                            break;
                        }
                    } else {
                        self.buf.push(c);
                    }
                }
                None => break,
            }
        }
        // save rest of string slice back
        self.data = chars.as_str();

        // process the buffer and output the token
        match self.buf.to_lowercase().as_str() {
            // empty string marks exhaustion of the chars() iterator
            // therefore the tokenizer is also exhausted
            "" => None,

            // symbols
            ":" => Some(Colon),
            ";" => Some(Semicolon),
            "+" => Some(Plus),
            "-" => Some(Minus),
            "*" => Some(Star),
            "/" => Some(Slash),

            // numbers and identifiers
            x => {
                // try to parse it as a number, otherwise it is an identifier
                match x.parse::<Value>() {
                    Ok(v) => Some(Number(v)),
                    Err(_) => Some(Identifier(format!("{}", x.to_lowercase()))),
                }
            }
        }
    }
}

// Tests for the tokenizer
#[test]
#[allow(unused_must_use)]
fn tokenize_number() {
    let expected = vec![Number(1)];
    let input = "1";
    let tokenizer = ForthTokenizer::new(input);
    let result: Vec<Token> = tokenizer.collect();
    assert_eq!(result, expected);
}

#[test]
#[allow(unused_must_use)]
fn tokenize_numbers() {
    let expected = vec![Number(1), Number(256), Number(42)];
    let input = "1 256 42";
    let tokenizer = ForthTokenizer::new(input);
    let result: Vec<Token> = tokenizer.collect();
    assert_eq!(result, expected);
}

#[test]
#[allow(unused_must_use)]
fn tokenize_numbers_multi_whitespace() {
    let expected = vec![Number(1), Number(256), Number(42)];
    let input = "1       256             42";
    let tokenizer = ForthTokenizer::new(input);
    let result: Vec<Token> = tokenizer.collect();
    assert_eq!(result, expected);
}

#[test]
#[allow(unused_must_use)]
fn tokenize_identifier() {
    let expected = vec![Identifier("a".to_string())];
    let input = "a";
    let tokenizer = ForthTokenizer::new(input);
    let result: Vec<Token> = tokenizer.collect();
    assert_eq!(result, expected);
}

#[test]
#[allow(unused_must_use)]
fn tokenize_identifiers() {
    let expected = vec![Identifier("abc".to_string()),
                        Identifier("hello".to_string()),
                        Identifier("world".to_string())];
    let input = "abc hello world";
    let tokenizer = ForthTokenizer::new(input);
    let result: Vec<Token> = tokenizer.collect();
    assert_eq!(result, expected);
}

#[test]
#[allow(unused_must_use)]
fn tokenize_identifier_normalization() {
    let expected = vec![Identifier("helloworld".to_string())];
    let input = "HeLLOwOrlD";
    let tokenizer = ForthTokenizer::new(input);
    let result: Vec<Token> = tokenizer.collect();
    assert_eq!(result, expected);
}

#[test]
#[allow(unused_must_use)]
fn tokenize_non_word_separators() {
    let expected = vec![Number(1), Number(2), Number(3), Number(4), Number(5), Number(6),
                        Number(7)];
    let input = "1\u{0000}2\u{0001}3\n4\r5 6\t7";
    let tokenizer = ForthTokenizer::new(input);
    let result: Vec<Token> = tokenizer.collect();
    assert_eq!(result, expected);
}

#[test]
#[allow(unused_must_use)]
fn tokenize_colon() {
    let expected = vec![Colon];
    let input = ":";
    let tokenizer = ForthTokenizer::new(input);
    let result: Vec<Token> = tokenizer.collect();
    assert_eq!(result, expected);
}

#[test]
#[allow(unused_must_use)]
fn tokenize_semicolon() {
    let expected = vec![Semicolon];
    let input = ";";
    let tokenizer = ForthTokenizer::new(input);
    let result: Vec<Token> = tokenizer.collect();
    assert_eq!(result, expected);
}

#[test]
#[allow(unused_must_use)]
fn tokenize_plus() {
    let expected = vec![Plus];
    let input = "+";
    let tokenizer = ForthTokenizer::new(input);
    let result: Vec<Token> = tokenizer.collect();
    assert_eq!(result, expected);
}

#[test]
#[allow(unused_must_use)]
fn tokenize_minus() {
    let expected = vec![Minus];
    let input = "-";
    let tokenizer = ForthTokenizer::new(input);
    let result: Vec<Token> = tokenizer.collect();
    assert_eq!(result, expected);
}

#[test]
#[allow(unused_must_use)]
fn tokenize_star() {
    let expected = vec![Star];
    let input = "*";
    let tokenizer = ForthTokenizer::new(input);
    let result: Vec<Token> = tokenizer.collect();
    assert_eq!(result, expected);
}

#[test]
#[allow(unused_must_use)]
fn tokenize_slash() {
    let expected = vec![Slash];
    let input = "/";
    let tokenizer = ForthTokenizer::new(input);
    let result: Vec<Token> = tokenizer.collect();
    assert_eq!(result, expected);
}

#[test]
#[allow(unused_must_use)]
fn tokenize_dup() {
    let expected = vec![Identifier("dup".to_string()), Identifier("dup".to_string())];
    let input = "dup dUp";
    let tokenizer = ForthTokenizer::new(input);
    let result: Vec<Token> = tokenizer.collect();
    assert_eq!(result, expected);
}

#[test]
#[allow(unused_must_use)]
fn tokenize_drop() {
    let expected = vec![Identifier("drop".to_string()), Identifier("drop".to_string())];
    let input = "drop DrOp";
    let tokenizer = ForthTokenizer::new(input);
    let result: Vec<Token> = tokenizer.collect();
    assert_eq!(result, expected);
}

#[test]
#[allow(unused_must_use)]
fn tokenize_swap() {
    let expected = vec![Identifier("swap".to_string()), Identifier("swap".to_string())];
    let input = "swap sWaP";
    let tokenizer = ForthTokenizer::new(input);
    let result: Vec<Token> = tokenizer.collect();
    assert_eq!(result, expected);
}

#[test]
#[allow(unused_must_use)]
fn tokenize_over() {
    let expected = vec![Identifier("over".to_string()), Identifier("over".to_string())];
    let input = "over OvEr";
    let tokenizer = ForthTokenizer::new(input);
    let result: Vec<Token> = tokenizer.collect();
    assert_eq!(result, expected);
}
<commit_msg>Forth more comments<commit_after>use std::collections::HashMap;
use std::rc::Rc;
use Token::*;

pub type Value = i32;
pub type ForthResult = Result<(), Error>;

pub struct Forth {
    stack: Vec<Value>,
    /// Stores the definitions of each word
    /// must be initialized to the system default words
    definitions: HashMap<String, Rc<Vec<Token>>>,
}

/// List of tokens which can occur in a Forth program.
#[derive(Debug,PartialEq,Eq,Clone)]
enum Token {
    Number(Value),
    /// Represents anything that is not a number or one of the punctuation symbols. Even the
    /// predefined word like `dup` or `swap` are converted into an Identifier while tokenizing a
    /// string. These predefined word have an already existing entry to the special tokens `Dup`,
    /// `Drop`, `Over`, `Swap` which actually do work.
    Identifier(String),

    Plus,
    Minus,
    Star,
    Slash,
    Colon,
    Semicolon,

    // special tokens, represent the predefined behaviour of the corresponding Identifiers
    Dup,
    Drop,
    Over,
    Swap,
}

#[derive(Debug, PartialEq)]
pub enum Error {
    DivisionByZero,
    StackUnderflow,
    UnknownWord,
    InvalidWord,
    /// New error condition for `;` which occur without a `:` first
    EndOfDefinitionWithoutStart,
}

impl Forth {
    pub fn new() -> Forth {
        let mut definitions = HashMap::new();
        // create default mappings for pre-defined words
        definitions.insert("drop".to_string(), Rc::new(vec![Drop]));
        definitions.insert("dup".to_string(), Rc::new(vec![Dup]));
        definitions.insert("swap".to_string(), Rc::new(vec![Swap]));
        definitions.insert("over".to_string(), Rc::new(vec![Over]));
        Forth {
            stack: vec![],
            definitions: definitions,
        }
    }

    /// Prints all numbers on the stack with ` ` as separation character
    pub fn format_stack(&self) -> String {
        let mut res = String::new();
        for val in self.stack.as_slice().iter() {
            res.push_str(&format!("{}", val));
            res.push(' ');
        }
        // remove trailing ' ' if at least 1 char
        let l = if res.len() == 0 {
            0
        } else {
            res.len() - 1
        };
        res.truncate(l);
        res
    }

    /// Looks up the stored definition of token for the word `word`.
    /// Returns `Error::UnknownWord` if the word is not in the internal hashmap.
    fn get_word_definition(&self, word: &String) -> Result<Rc<Vec<Token>>, Error> {
        if let Some(x) = self.definitions.get(word) {
            Ok(x.clone())
        } else {
            Err(Error::UnknownWord)
        }
    }

    /// Evaluate a string as Forth program. It may be called multiple times. The previous state
    /// will be reused.
    pub fn eval(&mut self, input: &str) -> ForthResult {
        let tokenizer = ForthTokenizer::new(input);
        try!{self.eval_vec(&tokenizer.collect())};
        Ok(())
    }

    /// Abstraction method to process both token streams from str input and stored commands in the
    /// hashmap.
    fn eval_vec(&mut self, input: &Vec<Token>) -> ForthResult {
        let mut tokenstream = input.as_slice().iter();
        loop {
            match tokenstream.next() {
                None => break,
                Some(token) => {
                    match token {
                        &Number(n) => self.stack.push(n),

                        // arbitrary identifiers
                        &Identifier(ref iden) => {
                            let tmp = try!{self.get_word_definition(iden)};
                            try!{self.eval_vec(tmp.as_ref())}
                        }

                        &Semicolon => {
                            // may only occur after colon
                            return Err(Error::EndOfDefinitionWithoutStart);
                        }
                        &Colon => {
                            let mut new_word_commands = Vec::new();

                            // must be Identifier
                            let t = tokenstream.next();
                            if let Some(&Identifier(ref id)) = t {
                                // consume all tokens until `;` is reached and append to
                                // `new_word_commands`
                                loop {
                                    match tokenstream.next() {
                                        None => return Err(Error::InvalidWord),
                                        Some(&Semicolon) => {
                                            // end of word, store in hashmap for later reuse
                                            self.definitions
                                                .insert(id.to_string(), Rc::new(new_word_commands));
                                            break;
                                        }
                                        Some(&Identifier(ref subiden)) => {
                                            // compiler mode:
                                            // copy definition of used word into new word
                                            new_word_commands.append(&mut try!{
                                                    self.get_word_definition(subiden)
                                                }
                                                .as_ref()
                                                .clone())
                                        }
                                        Some(token) => new_word_commands.push(token.clone()),
                                    }
                                }

                            } else {
                                // identifier expected but got something else
                                return Err(Error::InvalidWord);
                            }
                        }

                        // Operations with 1 operand
                        &Dup | &Drop => {
                            match self.stack.pop() {
                                Some(v1) => {
                                    match token {
                                        &Dup => {
                                            self.stack.push(v1);
                                            self.stack.push(v1);
                                        }
                                        &Drop => {}
                                        _ => unreachable!(),
                                    }
                                }
                                None => return Err(Error::StackUnderflow),
                            }
                        }

                        // Operations with 2 operand
                        &Plus | &Minus | &Star | &Slash | &Over | &Swap => {
                            match (self.stack.pop(), self.stack.pop()) {
                                (Some(v1), Some(v2)) => {
                                    match token {
                                        &Plus => self.stack.push(v2 + v1),
                                        &Minus => self.stack.push(v2 - v1),
                                        &Star => self.stack.push(v2 * v1),
                                        &Slash => {
                                            if v1 == 0 {
                                                return Err(Error::DivisionByZero);
                                            }
                                            self.stack.push(v2 / v1)
                                        }
                                        &Swap => {
                                            self.stack.push(v1);
                                            self.stack.push(v2);
                                        }
                                        &Over => {
                                            self.stack.push(v2);
                                            self.stack.push(v1);
                                            self.stack.push(v2);
                                        }
                                        _ => unreachable!(),
                                    }
                                }
                                (_, _) => return Err(Error::StackUnderflow),
                            }
                        }
                    }
                }
            }
        }
        Ok(())
    }
}

#[test]
#[allow(unused_must_use)]
fn redefine_word_previously_used() {
    let mut f = Forth::new();
    f.eval(": foo dup ;");
    f.eval(": dup swap ;");
    f.eval("1 2 foo");
    assert_eq!("1 2 2", f.format_stack());
}

#[test]
#[allow(unused_must_use)]
fn redefine_in_loop() {
    let mut f = Forth::new();
    f.eval(": swap dup ;");
    f.eval(": dup swap ;");
    f.eval(": swap dup ;");
    f.eval("1 swap");
    assert_eq!("1 1", f.format_stack());
}

/// Helper tool to convert a string into a list of Forth tokens.
struct ForthTokenizer<'a> {
    data: &'a str,
    buf: String,
}

impl<'a> ForthTokenizer<'a> {
    fn new(data: &'a str) -> ForthTokenizer {
        ForthTokenizer {
            data: data,
            buf: String::with_capacity(32),
        }
    }
}

impl<'a> Iterator for ForthTokenizer<'a> {
    type Item = Token;

    fn next(&mut self) -> Option<Self::Item> {
        // assumption: all data only consists of unicode symbols which are a single char
        // no glyph consisting out of multiple chars

        // reset buffer
        self.buf.truncate(0);

        // generate iterator
        let mut chars = self.data.chars();
        // need to write the for loop on my own, otherwise the iterator would be moved
        // and I cannot restore the &str value below
        // Consume everything separated by control or whitespace as a single token
        loop {
            match chars.next() {
                Some(c) => {
                    // not totally sure this is the correct filter, but seems to pass all the tests
                    if c.is_control() || c.is_whitespace() {
                        // exit if at least one token read
                        if self.buf.len() > 0 {
                            break;
                        }
                    } else {
                        self.buf.push(c);
                    }
                }
                None => break,
            }
        }
        // save rest of string slice back
        self.data = chars.as_str();

        // process the buffer and output the token
        match self.buf.to_lowercase().as_str() {
            // empty string marks exhaustion of the chars() iterator
            // therefore the tokenizer is also exhausted
            "" => None,

            // symbols
            ":" => Some(Colon),
            ";" => Some(Semicolon),
            "+" => Some(Plus),
            "-" => Some(Minus),
            "*" => Some(Star),
            "/" => Some(Slash),

            // numbers and identifiers
            x => {
                // try to parse it as a number, otherwise it is an identifier
                match x.parse::<Value>() {
                    Ok(v) => Some(Number(v)),
                    Err(_) => Some(Identifier(format!("{}", x.to_lowercase()))),
                }
            }
        }
    }
}

// Tests for the tokenizer
#[test]
#[allow(unused_must_use)]
fn tokenize_number() {
    let expected = vec![Number(1)];
    let input = "1";
    let tokenizer = ForthTokenizer::new(input);
    let result: Vec<Token> = tokenizer.collect();
    assert_eq!(result, expected);
}

#[test]
#[allow(unused_must_use)]
fn tokenize_numbers() {
    let expected = vec![Number(1), Number(256), Number(42)];
    let input = "1 256 42";
    let tokenizer = ForthTokenizer::new(input);
    let result: Vec<Token> = tokenizer.collect();
    assert_eq!(result, expected);
}

#[test]
#[allow(unused_must_use)]
fn tokenize_numbers_multi_whitespace() {
    let expected = vec![Number(1), Number(256), Number(42)];
    let input = "1       256             42";
    let tokenizer = ForthTokenizer::new(input);
    let result: Vec<Token> = tokenizer.collect();
    assert_eq!(result, expected);
}

#[test]
#[allow(unused_must_use)]
fn tokenize_identifier() {
    let expected = vec![Identifier("a".to_string())];
    let input = "a";
    let tokenizer = ForthTokenizer::new(input);
    let result: Vec<Token> = tokenizer.collect();
    assert_eq!(result, expected);
}

#[test]
#[allow(unused_must_use)]
fn tokenize_identifiers() {
    let expected = vec![Identifier("abc".to_string()),
                        Identifier("hello".to_string()),
                        Identifier("world".to_string())];
    let input = "abc hello world";
    let tokenizer = ForthTokenizer::new(input);
    let result: Vec<Token> = tokenizer.collect();
    assert_eq!(result, expected);
}

#[test]
#[allow(unused_must_use)]
fn tokenize_identifier_normalization() {
    let expected = vec![Identifier("helloworld".to_string())];
    let input = "HeLLOwOrlD";
    let tokenizer = ForthTokenizer::new(input);
    let result: Vec<Token> = tokenizer.collect();
    assert_eq!(result, expected);
}

#[test]
#[allow(unused_must_use)]
fn tokenize_non_word_separators() {
    let expected = vec![Number(1), Number(2), Number(3), Number(4), Number(5), Number(6),
                        Number(7)];
    let input = "1\u{0000}2\u{0001}3\n4\r5 6\t7";
    let tokenizer = ForthTokenizer::new(input);
    let result: Vec<Token> = tokenizer.collect();
    assert_eq!(result, expected);
}

#[test]
#[allow(unused_must_use)]
fn tokenize_colon() {
    let expected = vec![Colon];
    let input = ":";
    let tokenizer = ForthTokenizer::new(input);
    let result: Vec<Token> = tokenizer.collect();
    assert_eq!(result, expected);
}

#[test]
#[allow(unused_must_use)]
fn tokenize_semicolon() {
    let expected = vec![Semicolon];
    let input = ";";
    let tokenizer = ForthTokenizer::new(input);
    let result: Vec<Token> = tokenizer.collect();
    assert_eq!(result, expected);
}

#[test]
#[allow(unused_must_use)]
fn tokenize_plus() {
    let expected = vec![Plus];
    let input = "+";
    let tokenizer = ForthTokenizer::new(input);
    let result: Vec<Token> = tokenizer.collect();
    assert_eq!(result, expected);
}

#[test]
#[allow(unused_must_use)]
fn tokenize_minus() {
    let expected = vec![Minus];
    let input = "-";
    let tokenizer = ForthTokenizer::new(input);
    let result: Vec<Token> = tokenizer.collect();
    assert_eq!(result, expected);
}

#[test]
#[allow(unused_must_use)]
fn tokenize_star() {
    let expected = vec![Star];
    let input = "*";
    let tokenizer = ForthTokenizer::new(input);
    let result: Vec<Token> = tokenizer.collect();
    assert_eq!(result, expected);
}

#[test]
#[allow(unused_must_use)]
fn tokenize_slash() {
    let expected = vec![Slash];
    let input = "/";
    let tokenizer = ForthTokenizer::new(input);
    let result: Vec<Token> = tokenizer.collect();
    assert_eq!(result, expected);
}

#[test]
#[allow(unused_must_use)]
fn tokenize_dup() {
    let expected = vec![Identifier("dup".to_string()), Identifier("dup".to_string())];
    let input = "dup dUp";
    let tokenizer = ForthTokenizer::new(input);
    let result: Vec<Token> = tokenizer.collect();
    assert_eq!(result, expected);
}

#[test]
#[allow(unused_must_use)]
fn tokenize_drop() {
    let expected = vec![Identifier("drop".to_string()), Identifier("drop".to_string())];
    let input = "drop DrOp";
    let tokenizer = ForthTokenizer::new(input);
    let result: Vec<Token> = tokenizer.collect();
    assert_eq!(result, expected);
}

#[test]
#[allow(unused_must_use)]
fn tokenize_swap() {
    let expected = vec![Identifier("swap".to_string()), Identifier("swap".to_string())];
    let input = "swap sWaP";
    let tokenizer = ForthTokenizer::new(input);
    let result: Vec<Token> = tokenizer.collect();
    assert_eq!(result, expected);
}

#[test]
#[allow(unused_must_use)]
fn tokenize_over() {
    let expected = vec![Identifier("over".to_string()), Identifier("over".to_string())];
    let input = "over OvEr";
    let tokenizer = ForthTokenizer::new(input);
    let result: Vec<Token> = tokenizer.collect();
    assert_eq!(result, expected);
}
<|endoftext|>