<commit_before>#![deny(missing_docs)]

//! A GLFW window back-end for the Piston game engine.

extern crate glfw;
extern crate collections;
extern crate gl;
extern crate event;
extern crate shader_version;
extern crate input;

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

/// Contains stuff for game window.
pub struct GlfwWindow {
    /// 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 GlfwWindow {
    /// 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) -> GlfwWindow {
        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 });

        GlfwWindow {
            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) -> GlfwWindow {
        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| window.get_proc_address(s));

        GlfwWindow {
            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));
                }
                _ => {}
            }
        }
    }
}

impl Window for GlfwWindow {
    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 get_size(&self) -> (u32, u32) {
        let (w, h) = self.window.get_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>Upgraded to latest Rust<commit_after>#![deny(missing_docs)]

//! A GLFW window back-end for the Piston game engine.

extern crate glfw;
extern crate collections;
extern crate gl;
extern crate event;
extern crate shader_version;
extern crate input;

// External crates.
use collections::RingBuf;
use glfw::Context;
use input::{
    keyboard,
    mouse,
};
use event::{
    Window,
    WindowSettings,
};
use shader_version::opengl::OpenGL;

/// Contains stuff for game window.
pub struct GlfwWindow {
    /// 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 GlfwWindow {
    /// 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) -> GlfwWindow {
        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 });

        GlfwWindow {
            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) -> GlfwWindow {
        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| window.get_proc_address(s));

        GlfwWindow {
            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));
                }
                _ => {}
            }
        }
    }
}

impl Window for GlfwWindow {
    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 get_size(&self) -> (u32, u32) {
        let (w, h) = self.window.get_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>//! Postgres support for the `r2d2` connection pool.
#![doc(html_root_url="https://sfackler.github.io/r2d2-postgres/doc")]
#![warn(missing_docs)]
extern crate r2d2;
extern crate postgres;

use std::error;
use std::error::Error as _StdError;
use std::fmt;
use postgres::{IntoConnectParams, SslMode};

/// A unified enum of errors returned by postgres::Connection
#[derive(Debug)]
pub enum Error {
    /// A postgres::ConnectError
    Connect(postgres::ConnectError),
    /// An postgres::Error
    Other(postgres::Error),
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}: {}", self.description(), self.cause().unwrap())
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Connect(_) => "Error opening a connection",
            Error::Other(_) => "Error communicating with server",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Connect(ref err) => Some(err as &error::Error),
            Error::Other(ref err) => Some(err as &error::Error),
        }
    }
}

/// An `r2d2::ConnectionManager` for `postgres::Connection`s.
///
/// ## Example
///
/// ```rust,no_run
/// #![allow(unstable)]
/// extern crate r2d2;
/// extern crate r2d2_postgres;
/// extern crate postgres;
///
/// use std::sync::Arc;
/// use std::default::Default;
/// use std::thread;
/// use postgres::SslMode;
/// use r2d2_postgres::PostgresConnectionManager;
///
/// fn main() {
///     let config = Default::default();
///     let manager = PostgresConnectionManager::new("postgres://postgres@localhost",
///                                                  SslMode::None).unwrap();
///     let error_handler = Box::new(r2d2::LoggingErrorHandler);
///     let pool = Arc::new(r2d2::Pool::new(config, manager, error_handler).unwrap());
///
///     for i in 0..10i32 {
///         let pool = pool.clone();
///         thread::spawn(move || {
///             let conn = pool.get().unwrap();
///             conn.execute("INSERT INTO foo (bar) VALUES ($1)", &[&i]).unwrap();
///         });
///     }
/// }
/// ```
pub struct PostgresConnectionManager {
    params: postgres::ConnectParams,
    ssl_mode: SslMode,
}

impl fmt::Debug for PostgresConnectionManager {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "PostgresConnectionManager {{ parameters: {:?}, ssl_mode: {:?} }}",
               self.params, self.ssl_mode)
    }
}

impl PostgresConnectionManager {
    /// Creates a new `PostgresConnectionManager`.
    ///
    /// See `postgres::Connection::connect` for a description of the parameter
    /// types.
    pub fn new<T: IntoConnectParams>(params: T, ssl_mode: SslMode)
            -> Result<PostgresConnectionManager, postgres::ConnectError> {
        Ok(PostgresConnectionManager {
            params: try!(params.into_connect_params()),
            ssl_mode: ssl_mode,
        })
    }
}

impl r2d2::ConnectionManager for PostgresConnectionManager {
    type Connection = postgres::Connection;
    type Error = Error;

    fn connect(&self) -> Result<postgres::Connection, Error> {
        postgres::Connection::connect(self.params.clone(), &self.ssl_mode).map_err(Error::Connect)
    }

    fn is_valid(&self, conn: &mut postgres::Connection) -> Result<(), Error> {
        conn.batch_execute("").map_err(Error::Other)
    }

    fn has_broken(&self, conn: &mut postgres::Connection) -> bool {
        conn.is_desynchronized()
    }
}
<commit_msg>Derive Debug<commit_after>//! Postgres support for the `r2d2` connection pool.
#![doc(html_root_url="https://sfackler.github.io/r2d2-postgres/doc")]
#![warn(missing_docs)]
extern crate r2d2;
extern crate postgres;

use std::error;
use std::error::Error as _StdError;
use std::fmt;
use postgres::{IntoConnectParams, SslMode};

/// A unified enum of errors returned by postgres::Connection
#[derive(Debug)]
pub enum Error {
    /// A postgres::ConnectError
    Connect(postgres::ConnectError),
    /// An postgres::Error
    Other(postgres::Error),
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}: {}", self.description(), self.cause().unwrap())
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Connect(_) => "Error opening a connection",
            Error::Other(_) => "Error communicating with server",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Connect(ref err) => Some(err as &error::Error),
            Error::Other(ref err) => Some(err as &error::Error),
        }
    }
}

/// An `r2d2::ConnectionManager` for `postgres::Connection`s.
///
/// ## Example
///
/// ```rust,no_run
/// #![allow(unstable)]
/// extern crate r2d2;
/// extern crate r2d2_postgres;
/// extern crate postgres;
///
/// use std::sync::Arc;
/// use std::default::Default;
/// use std::thread;
/// use postgres::SslMode;
/// use r2d2_postgres::PostgresConnectionManager;
///
/// fn main() {
///     let config = Default::default();
///     let manager = PostgresConnectionManager::new("postgres://postgres@localhost",
///                                                  SslMode::None).unwrap();
///     let error_handler = Box::new(r2d2::LoggingErrorHandler);
///     let pool = Arc::new(r2d2::Pool::new(config, manager, error_handler).unwrap());
///
///     for i in 0..10i32 {
///         let pool = pool.clone();
///         thread::spawn(move || {
///             let conn = pool.get().unwrap();
///             conn.execute("INSERT INTO foo (bar) VALUES ($1)", &[&i]).unwrap();
///         });
///     }
/// }
/// ```
#[derive(Debug)]
pub struct PostgresConnectionManager {
    params: postgres::ConnectParams,
    ssl_mode: SslMode,
}

impl PostgresConnectionManager {
    /// Creates a new `PostgresConnectionManager`.
    ///
    /// See `postgres::Connection::connect` for a description of the parameter
    /// types.
    pub fn new<T: IntoConnectParams>(params: T, ssl_mode: SslMode)
            -> Result<PostgresConnectionManager, postgres::ConnectError> {
        Ok(PostgresConnectionManager {
            params: try!(params.into_connect_params()),
            ssl_mode: ssl_mode,
        })
    }
}

impl r2d2::ConnectionManager for PostgresConnectionManager {
    type Connection = postgres::Connection;
    type Error = Error;

    fn connect(&self) -> Result<postgres::Connection, Error> {
        postgres::Connection::connect(self.params.clone(), &self.ssl_mode).map_err(Error::Connect)
    }

    fn is_valid(&self, conn: &mut postgres::Connection) -> Result<(), Error> {
        conn.batch_execute("").map_err(Error::Other)
    }

    fn has_broken(&self, conn: &mut postgres::Connection) -> bool {
        conn.is_desynchronized()
    }
}
<|endoftext|>


<commit_before>#[macro_use] extern crate hyper;
extern crate url;
extern crate time;
extern crate rand;
extern crate crypto;
extern crate rustc_serialize;
extern crate mime;

mod auth;
pub mod error;
pub mod user;
mod links;
mod common;

pub use auth::{Token, request_token, authorize_url, access_token};
pub use common::{Response, TwitterErrors, TwitterErrorCode};
<commit_msg>more warnings<commit_after>#![warn(missing_docs)]
#![warn(unused_extern_crates)]
#![warn(unused_qualifications)]

#[macro_use] extern crate hyper;
extern crate url;
extern crate time;
extern crate rand;
extern crate crypto;
extern crate rustc_serialize;
extern crate mime;

mod auth;
pub mod error;
pub mod user;
mod links;
mod common;

pub use auth::{Token, request_token, authorize_url, access_token};
pub use common::{Response, TwitterErrors, TwitterErrorCode};
<|endoftext|>


<commit_before>extern crate num;
use num::traits::{Zero, One, Signed, ToPrimitive};
use num::bigint::{BigInt, ToBigInt};
use num::rational::BigRational;

fn factorial(n: i64) -> BigInt
{
    let mut acc = One::one();
    for i in 2 .. n + 1
    {
        acc = acc * i.to_bigint().unwrap();
    }
    acc
}

fn factorial_f(n: f32) -> BigInt
{
    factorial(n as i64)
}

fn minus_one_pow(n: i64) -> i64
{
    1 - n % 2 * 2
}

// could optimize the type usage better if i knew what i'm doing
pub fn clebschgordansq(j1: f32, m1: f32, j2: f32, m2: f32, j12: f32, m12: f32) -> (i32, BigRational)
{
    if m1 + m2 != m12 || j1 + j2 < j12 || (j1 - j2).abs() > j12 || (2. * (j1 + j2 + j12)) % 2. != 0.
    {
        return (0, Zero::zero())
    }

    let kmin = -(0_f32.min(j12 - j2 + m1).min(j12 - j1 - m2).trunc());
    let kmax = (j1 + j2 - j12).min(j1 - m1).min(j2 + m2).trunc();
    if kmin > kmax
    {
        return (0, Zero::zero())
    }

    let mut c1 = kmin as i64;
    let mut c2 = (j1 + j2 - j12 - kmin) as i64;
    let mut c3 = (j1 - m1 - kmin) as i64;
    let mut c4 = (j2 + m2 - kmin) as i64;
    let mut c5 = (j12 - j2 + m1 + kmin) as i64;
    let mut c6 = (j12 - j1 - m2 + kmin) as i64;
    let mut c = BigRational::new(
        minus_one_pow(kmin as i64).to_bigint().unwrap(),
        factorial(c1) * factorial(c2) * factorial(c3) * factorial(c4) * factorial(c5) * factorial(c6)
    );
    let mut r = c.clone();

    for _ in kmin as i64 .. kmax as i64  // k unused, removed the +1
    {
        c1 += 1;
        c5 += 1;
        c6 += 1;
        c = c * BigRational::new(
            (-c2 * c3 * c4).to_bigint().unwrap(),  // could overflow, don't know the size of values
            (c1 * c5 * c6).to_bigint().unwrap()
        );
        c2 -= 1;
        c3 -= 1;
        c4 -= 1;
        r = r + c.clone();  // ops::AddAssign is still on RFC
    }

    let sign = r.signum().to_integer().to_i32().unwrap(); // this sucks
    let rsq = r.clone() * r; // ugly, pow() not implemented for BigInt

    let val = BigRational::new(
        ((2. * j12 + 1.) as i64).to_bigint().unwrap() *
        factorial_f(j12 + j1 - j2) *
        factorial_f(j12 - j1 + j2) *
        factorial_f(j1 + j2 - j12) *
        factorial_f(j12 + m12) * // reordered things here because BigRational * BigInt isn't implemented
        factorial_f(j12 - m12) *
        factorial_f(j1 - m1) *
        factorial_f(j1 + m1) *
        factorial_f(j2 - m2) *
        factorial_f(j2 + m2),
        factorial_f(j1 + j2 + j12 + 1.)
    ) * rsq;

    (sign, val)
}

/*
// can't sqrt() a BigNum, so this doesn't work. maybe should turn it back into float?
pub fn clebschgordan(j1: f32, m1: f32, j2: f32, m2: f32, j12: f32, m12: f32) -> BigRational
{
    let (s, r) = clebschgordansq(j1, m1, j2, m2, j12, m12);
    s * r.sqrt()
}
*/
<commit_msg>more improvements<commit_after>extern crate num;
use num::traits::{Zero, One, Signed, ToPrimitive};
use num::bigint::{BigInt, ToBigInt};
use num::rational::BigRational;

fn factorial(n: i64) -> BigInt
{
    (2..n + 1).fold(One::one(), |acc, i| acc * i.to_bigint().unwrap())
}

fn factorial_f(n: f32) -> BigInt
{
    factorial(n as i64)
}

fn minus_one_pow(n: i64) -> i64
{
    1 - n % 2 * 2
}

// could optimize the type usage better if i knew what i'm doing
pub fn clebschgordansq(j1: f32, m1: f32, j2: f32, m2: f32, j12: f32, m12: f32) -> (i32, BigRational)
{
    if m1 + m2 != m12 || j1 + j2 < j12 || (j1 - j2).abs() > j12 || (2. * (j1 + j2 + j12)) % 2. != 0.
    {
        return (0, Zero::zero())
    }

    let kmin = -(0_f32.min(j12 - j2 + m1).min(j12 - j1 - m2) as i64);
    let kmax = (j1 + j2 - j12).min(j1 - m1).min(j2 + m2) as i64;
    if kmin > kmax
    {
        return (0, Zero::zero())
    }

    let kmin_f = kmin as f32;
    let mut c1 = kmin;
    let mut c2 = (j1 + j2 - j12 - kmin_f) as i64;
    let mut c3 = (j1 - m1 - kmin_f) as i64;
    let mut c4 = (j2 + m2 - kmin_f) as i64;
    let mut c5 = (j12 - j2 + m1 + kmin_f) as i64;
    let mut c6 = (j12 - j1 - m2 + kmin_f) as i64;
    let mut c = BigRational::new(
        minus_one_pow(kmin).to_bigint().unwrap(),
        factorial(c1) * factorial(c2) * factorial(c3) * factorial(c4) * factorial(c5) * factorial(c6)
    );
    let mut r = c.clone();

    for _ in kmin .. kmax
    {
        c1 += 1;
        c5 += 1;
        c6 += 1;
        c = c * BigRational::new(
            (-c2 * c3 * c4).to_bigint().unwrap(),  // could overflow, don't know the size of values
            (c1 * c5 * c6).to_bigint().unwrap()
        );
        c2 -= 1;
        c3 -= 1;
        c4 -= 1;
        r = r + c.clone();  // ops::AddAssign is still on RFC
    }

    let sign = r.signum().to_integer().to_i32().unwrap(); // this sucks
    let rsq = r.clone() * r; // ugly, pow() not implemented for BigInt

    let val = BigRational::new(
        ((2. * j12 + 1.) as i64).to_bigint().unwrap() *
        factorial_f(j12 + j1 - j2) *
        factorial_f(j12 - j1 + j2) *
        factorial_f(j1 + j2 - j12) *
        factorial_f(j12 + m12) * // reordered things here because BigRational * BigInt isn't implemented
        factorial_f(j12 - m12) *
        factorial_f(j1 - m1) *
        factorial_f(j1 + m1) *
        factorial_f(j2 - m2) *
        factorial_f(j2 + m2),
        factorial_f(j1 + j2 + j12 + 1.)
    ) * rsq;

    (sign, val)
}

/*
// can't sqrt() a BigNum, so this doesn't work. maybe should turn it back into float?
pub fn clebschgordan(j1: f32, m1: f32, j2: f32, m2: f32, j12: f32, m12: f32) -> BigRational
{
    let (s, r) = clebschgordansq(j1, m1, j2, m2, j12, m12);
    s * r.sqrt()
}
*/
<|endoftext|>


<commit_before>#![crate_name = "amethyst"]
#![crate_type = "lib"]

//! Amethyst is a free and open source SDK (software development kit) written in
//! idiomatic [Rust](https://www.rust-lang.org/) for building video games and
//! interactive multimedia applications.
//!
//! # Example
//!
//! ```
//! extern crate amethyst;
//!
//! use amethyst::*;
//!
//! struct GameState;
//!
//! impl State for GameState {
//!     fn new() -> GameState {
//!         GameState
//!     }
//!
//!     fn handle_events(&mut self, game: &Game, events: &Vec<Event>) {
//!         for e in events {
//!             match e {
//!                 Event::Closed => game.quit(),
//!                 Event::Resized(x, y) => println!("x: {}, y: {}", x, y),
//!                 Event::KeyPressed(k) => if k == Key::Esc { game.quit() }
//!             }
//!         }
//!     }
//!
//!     fn update(&mut self, game: &Game, delta: Duration) {
//!         println!("Computing some more whoop-ass...");
//!     }
//! }
//!
//! fn main() {
//!     let mut game = Application::new(GameState::new());
//!     game.run();
//! }
//! ```

pub mod engine;
pub mod renderer;
<commit_msg>add trailing newline<commit_after>#![crate_name = "amethyst"]
#![crate_type = "lib"]

//! Amethyst is a free and open source SDK (software development kit) written in
//! idiomatic [Rust](https://www.rust-lang.org/) for building video games and
//! interactive multimedia applications.
//!
//! # Example
//!
//! ```
//! extern crate amethyst;
//!
//! use amethyst::*;
//!
//! struct GameState;
//!
//! impl State for GameState {
//!     fn new() -> GameState {
//!         GameState
//!     }
//!
//!     fn handle_events(&mut self, game: &Game, events: &Vec<Event>) {
//!         for e in events {
//!             match e {
//!                 Event::Closed => game.quit(),
//!                 Event::Resized(x, y) => println!("x: {}, y: {}", x, y),
//!                 Event::KeyPressed(k) => if k == Key::Esc { game.quit() }
//!             }
//!         }
//!     }
//!
//!     fn update(&mut self, game: &Game, delta: Duration) {
//!         println!("Computing some more whoop-ass...");
//!     }
//! }
//!
//! fn main() {
//!     let mut game = Application::new(GameState::new());
//!     game.run();
//! }
//! ```

pub mod engine;
pub mod renderer;

<|endoftext|>


<commit_before>extern crate libc;
use std::ffi::CString;

#[allow(dead_code,
        non_snake_case,
        non_camel_case_types,
        non_upper_case_globals)]
pub mod libpq;

// Symbols Postgres needs to find.

#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern fn _PG_init() { }

#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern fn
    _PG_output_plugin_init(cb: *mut libpq::OutputPluginCallbacks) { init(cb); }

// Implementation of initialization and callbacks.

pub unsafe extern fn init(cb: *mut libpq::OutputPluginCallbacks) {
    (*cb).startup_cb = Some(startup);
    (*cb).begin_cb = Some(begin);
    (*cb).change_cb = Some(change);
    (*cb).commit_cb = Some(commit);
    (*cb).shutdown_cb = Some(shutdown);
}
/*
pub type LogicalOutputPluginInit =
    ::std::option::Option<extern "C" fn(cb: *mut Struct_OutputPluginCallbacks)
                              -> ()>;
*/

extern fn startup(ctx: *mut libpq::Struct_LogicalDecodingContext,
                  options: *mut libpq::OutputPluginOptions,
                  is_init: libpq::_bool) {

}
/*
pub type LogicalDecodeStartupCB =
    ::std::option::Option<extern "C" fn(ctx:
                                            *mut Struct_LogicalDecodingContext,
                                        options: *mut OutputPluginOptions,
                                        is_init: _bool) -> ()>;
 */

extern fn begin(ctx: *mut libpq::Struct_LogicalDecodingContext,
                txn: *mut libpq::ReorderBufferTXN) {
    unsafe {
        let last = 1;                                     // True in C language
        let s = CString::new("BEGIN %u").unwrap();
        libpq::OutputPluginPrepareWrite(ctx, last);
        libpq::appendStringInfo((*ctx).out, s.as_ptr(), (*txn).xid);
        libpq::OutputPluginWrite(ctx, last);
    }
}
/*
pub type LogicalDecodeBeginCB =
    ::std::option::Option<extern "C" fn(arg1:
                                            *mut Struct_LogicalDecodingContext,
                                        txn: *mut ReorderBufferTXN) -> ()>;
 */

extern fn change(ctx: *mut libpq::Struct_LogicalDecodingContext,
                 txn: *mut libpq::ReorderBufferTXN,
                 relation: libpq::Relation,
                 change: *mut libpq::ReorderBufferChange) {

}
/*
pub type LogicalDecodeChangeCB =
    ::std::option::Option<extern "C" fn(arg1:
                                            *mut Struct_LogicalDecodingContext,
                                        txn: *mut ReorderBufferTXN,
                                        relation: Relation,
                                        change: *mut ReorderBufferChange)
                              -> ()>;
 */

extern fn commit(ctx: *mut libpq::Struct_LogicalDecodingContext,
                 txn: *mut libpq::ReorderBufferTXN,
                 lsn: libpq::XLogRecPtr) {
    unsafe {
        let last = 1;                                     // True in C language
        let s = CString::new("COMMIT %u").unwrap();
        libpq::OutputPluginPrepareWrite(ctx, last);
        libpq::appendStringInfo((*ctx).out, s.as_ptr(), (*txn).xid);
        libpq::OutputPluginWrite(ctx, last);
    }
}
/*
pub type LogicalDecodeCommitCB =
    ::std::option::Option<extern "C" fn(arg1:
                                            *mut Struct_LogicalDecodingContext,
                                        txn: *mut ReorderBufferTXN,
                                        commit_lsn: XLogRecPtr) -> ()>;
 */

extern fn shutdown(ctx: *mut libpq::Struct_LogicalDecodingContext) {

}
/*
pub type LogicalDecodeShutdownCB =
    ::std::option::Option<extern "C" fn(arg1:
                                            *mut Struct_LogicalDecodingContext)
                              -> ()>;

 */
<commit_msg>Set output type to text<commit_after>extern crate libc;
use std::ffi::CString;

#[allow(dead_code,
        non_snake_case,
        non_camel_case_types,
        non_upper_case_globals)]
pub mod libpq;

// Symbols Postgres needs to find.

#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern fn _PG_init() { }

#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern fn
    _PG_output_plugin_init(cb: *mut libpq::OutputPluginCallbacks) { init(cb); }

// Implementation of initialization and callbacks.

pub unsafe extern fn init(cb: *mut libpq::OutputPluginCallbacks) {
    (*cb).startup_cb = Some(startup);
    (*cb).begin_cb = Some(begin);
    (*cb).change_cb = Some(change);
    (*cb).commit_cb = Some(commit);
    (*cb).shutdown_cb = Some(shutdown);
}
/*
pub type LogicalOutputPluginInit =
    ::std::option::Option<extern "C" fn(cb: *mut Struct_OutputPluginCallbacks)
                              -> ()>;
*/

extern fn startup(ctx: *mut libpq::Struct_LogicalDecodingContext,
                  options: *mut libpq::OutputPluginOptions,
                  is_init: libpq::_bool) {
    unsafe {
        (*options).output_type = libpq::OUTPUT_PLUGIN_TEXTUAL_OUTPUT;
    }
}
/*
pub type LogicalDecodeStartupCB =
    ::std::option::Option<extern "C" fn(ctx:
                                            *mut Struct_LogicalDecodingContext,
                                        options: *mut OutputPluginOptions,
                                        is_init: _bool) -> ()>;
 */

extern fn begin(ctx: *mut libpq::Struct_LogicalDecodingContext,
                txn: *mut libpq::ReorderBufferTXN) {
    unsafe {
        let last = 1;                                     // True in C language
        let s = CString::new("BEGIN %u").unwrap();
        libpq::OutputPluginPrepareWrite(ctx, last);
        libpq::appendStringInfo((*ctx).out, s.as_ptr(), (*txn).xid);
        libpq::OutputPluginWrite(ctx, last);
    }
}
/*
pub type LogicalDecodeBeginCB =
    ::std::option::Option<extern "C" fn(arg1:
                                            *mut Struct_LogicalDecodingContext,
                                        txn: *mut ReorderBufferTXN) -> ()>;
 */

extern fn change(ctx: *mut libpq::Struct_LogicalDecodingContext,
                 txn: *mut libpq::ReorderBufferTXN,
                 relation: libpq::Relation,
                 change: *mut libpq::ReorderBufferChange) {

}
/*
pub type LogicalDecodeChangeCB =
    ::std::option::Option<extern "C" fn(arg1:
                                            *mut Struct_LogicalDecodingContext,
                                        txn: *mut ReorderBufferTXN,
                                        relation: Relation,
                                        change: *mut ReorderBufferChange)
                              -> ()>;
 */

extern fn commit(ctx: *mut libpq::Struct_LogicalDecodingContext,
                 txn: *mut libpq::ReorderBufferTXN,
                 lsn: libpq::XLogRecPtr) {
    unsafe {
        let last = 1;                                     // True in C language
        let s = CString::new("COMMIT %u").unwrap();
        libpq::OutputPluginPrepareWrite(ctx, last);
        libpq::appendStringInfo((*ctx).out, s.as_ptr(), (*txn).xid);
        libpq::OutputPluginWrite(ctx, last);
    }
}
/*
pub type LogicalDecodeCommitCB =
    ::std::option::Option<extern "C" fn(arg1:
                                            *mut Struct_LogicalDecodingContext,
                                        txn: *mut ReorderBufferTXN,
                                        commit_lsn: XLogRecPtr) -> ()>;
 */

extern fn shutdown(ctx: *mut libpq::Struct_LogicalDecodingContext) {

}
/*
pub type LogicalDecodeShutdownCB =
    ::std::option::Option<extern "C" fn(arg1:
                                            *mut Struct_LogicalDecodingContext)
                              -> ()>;

 */
<|endoftext|>


<commit_before>#![no_std]

//! The `array-vec` crate allows you to initialize arrays
//! with an initializer closure that will be called
//! once for each element until the array is filled.
//!
//! This way you do not need to default-fill an array
//! before running initializers. Rust currently only
//! lets you either specify all initializers at once,
//! individually (`[a(), b(), c(), ...]`), or specify
//! one initializer for a `Copy` type (`[a(); N]`),
//! which will be called once with the result copied over.
//!
//! # Examples:
//! ```rust
//! # #![allow(unused)]
//! # extern crate array_init;
//!
//! // Initialize an array of length 10 containing
//! // successive squares
//!
//! let arr: [u32; 50] = array_init::array_init(|i| (i*i) as u32);
//!
//! // Initialize an array from an iterator
//! // producing an array of [1,2,3,4] repeated
//!
//! let four = [1u32,2,3,4];
//! let mut iter = four.iter().cloned().cycle();
//! let arr: [u32; 50] = array_init::from_iter(iter).unwrap();
//!
//! // Closures can also mutate state. We guarantee that they will be called
//! // in order from lower to higher indices.
//!
//! let mut last = 1u64;
//! let mut secondlast = 0;
//! let fibonacci: [u64; 50] = array_init::array_init(|_| {
//!     let this = last + secondlast;
//!     secondlast = last;
//!     last = this;
//!     this
//! });
//! ```
//!
//! Currently, using `from_iter` and `array_init` will incur additional
//! memcpys, which may be undesirable for a large array. This can be eliminated
//! by using the nightly feature of this crate, which uses unions to provide
//! panic-safety. Alternatively, if your array only contains `Copy` types,
//! you can use `array_init_copy` and `from_iter_copy`.
//!
//! Sadly, cannot guarantee right now that any of these solutions will completely
//! eliminate a memcpy.
//!

extern crate nodrop;

use nodrop::NoDrop;
use core::mem;

/// Trait for things which are actually arrays
///
/// Probably shouldn't implement this yourself,
/// but you can
pub unsafe trait IsArray {
    type Item;
    /// Must assume self is uninitialized.
    fn set(&mut self, idx: usize, value: Self::Item);
    fn len() -> usize;
}

#[inline]
/// Initialize an array given an initializer expression
///
/// The initializer is given the index of the element. It is allowed
/// to mutate external state; we will always initialize the elements in order.
///
/// Without the nightly feature it is very likely that this will cause memcpys.
/// For panic safety, we internally use NoDrop, which will ensure that panics
/// in the initializer will not cause the array to be prematurely dropped.
/// If you are using a Copy type, prefer using `array_init_copy` since
/// it does not need the panic safety stuff and is more likely to have no
/// memcpys.
///
/// # Examples
///
/// ```rust
/// # #![allow(unused)]
/// # extern crate array_init;
///
/// // Initialize an array of length 10 containing
/// // successive squares
///
/// let arr: [u32; 50] = array_init::array_init(|i| (i*i) as u32);
///
/// // Initialize an array from an iterator
/// // producing an array of [1,2,3,4] repeated
///
/// let four = [1u32,2,3,4];
/// let mut iter = four.iter().cloned().cycle();
/// let arr: [u32; 50] = array_init::from_iter(iter).unwrap();
///
/// ```
///
pub fn array_init<Array, F>(mut initializer: F) -> Array where Array: IsArray,
                                                               F: FnMut(usize) -> Array::Item {
    // NoDrop makes this panic-safe
    // We are sure to initialize the whole array here,
    // and we do not read from the array till then, so this is safe.
    let mut ret: NoDrop<Array> = NoDrop::new(unsafe { mem::uninitialized() });
    for i in 0..Array::len() {
        Array::set(&mut ret, i, initializer(i));
    }
    ret.into_inner()
}

#[inline]
/// Initialize an array given an iterator
///
/// We will iterate until the array is full or the iterator is exhausted. Returns
/// None if the iterator is exhausted before we can fill the array.
///
/// Without the nightly feature it is very likely that this will cause memcpys.
/// For panic safety, we internally use NoDrop, which will ensure that panics
/// in the initializer will not cause the array to be prematurely dropped.
/// If you are using a Copy type, prefer using `from_iter_copy` since
/// it does not need the panic safety stuff and is more likely to have no
/// memcpys.
///
/// # Examples
///
/// ```rust
/// # #![allow(unused)]
/// # extern crate array_init;
///
/// // Initialize an array from an iterator
/// // producing an array of [1,2,3,4] repeated
///
/// let four = [1u32,2,3,4];
/// let mut iter = four.iter().cloned().cycle();
/// let arr: [u32; 50] = array_init::from_iter_copy(iter).unwrap();
/// ```
///
pub fn from_iter<Array, I>(iter: I) -> Option<Array>
    where I: IntoIterator<Item = Array::Item>,
          Array: IsArray {
    // NoDrop makes this panic-safe
    // We are sure to initialize the whole array here,
    // and we do not read from the array till then, so this is safe.
    let mut ret: NoDrop<Array> = NoDrop::new(unsafe { mem::uninitialized() });
    let mut count = 0;
    for item in iter.into_iter().take(Array::len()) {
        Array::set(&mut ret, count, item);
        count += 1;
    }
    // crucial for safety!
    if count == Array::len() {
        Some(ret.into_inner())
    } else {
        None
    }
}

#[inline]
/// Initialize an array of `Copy` elements given an initializer expression
///
/// The initializer is given the index of the element. It is allowed
/// to mutate external state; we will always initialize the elements in order.
///
/// This is preferred over `array_init` if you have a `Copy` type
///
/// # Examples
///
/// ```rust
/// # #![allow(unused)]
/// # extern crate array_init;
///
/// // Initialize an array of length 10 containing
/// // successive squares
///
/// let arr: [u32; 50] = array_init::array_init_copy(|i| (i*i) as u32);
///
///
/// // Closures can also mutate state. We guarantee that they will be called
/// // in order from lower to higher indices.
///
/// let mut last = 1u64;
/// let mut secondlast = 0;
/// let fibonacci: [u64; 50] = array_init::array_init_copy(|_| {
///     let this = last + secondlast;
///     secondlast = last;
///     last = this;
///     this
/// });
/// ```
///
pub fn array_init_copy<Array, F>(mut initializer: F) -> Array where Array: IsArray,
                                                                    F: FnMut(usize) -> Array::Item,
                                                                    Array::Item : Copy {
    // We are sure to initialize the whole array here,
    // and we do not read from the array till then, so this is safe.
    let mut ret: Array = unsafe { mem::uninitialized() };
    for i in 0..Array::len() {
        Array::set(&mut ret, i, initializer(i));
    }
    ret
}

#[inline]
/// Initialize an array given an iterator
///
/// We will iterate until the array is full or the iterator is exhausted. Returns
/// None if the iterator is exhausted before we can fill the array.
///
/// This is preferred over `from_iter_copy` if you have a `Copy` type
///
/// # Examples
///
/// ```rust
/// # #![allow(unused)]
/// # extern crate array_init;
///
/// // Initialize an array from an iterator
/// // producing an array of [1,2,3,4] repeated
///
/// let four = [1u32,2,3,4];
/// let mut iter = four.iter().cloned().cycle();
/// let arr: [u32; 50] = array_init::from_iter_copy(iter).unwrap();
/// ```
pub fn from_iter_copy<Array, I>(iter: I) -> Option<Array>
    where I: IntoIterator<Item = Array::Item>,
          Array: IsArray,
          Array::Item : Copy {
    // We are sure to initialize the whole array here,
    // and we do not read from the array till then, so this is safe.
    let mut ret: Array = unsafe { mem::uninitialized() };
    let mut count = 0;
    for item in iter.into_iter().take(Array::len()) {
        Array::set(&mut ret, count, item);
        count += 1;
    }
    // crucial for safety!
    if count == Array::len() {
        Some(ret)
    } else {
        None
    }
}

macro_rules! impl_is_array {
    ($($size:expr)+) => ($(
        unsafe impl<T> IsArray for [T; $size] {
            type Item = T;
            #[inline]
            fn set(&mut self, idx: usize, value: Self::Item) {
                mem::forget(mem::replace(&mut self[idx], value));
            }

            #[inline]
            fn len() -> usize {
                $size
            }
        }
    )+)
}

// lol

impl_is_array! {
     0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
    16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
    32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
    48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
    64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
    80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
    96 97 98 99 100 101 102 103 104 105 106 107 108
    109 110 111 112 113 114 115 116 117 118 119 120
    121 122 123 124 125 126 127 128
}
<commit_msg>document panics (fixes #10)<commit_after>#![no_std]

//! The `array-vec` crate allows you to initialize arrays
//! with an initializer closure that will be called
//! once for each element until the array is filled.
//!
//! This way you do not need to default-fill an array
//! before running initializers. Rust currently only
//! lets you either specify all initializers at once,
//! individually (`[a(), b(), c(), ...]`), or specify
//! one initializer for a `Copy` type (`[a(); N]`),
//! which will be called once with the result copied over.
//!
//! # Examples:
//! ```rust
//! # #![allow(unused)]
//! # extern crate array_init;
//!
//! // Initialize an array of length 10 containing
//! // successive squares
//!
//! let arr: [u32; 50] = array_init::array_init(|i| (i*i) as u32);
//!
//! // Initialize an array from an iterator
//! // producing an array of [1,2,3,4] repeated
//!
//! let four = [1u32,2,3,4];
//! let mut iter = four.iter().cloned().cycle();
//! let arr: [u32; 50] = array_init::from_iter(iter).unwrap();
//!
//! // Closures can also mutate state. We guarantee that they will be called
//! // in order from lower to higher indices.
//!
//! let mut last = 1u64;
//! let mut secondlast = 0;
//! let fibonacci: [u64; 50] = array_init::array_init(|_| {
//!     let this = last + secondlast;
//!     secondlast = last;
//!     last = this;
//!     this
//! });
//! ```
//!
//! Currently, using `from_iter` and `array_init` will incur additional
//! memcpys, which may be undesirable for a large array. This can be eliminated
//! by using the nightly feature of this crate, which uses unions to provide
//! panic-safety. Alternatively, if your array only contains `Copy` types,
//! you can use `array_init_copy` and `from_iter_copy`.
//!
//! Sadly, cannot guarantee right now that any of these solutions will completely
//! eliminate a memcpy.
//!

extern crate nodrop;

use nodrop::NoDrop;
use core::mem;

/// Trait for things which are actually arrays
///
/// Probably shouldn't implement this yourself,
/// but you can
pub unsafe trait IsArray {
    type Item;
    /// Must assume self is uninitialized.
    fn set(&mut self, idx: usize, value: Self::Item);
    fn len() -> usize;
}

#[inline]
/// Initialize an array given an initializer expression
///
/// The initializer is given the index of the element. It is allowed
/// to mutate external state; we will always initialize the elements in order.
///
/// Without the nightly feature it is very likely that this will cause memcpys.
/// For panic safety, we internally use NoDrop, which will ensure that panics
/// in the initializer will not cause the array to be prematurely dropped.
/// If you are using a Copy type, prefer using `array_init_copy` since
/// it does not need the panic safety stuff and is more likely to have no
/// memcpys.
///
/// If your initializer panics, any elements that have been initialized
/// will be leaked.
///
/// # Examples
///
/// ```rust
/// # #![allow(unused)]
/// # extern crate array_init;
///
/// // Initialize an array of length 10 containing
/// // successive squares
///
/// let arr: [u32; 50] = array_init::array_init(|i| (i*i) as u32);
///
/// // Initialize an array from an iterator
/// // producing an array of [1,2,3,4] repeated
///
/// let four = [1u32,2,3,4];
/// let mut iter = four.iter().cloned().cycle();
/// let arr: [u32; 50] = array_init::from_iter(iter).unwrap();
///
/// ```
///
pub fn array_init<Array, F>(mut initializer: F) -> Array where Array: IsArray,
                                                               F: FnMut(usize) -> Array::Item {
    // NoDrop makes this panic-safe
    // We are sure to initialize the whole array here,
    // and we do not read from the array till then, so this is safe.
    let mut ret: NoDrop<Array> = NoDrop::new(unsafe { mem::uninitialized() });
    for i in 0..Array::len() {
        Array::set(&mut ret, i, initializer(i));
    }
    ret.into_inner()
}

#[inline]
/// Initialize an array given an iterator
///
/// We will iterate until the array is full or the iterator is exhausted. Returns
/// None if the iterator is exhausted before we can fill the array.
///
/// Without the nightly feature it is very likely that this will cause memcpys.
/// For panic safety, we internally use NoDrop, which will ensure that panics
/// in the initializer will not cause the array to be prematurely dropped.
/// If you are using a Copy type, prefer using `from_iter_copy` since
/// it does not need the panic safety stuff and is more likely to have no
/// memcpys.
///
/// # Examples
///
/// ```rust
/// # #![allow(unused)]
/// # extern crate array_init;
///
/// // Initialize an array from an iterator
/// // producing an array of [1,2,3,4] repeated
///
/// let four = [1u32,2,3,4];
/// let mut iter = four.iter().cloned().cycle();
/// let arr: [u32; 50] = array_init::from_iter_copy(iter).unwrap();
/// ```
///
pub fn from_iter<Array, I>(iter: I) -> Option<Array>
    where I: IntoIterator<Item = Array::Item>,
          Array: IsArray {
    // NoDrop makes this panic-safe
    // We are sure to initialize the whole array here,
    // and we do not read from the array till then, so this is safe.
    let mut ret: NoDrop<Array> = NoDrop::new(unsafe { mem::uninitialized() });
    let mut count = 0;
    for item in iter.into_iter().take(Array::len()) {
        Array::set(&mut ret, count, item);
        count += 1;
    }
    // crucial for safety!
    if count == Array::len() {
        Some(ret.into_inner())
    } else {
        None
    }
}

#[inline]
/// Initialize an array of `Copy` elements given an initializer expression
///
/// The initializer is given the index of the element. It is allowed
/// to mutate external state; we will always initialize the elements in order.
///
/// This is preferred over `array_init` if you have a `Copy` type
///
/// # Examples
///
/// ```rust
/// # #![allow(unused)]
/// # extern crate array_init;
///
/// // Initialize an array of length 10 containing
/// // successive squares
///
/// let arr: [u32; 50] = array_init::array_init_copy(|i| (i*i) as u32);
///
///
/// // Closures can also mutate state. We guarantee that they will be called
/// // in order from lower to higher indices.
///
/// let mut last = 1u64;
/// let mut secondlast = 0;
/// let fibonacci: [u64; 50] = array_init::array_init_copy(|_| {
///     let this = last + secondlast;
///     secondlast = last;
///     last = this;
///     this
/// });
/// ```
///
pub fn array_init_copy<Array, F>(mut initializer: F) -> Array where Array: IsArray,
                                                                    F: FnMut(usize) -> Array::Item,
                                                                    Array::Item : Copy {
    // We are sure to initialize the whole array here,
    // and we do not read from the array till then, so this is safe.
    let mut ret: Array = unsafe { mem::uninitialized() };
    for i in 0..Array::len() {
        Array::set(&mut ret, i, initializer(i));
    }
    ret
}

#[inline]
/// Initialize an array given an iterator
///
/// We will iterate until the array is full or the iterator is exhausted. Returns
/// None if the iterator is exhausted before we can fill the array.
///
/// This is preferred over `from_iter_copy` if you have a `Copy` type
///
/// # Examples
///
/// ```rust
/// # #![allow(unused)]
/// # extern crate array_init;
///
/// // Initialize an array from an iterator
/// // producing an array of [1,2,3,4] repeated
///
/// let four = [1u32,2,3,4];
/// let mut iter = four.iter().cloned().cycle();
/// let arr: [u32; 50] = array_init::from_iter_copy(iter).unwrap();
/// ```
pub fn from_iter_copy<Array, I>(iter: I) -> Option<Array>
    where I: IntoIterator<Item = Array::Item>,
          Array: IsArray,
          Array::Item : Copy {
    // We are sure to initialize the whole array here,
    // and we do not read from the array till then, so this is safe.
    let mut ret: Array = unsafe { mem::uninitialized() };
    let mut count = 0;
    for item in iter.into_iter().take(Array::len()) {
        Array::set(&mut ret, count, item);
        count += 1;
    }
    // crucial for safety!
    if count == Array::len() {
        Some(ret)
    } else {
        None
    }
}

macro_rules! impl_is_array {
    ($($size:expr)+) => ($(
        unsafe impl<T> IsArray for [T; $size] {
            type Item = T;
            #[inline]
            fn set(&mut self, idx: usize, value: Self::Item) {
                mem::forget(mem::replace(&mut self[idx], value));
            }

            #[inline]
            fn len() -> usize {
                $size
            }
        }
    )+)
}

// lol

impl_is_array! {
     0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
    16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
    32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
    48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
    64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
    80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
    96 97 98 99 100 101 102 103 104 105 106 107 108
    109 110 111 112 113 114 115 116 117 118 119 120
    121 122 123 124 125 126 127 128
}
<|endoftext|>


<commit_before>use std::io::{Read, Error};

#[derive(Debug)]
struct Bom ( u8, u8, u8, u8 );

#[derive(Clone,Debug,PartialEq,Eq)]
enum Flavour {
    UCS,
    UTF,
    EBCDIC,
    ASCII,
    Unknown,
}

#[derive(Clone,Debug,PartialEq,Eq)]
enum ByteOrder {
    BigEndian,
    LittleEndian,
    Unusual2143,
    Unusual3412,
    NotApplicable
}

#[derive(Clone,Debug,PartialEq,Eq)]
enum Width {
    EightBit     = 8,
    SixteenBit   = 16,
    ThirtyTwoBit = 32
}

#[derive(Clone,Debug,PartialEq,Eq)]
struct Descriptor (Flavour, Width, ByteOrder);

// 32-Bit Encodings
const UCS_4_BE: Descriptor = Descriptor(Flavour::UCS, Width::ThirtyTwoBit, ByteOrder::BigEndian);
const UCS_4_LE: Descriptor = Descriptor(Flavour::UCS, Width::ThirtyTwoBit, ByteOrder::LittleEndian);
const UCS_4_2143: Descriptor = Descriptor(Flavour::UCS, Width::ThirtyTwoBit, ByteOrder::Unusual2143);
const UCS_4_3412: Descriptor = Descriptor(Flavour::UCS, Width::ThirtyTwoBit, ByteOrder::Unusual3412);

// 16-Bit Encodings
const UTF_16_BE: Descriptor = Descriptor(Flavour::UTF, Width::SixteenBit, ByteOrder::BigEndian);
const UTF_16_LE: Descriptor = Descriptor(Flavour::UTF, Width::SixteenBit, ByteOrder::LittleEndian);

const UTF_8: Descriptor = Descriptor(Flavour::UTF, Width::EightBit, ByteOrder::NotApplicable);
const EBCDIC: Descriptor = Descriptor(Flavour::EBCDIC, Width::EightBit, ByteOrder::NotApplicable);

// ASCII compatible encodings
const ASCII_32BIT_BE: Descriptor = Descriptor(Flavour::Unknown, Width::ThirtyTwoBit, ByteOrder::BigEndian);
const ASCII_32BIT_LE: Descriptor = Descriptor(Flavour::Unknown, Width::ThirtyTwoBit, ByteOrder::LittleEndian);
const ASCII_16BIT_BE: Descriptor = Descriptor(Flavour::Unknown, Width::SixteenBit, ByteOrder::BigEndian);
const ASCII_16BIT_LE: Descriptor = Descriptor(Flavour::Unknown, Width::SixteenBit, ByteOrder::LittleEndian);
const ASCII_8BIT: Descriptor = Descriptor(Flavour::ASCII, Width::EightBit, ByteOrder::NotApplicable);

/// Attempt to detect the character set of the supplied byte stream.
///
/// `reader` is expected to be positioned at the start of the stream. `detect` will read up to 512
/// bytes in order to determine the encoding.
///
/// The optional `hint` is a possible encoding name for the text that may have been received
/// externally to the text itself, such as from HTTP header.
///
/// ### Example
///
/// ```
/// use std::io::Cursor;
/// extern crate xhtmlchardet;
///
/// let text = b"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><channel><title>Example</title></channel>";
/// let mut text_cursor = Cursor::new(text.to_vec());
/// let detected_charsets = xhtmlchardet::detect(&mut text_cursor, None);
/// assert_eq!(detected_charsets.unwrap_or(vec![]), vec!["iso-8859-1".to_string()]);
/// ```
pub fn detect<R: Read>(reader: &mut R, hint: Option<String>) -> Result<Vec<String>, Error> {
    // Read the first 4 bytes and see if they help
    let mut first_four_bytes = [0u8; 4];
    try!(reader.read(&mut first_four_bytes));

    let bom = Bom(
        first_four_bytes[0],
        first_four_bytes[1],
        first_four_bytes[2],
        first_four_bytes[3]
    );

    let possible = detect_byte_order_mark(&bom);

    // Now that byte size may have been determined try reading the first 512ish bytes to read an
    // encoding declaration
    let mut buf = [0u8; 512];
    try!(reader.read(&mut buf));

    let mut candidates = Vec::with_capacity(3);

    // Look for encoding="", charset="?"?
    search("encoding=", &buf.to_vec(), possible.as_ref())
        .or_else(|| search("charset=", &buf.to_vec(), possible.as_ref()))
        .map(|encoding| normalise(&encoding))
        .map(|encoding| push_if_not_contains(&mut candidates, endianify(&encoding, possible.as_ref())));

    // Consider hint
    hint.map(|hint| normalise(&hint))
        .map(|encoding| push_if_not_contains(&mut candidates, endianify(&encoding, possible.as_ref())));

    // Include info from BOM detection
    match possible {
        Some(UCS_4_LE) => Some("ucs-4le"),
        Some(UCS_4_BE) => Some("ucs-4be"),
        Some(UTF_16_LE) => Some("utf-16le"),
        Some(UTF_16_BE) => Some("utf-16be"),
        Some(Descriptor(Flavour::UTF, Width::EightBit, _)) => Some("utf-8"),
        Some(EBCDIC) => Some("ebcdic"),
        _ => None
    }.map(|encoding| push_if_not_contains(&mut candidates, encoding.to_string()));

    // Otherwise test if UTF-8
    if candidates.is_empty() && String::from_utf8(buf.to_vec()).is_ok() {
        candidates.push("utf-8".to_string());
    }

    return Ok(candidates);
}

fn detect_byte_order_mark(bom: &Bom) -> Option<Descriptor> {
    // Can do below without the Bom type if slice pattern syntax becomes non-experimental
    // let possible = match first_four_bytes {
    //     // With Byte Order Mark
    //     [0x00, 0x00, 0xFE, 0xFF]             => Some("UCS-4BE"),
    //     [0xFF, 0xFE, 0x00, 0x00]             => Some("UCS-4LE"),
    //     [0x00, 0x00, 0xFF, 0xFE]             => Some("UCS-4OE"),
    //     [0xFE, 0xFF, 0x00, 0x00]             => Some("UCS-4EO"),
    //     [0xFE, 0xFF, c, d] if c > 0 && d > 0 => Some("UTF-16BE"),
    //     [0xFF, 0xFE, c, d] if c > 0 && d > 0 => Some("UCS-16LE"),
    //     [0xEF, 0xBB, 0xBF, _   ]             => Some("UTF-8"),

    //     //  Without Byte Order Mark
    //     [0x00, 0x00, 0x00, 0x3C] |
    //     [0x3C, 0x00, 0x00, 0x00] |
    //     [0x00, 0x00, 0x3C, 0x00] |
    //     [0x00, 0x3C, 0x00, 0x00]             => Some("32-bit"),
    //     [0x00, 0x3C, 0x00, 0x3F]             => Some("16-bit Big Endian"),
    //     [0x3C, 0x00, 0x3F, 0x00]             => Some("16-bit Little Endian"),
    //     [0x3C, 0x3F, 0x78, 0x6D]             => Some("8-bit"),
    //     [0x4C, 0x6F, 0xA7, 0x94]             => Some("EBCDIC"),
    //     // This may be UTF-8 without an encoding declaration as this is not required
    //     // for UTF-8
    //     _                                    => Some("Other"),
    // };

    // http://www.w3.org/TR/2004/REC-xml-20040204/#sec-guessing-no-ext-info
    match *bom {
        // With Byte Order Mark
        Bom(0x00, 0x00, 0xFE, 0xFF)                   => Some(UCS_4_BE),
        Bom(0xFF, 0xFE, 0x00, 0x00)                   => Some(UCS_4_LE),
        Bom(0x00, 0x00, 0xFF, 0xFE)                   => Some(UCS_4_2143),
        Bom(0xFE, 0xFF, 0x00, 0x00)                   => Some(UCS_4_3412),
        Bom(0xFE, 0xFF, c   , d   ) if c > 0 || d > 0 => Some(UTF_16_BE),
        Bom(0xFF, 0xFE, c   , d   ) if c > 0 || d > 0 => Some(UTF_16_LE),
        Bom(0xEF, 0xBB, 0xBF, _   )                   => Some(UTF_8),

        //  Without Byte Order Mark
        Bom(0x00, 0x00, 0x00, 0x3C)                   => Some(ASCII_32BIT_BE),
        Bom(0x3C, 0x00, 0x00, 0x00)                   => Some(ASCII_32BIT_LE),
        Bom(0x00, 0x00, 0x3C, 0x00)                   => Some(Descriptor(Flavour::Unknown, Width::ThirtyTwoBit, ByteOrder::Unusual2143)),
        Bom(0x00, 0x3C, 0x00, 0x00)                   => Some(Descriptor(Flavour::Unknown, Width::ThirtyTwoBit, ByteOrder::Unusual3412)),
        Bom(0x00, 0x3C, 0x00, 0x3F)                   => Some(ASCII_16BIT_BE),
        Bom(0x3C, 0x00, 0x3F, 0x00)                   => Some(ASCII_16BIT_LE),
        Bom(0x3C, 0x3F, 0x78, 0x6D)                   => Some(ASCII_8BIT),
        Bom(0x4C, 0x6F, 0xA7, 0x94)                   => Some(EBCDIC),
        // This may be UTF-8 without an encoding declaration as this is not required
        // for UTF-8
        _                                             => None,
    }
}

fn normalise(encoding: &String) -> String {
    encoding.to_lowercase()
        .replace("us-ascii", "ascii")
        .replace("utf8", "utf-8")
        .replace("shift-jis", "shift_jis")
}

fn push_if_not_contains<T: PartialEq>(vec: &mut Vec<T>, item: T) {
    if !vec.contains(&item) {
        vec.push(item);
    }
}

fn endianify(encoding: &str, descriptor: Option<&Descriptor>) -> String {
    let ascii = ASCII_8BIT;
    let &Descriptor(_, _, ref order) = descriptor.unwrap_or(&ascii);

    match encoding {
        "utf-16" => {
            match *order {
                ByteOrder::LittleEndian => "utf-16le".to_string(),
                ByteOrder::BigEndian    => "utf-16be".to_string(),
                _ => encoding.to_string()
            }
        },
        _ => encoding.to_string()
    }
}

fn search(needle: &str, haystack: &Vec<u8>, descriptor: Option<&Descriptor>) -> Option<String> {
    let ascii = ASCII_8BIT;
    let &Descriptor(_, ref width, ref order) = descriptor.unwrap_or(&ascii);
    let chunk_size = (width.clone() as usize) / 8;

    let mut index = match *order {
        ByteOrder::NotApplicable | ByteOrder::LittleEndian  => 0,
        ByteOrder::BigEndian => chunk_size - 1,
        ByteOrder::Unusual2143 => 2,
        ByteOrder::Unusual3412 => 1,
    };

    let mut ascii_bytes = Vec::with_capacity(haystack.len() / chunk_size);
    while index < haystack.len() {
        ascii_bytes.push(haystack[index]);
        index += chunk_size;
    }

    let ascii_haystack = String::from_utf8_lossy(&ascii_bytes);

    ascii_haystack.find(needle).map(|pos| {
        // Skip to the matching byte + length of the needle
        ascii_haystack[pos + needle.len()..].chars()
            .skip_while(|char| *char == '"' || *char == '\'')
            .take_while(|char| *char != '"' && *char != '\'').collect()
    })
}

<commit_msg>Rename possible -> possible_encoding<commit_after>use std::io::{Read, Error};

#[derive(Debug)]
struct Bom ( u8, u8, u8, u8 );

#[derive(Clone,Debug,PartialEq,Eq)]
enum Flavour {
    UCS,
    UTF,
    EBCDIC,
    ASCII,
    Unknown,
}

#[derive(Clone,Debug,PartialEq,Eq)]
enum ByteOrder {
    BigEndian,
    LittleEndian,
    Unusual2143,
    Unusual3412,
    NotApplicable
}

#[derive(Clone,Debug,PartialEq,Eq)]
enum Width {
    EightBit     = 8,
    SixteenBit   = 16,
    ThirtyTwoBit = 32
}

#[derive(Clone,Debug,PartialEq,Eq)]
struct Descriptor (Flavour, Width, ByteOrder);

// 32-Bit Encodings
const UCS_4_BE: Descriptor = Descriptor(Flavour::UCS, Width::ThirtyTwoBit, ByteOrder::BigEndian);
const UCS_4_LE: Descriptor = Descriptor(Flavour::UCS, Width::ThirtyTwoBit, ByteOrder::LittleEndian);
const UCS_4_2143: Descriptor = Descriptor(Flavour::UCS, Width::ThirtyTwoBit, ByteOrder::Unusual2143);
const UCS_4_3412: Descriptor = Descriptor(Flavour::UCS, Width::ThirtyTwoBit, ByteOrder::Unusual3412);

// 16-Bit Encodings
const UTF_16_BE: Descriptor = Descriptor(Flavour::UTF, Width::SixteenBit, ByteOrder::BigEndian);
const UTF_16_LE: Descriptor = Descriptor(Flavour::UTF, Width::SixteenBit, ByteOrder::LittleEndian);

const UTF_8: Descriptor = Descriptor(Flavour::UTF, Width::EightBit, ByteOrder::NotApplicable);
const EBCDIC: Descriptor = Descriptor(Flavour::EBCDIC, Width::EightBit, ByteOrder::NotApplicable);

// ASCII compatible encodings
const ASCII_32BIT_BE: Descriptor = Descriptor(Flavour::Unknown, Width::ThirtyTwoBit, ByteOrder::BigEndian);
const ASCII_32BIT_LE: Descriptor = Descriptor(Flavour::Unknown, Width::ThirtyTwoBit, ByteOrder::LittleEndian);
const ASCII_16BIT_BE: Descriptor = Descriptor(Flavour::Unknown, Width::SixteenBit, ByteOrder::BigEndian);
const ASCII_16BIT_LE: Descriptor = Descriptor(Flavour::Unknown, Width::SixteenBit, ByteOrder::LittleEndian);
const ASCII_8BIT: Descriptor = Descriptor(Flavour::ASCII, Width::EightBit, ByteOrder::NotApplicable);

/// Attempt to detect the character set of the supplied byte stream.
///
/// `reader` is expected to be positioned at the start of the stream. `detect` will read up to 512
/// bytes in order to determine the encoding.
///
/// The optional `hint` is a possible encoding name for the text that may have been received
/// externally to the text itself, such as from HTTP header.
///
/// ### Example
///
/// ```
/// use std::io::Cursor;
/// extern crate xhtmlchardet;
///
/// let text = b"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><channel><title>Example</title></channel>";
/// let mut text_cursor = Cursor::new(text.to_vec());
/// let detected_charsets = xhtmlchardet::detect(&mut text_cursor, None);
/// assert_eq!(detected_charsets.unwrap_or(vec![]), vec!["iso-8859-1".to_string()]);
/// ```
pub fn detect<R: Read>(reader: &mut R, hint: Option<String>) -> Result<Vec<String>, Error> {
    // Read the first 4 bytes and see if they help
    let mut first_four_bytes = [0u8; 4];
    try!(reader.read(&mut first_four_bytes));

    let bom = Bom(
        first_four_bytes[0],
        first_four_bytes[1],
        first_four_bytes[2],
        first_four_bytes[3]
    );

    let possible_encoding = detect_byte_order_mark(&bom);

    // Now that byte size may have been determined try reading the first 512ish bytes to read an
    // encoding declaration
    let mut buf = [0u8; 512];
    try!(reader.read(&mut buf));

    let mut candidates = Vec::with_capacity(3);

    // Look for encoding="", charset="?"?
        .map(|encoding| normalise(&encoding))
    search("encoding=", &buf.to_vec(), possible_encoding.as_ref())
        .or_else(|| search("charset=", &buf.to_vec(), possible_encoding.as_ref()))
        .map(|encoding| push_if_not_contains(&mut candidates, endianify(&encoding, possible_encoding.as_ref())));

    // Consider hint
    hint.map(|hint| normalise(&hint))
        .map(|encoding| push_if_not_contains(&mut candidates, endianify(&encoding, possible_encoding.as_ref())));

    // Include info from BOM detection
    match possible_encoding {
        Some(UCS_4_LE) => Some("ucs-4le"),
        Some(UCS_4_BE) => Some("ucs-4be"),
        Some(UTF_16_LE) => Some("utf-16le"),
        Some(UTF_16_BE) => Some("utf-16be"),
        Some(Descriptor(Flavour::UTF, Width::EightBit, _)) => Some("utf-8"),
        Some(EBCDIC) => Some("ebcdic"),
        _ => None
    }.map(|encoding| push_if_not_contains(&mut candidates, encoding.to_string()));

    // Otherwise test if UTF-8
    if candidates.is_empty() && String::from_utf8(buf.to_vec()).is_ok() {
        candidates.push("utf-8".to_string());
    }

    return Ok(candidates);
}

fn detect_byte_order_mark(bom: &Bom) -> Option<Descriptor> {
    // Can do below without the Bom type if slice pattern syntax becomes non-experimental
    // let possible = match first_four_bytes {
    //     // With Byte Order Mark
    //     [0x00, 0x00, 0xFE, 0xFF]             => Some("UCS-4BE"),
    //     [0xFF, 0xFE, 0x00, 0x00]             => Some("UCS-4LE"),
    //     [0x00, 0x00, 0xFF, 0xFE]             => Some("UCS-4OE"),
    //     [0xFE, 0xFF, 0x00, 0x00]             => Some("UCS-4EO"),
    //     [0xFE, 0xFF, c, d] if c > 0 && d > 0 => Some("UTF-16BE"),
    //     [0xFF, 0xFE, c, d] if c > 0 && d > 0 => Some("UCS-16LE"),
    //     [0xEF, 0xBB, 0xBF, _   ]             => Some("UTF-8"),

    //     //  Without Byte Order Mark
    //     [0x00, 0x00, 0x00, 0x3C] |
    //     [0x3C, 0x00, 0x00, 0x00] |
    //     [0x00, 0x00, 0x3C, 0x00] |
    //     [0x00, 0x3C, 0x00, 0x00]             => Some("32-bit"),
    //     [0x00, 0x3C, 0x00, 0x3F]             => Some("16-bit Big Endian"),
    //     [0x3C, 0x00, 0x3F, 0x00]             => Some("16-bit Little Endian"),
    //     [0x3C, 0x3F, 0x78, 0x6D]             => Some("8-bit"),
    //     [0x4C, 0x6F, 0xA7, 0x94]             => Some("EBCDIC"),
    //     // This may be UTF-8 without an encoding declaration as this is not required
    //     // for UTF-8
    //     _                                    => Some("Other"),
    // };

    // http://www.w3.org/TR/2004/REC-xml-20040204/#sec-guessing-no-ext-info
    match *bom {
        // With Byte Order Mark
        Bom(0x00, 0x00, 0xFE, 0xFF)                   => Some(UCS_4_BE),
        Bom(0xFF, 0xFE, 0x00, 0x00)                   => Some(UCS_4_LE),
        Bom(0x00, 0x00, 0xFF, 0xFE)                   => Some(UCS_4_2143),
        Bom(0xFE, 0xFF, 0x00, 0x00)                   => Some(UCS_4_3412),
        Bom(0xFE, 0xFF, c   , d   ) if c > 0 || d > 0 => Some(UTF_16_BE),
        Bom(0xFF, 0xFE, c   , d   ) if c > 0 || d > 0 => Some(UTF_16_LE),
        Bom(0xEF, 0xBB, 0xBF, _   )                   => Some(UTF_8),

        //  Without Byte Order Mark
        Bom(0x00, 0x00, 0x00, 0x3C)                   => Some(ASCII_32BIT_BE),
        Bom(0x3C, 0x00, 0x00, 0x00)                   => Some(ASCII_32BIT_LE),
        Bom(0x00, 0x00, 0x3C, 0x00)                   => Some(Descriptor(Flavour::Unknown, Width::ThirtyTwoBit, ByteOrder::Unusual2143)),
        Bom(0x00, 0x3C, 0x00, 0x00)                   => Some(Descriptor(Flavour::Unknown, Width::ThirtyTwoBit, ByteOrder::Unusual3412)),
        Bom(0x00, 0x3C, 0x00, 0x3F)                   => Some(ASCII_16BIT_BE),
        Bom(0x3C, 0x00, 0x3F, 0x00)                   => Some(ASCII_16BIT_LE),
        Bom(0x3C, 0x3F, 0x78, 0x6D)                   => Some(ASCII_8BIT),
        Bom(0x4C, 0x6F, 0xA7, 0x94)                   => Some(EBCDIC),
        // This may be UTF-8 without an encoding declaration as this is not required
        // for UTF-8
        _                                             => None,
    }
}

fn normalise(encoding: &String) -> String {
    encoding.to_lowercase()
        .replace("us-ascii", "ascii")
        .replace("utf8", "utf-8")
        .replace("shift-jis", "shift_jis")
}

fn push_if_not_contains<T: PartialEq>(vec: &mut Vec<T>, item: T) {
    if !vec.contains(&item) {
        vec.push(item);
    }
}

fn endianify(encoding: &str, descriptor: Option<&Descriptor>) -> String {
    let ascii = ASCII_8BIT;
    let &Descriptor(_, _, ref order) = descriptor.unwrap_or(&ascii);

    match encoding {
        "utf-16" => {
            match *order {
                ByteOrder::LittleEndian => "utf-16le".to_string(),
                ByteOrder::BigEndian    => "utf-16be".to_string(),
                _ => encoding.to_string()
            }
        },
        _ => encoding.to_string()
    }
}

fn search(needle: &str, haystack: &Vec<u8>, descriptor: Option<&Descriptor>) -> Option<String> {
    let ascii = ASCII_8BIT;
    let &Descriptor(_, ref width, ref order) = descriptor.unwrap_or(&ascii);
    let chunk_size = (width.clone() as usize) / 8;

    let mut index = match *order {
        ByteOrder::NotApplicable | ByteOrder::LittleEndian  => 0,
        ByteOrder::BigEndian => chunk_size - 1,
        ByteOrder::Unusual2143 => 2,
        ByteOrder::Unusual3412 => 1,
    };

    let mut ascii_bytes = Vec::with_capacity(haystack.len() / chunk_size);
    while index < haystack.len() {
        ascii_bytes.push(haystack[index]);
        index += chunk_size;
    }

    let ascii_haystack = String::from_utf8_lossy(&ascii_bytes);

    ascii_haystack.find(needle).map(|pos| {
        // Skip to the matching byte + length of the needle
        ascii_haystack[pos + needle.len()..].chars()
            .skip_while(|char| *char == '"' || *char == '\'')
            .take_while(|char| *char != '"' && *char != '\'').collect()
    })
}

<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::slice::bytes::copy_memory;

static S: [u8, ..256] = [
    0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36, 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13,
    0x62, 0xA7, 0x05, 0xF3, 0xC0, 0xC7, 0x73, 0x8C, 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, 0x82, 0xCA,
    0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16, 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12,
    0xBE, 0x4E, 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E, 0xBB, 0x2F, 0xEE, 0x7A,
    0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, 0x07, 0x3F, 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21,
    0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E, 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03,
    0xFF, 0x19, 0x30, 0xB3, 0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56, 0xAA, 0xC6,
    0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6, 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1,
    0x45, 0x9D, 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65, 0xE6, 0x2D, 0xA8, 0x02,
    0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, 0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F,
    0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 0xC3, 0x5C, 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26,
    0x2C, 0x53, 0x0D, 0x6E, 0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, 0x4D, 0x52,
    0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A,
    0x78, 0x88, 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 0xE9, 0xCB, 0xD5, 0xFE, 0x3B, 0x00, 0x1D, 0x39,
    0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58, 0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A,
    0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99, 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14
];

static S2: [u8, ..256] = [
    0xDD, 0x07, 0x8F, 0x5F, 0x7E, 0x12, 0x0E, 0x46, 0xCB, 0xB7, 0xEF, 0x4C, 0xCC, 0xB2, 0xE3, 0x9F,
    0x4A, 0xFD, 0x2F, 0x0F, 0xFF, 0x44, 0x27, 0x2D, 0x2B, 0x61, 0xF7, 0x90, 0x98, 0xDE, 0x20, 0xF6,
    0x87, 0x4F, 0x4D, 0xA3, 0xC8, 0x92, 0xAF, 0x57, 0xB5, 0x00, 0x6B, 0x1A, 0xB0, 0x8D, 0x01, 0x3D,
    0x62, 0xF0, 0x56, 0xFB, 0x9C, 0x58, 0x09, 0xC2, 0x72, 0xDF, 0xA7, 0xDC, 0x23, 0x08, 0x59, 0x47,
    0x9D, 0xBC, 0x29, 0x02, 0xF1, 0x80, 0x99, 0xA1, 0x64, 0x37, 0xCF, 0xEE, 0x1D, 0xBE, 0x31, 0x70,
    0xF2, 0xA5, 0xBF, 0xB1, 0x0A, 0xA0, 0x6D, 0x22, 0xE5, 0x83, 0x54, 0x89, 0xA9, 0x52, 0x69, 0x4E,
    0x91, 0x9A, 0x10, 0xD5, 0x84, 0x8B, 0xE4, 0x28, 0x41, 0x9B, 0xC0, 0x7A, 0xC4, 0xD7, 0xB3, 0x2A,
    0x82, 0x85, 0xEA, 0x16, 0x7D, 0xED, 0x78, 0xE9, 0xD0, 0x42, 0x3F, 0xCA, 0x06, 0x76, 0x9E, 0x51,
    0x50, 0xBD, 0x1E, 0xFE, 0xB6, 0xB4, 0x88, 0x86, 0xD1, 0x4B, 0x2C, 0xD3, 0x17, 0xFA, 0x3B, 0xF4,
    0x55, 0x43, 0x6A, 0x19, 0x48, 0xD2, 0x74, 0x5E, 0x18, 0xF9, 0x53, 0x21, 0x7C, 0x81, 0x35, 0xFC,
    0x38, 0x0B, 0x04, 0xA2, 0x75, 0x65, 0xE8, 0x11, 0x8E, 0x40, 0x6E, 0xC6, 0x6C, 0x93, 0x94, 0xA6,
    0x95, 0xCE, 0x45, 0x63, 0xF3, 0x66, 0x77, 0xE2, 0x71, 0x96, 0xAC, 0x3C, 0x1C, 0xCD, 0x30, 0x5C,
    0x14, 0xC5, 0x49, 0xA8, 0x32, 0xAD, 0x6F, 0x15, 0xC3, 0x03, 0x1F, 0xD9, 0x5A, 0xBA, 0xAB, 0x8A,
    0xE6, 0x67, 0x73, 0xB8, 0x25, 0xDA, 0x33, 0x68, 0x05, 0x1B, 0x34, 0xF8, 0xC1, 0xA4, 0x36, 0xB9,
    0x26, 0xC9, 0x7B, 0xD4, 0xE7, 0x2E, 0x8C, 0x5B, 0xD6, 0xD8, 0xAE, 0xEC, 0x0C, 0xF5, 0x3E, 0xE1,
    0x0D, 0x7F, 0xE0, 0x13, 0xBB, 0x3A, 0x97, 0x5D, 0xEB, 0xAA, 0xC7, 0x39, 0x79, 0x24, 0xDB, 0x60
];

#[inline]
fn md2_pad(msg: &[u8]) -> Vec<u8> {
    let mut msg = msg.to_vec();
    let pad = 16 - msg.len() % 16;
    msg.grow_fn(pad, |_| pad as u8);
    msg
}

#[inline]
fn md2_checksum(msg: &[u8]) -> [u8, ..16] {
    let mut checksum = [0u8, ..16];
    let mut last = 0u8;

    for chunk in msg.chunks(16) {
        for (i, byte) in checksum.iter_mut().enumerate() {
            *byte ^= S[(chunk[i] ^ last) as uint];
            last = *byte;
        }
    }

    checksum
}

#[inline]
fn md2_compress(state: &[u8], msg: &[u8]) -> [u8, ..16] {
    // Two 128 bit blocks in, one 128 bit block out.
    assert!(state.len() == 16 && msg.len() == 16);

    let mut x = [0u8, ..48];
    let mut result = [0u8, ..16];

    // Copy over the previous state.
    copy_memory(x.slice_mut(0, 16), state);

    // Copy over the message block.
    copy_memory(x.slice_mut(16, 32), msg);

    // XOR the previous state and the message block.
    for (i, byte) in msg.iter().enumerate() {
        x[32 + i] = *byte ^ x[i];
    }

    // Encrypt block (18 rounds).
    let mut t = 0u8;
    for i in range(0, 18) {
        for byte in x.iter_mut() {
            *byte ^= S[t as uint];
            t = *byte;
        }
        t += i;
    }

    // Copy the new state.
    copy_memory(&mut result, x.slice(0, 16));
    result
}

pub fn md2(msg: &[u8]) -> [u8, ..16] {
    // Pad the message to be a multiple of 16 bytes long.
    let msg = md2_pad(msg);
    assert!(msg.len() % 16 == 0);

    // Compress all message blocks.
    let state = msg.chunks(16).fold([0u8, ..16], |s, m| md2_compress(&s, m));

    // Compute the checksum.
    let checksum = md2_checksum(msg.as_slice());

    // Compress checksum and return.
    md2_compress(&state, &checksum)
}

#[cfg(test)]
mod test {
    use md2;

    fn hex(buf: &[u8]) -> String {
        buf.iter().fold(String::new(), |a, &b| format!("{}{:02x}", a, b))
    }

    fn cmp(d: &str, s: &str) {
        assert_eq!(d.to_string(), hex(&md2(s.as_bytes())));
    }

    #[test]
    fn test_md2() {
        cmp("8350e5a3e24c153df2275c9f80692773", "");
        cmp("32ec01ec4a6dac72c0ab96fb34c0b5d1", "a");
        cmp("da853b0d3f88d99b30283a69e6ded6bb", "abc");
        cmp("ab4f496bfb2a530b219ff33031fe06b0", "message digest");
        cmp("4e8ddff3650292ab5a4108c3aa47940b", "abcdefghijklmnopqrstuvwxyz");
        cmp("da33def2a42df13975352846c30338cd", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
        cmp("d5976f79d83d3a0dc9806c3c66f3efd8", "12345678901234567890123456789012345678901234567890123456789012345678901234567890");
    }
}
<commit_msg>make lib public<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::slice::bytes::copy_memory;

pub static S: [u8, ..256] = [
    0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36, 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13,
    0x62, 0xA7, 0x05, 0xF3, 0xC0, 0xC7, 0x73, 0x8C, 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, 0x82, 0xCA,
    0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16, 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12,
    0xBE, 0x4E, 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E, 0xBB, 0x2F, 0xEE, 0x7A,
    0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, 0x07, 0x3F, 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21,
    0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E, 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03,
    0xFF, 0x19, 0x30, 0xB3, 0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56, 0xAA, 0xC6,
    0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6, 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1,
    0x45, 0x9D, 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65, 0xE6, 0x2D, 0xA8, 0x02,
    0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, 0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F,
    0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 0xC3, 0x5C, 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26,
    0x2C, 0x53, 0x0D, 0x6E, 0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, 0x4D, 0x52,
    0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A,
    0x78, 0x88, 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 0xE9, 0xCB, 0xD5, 0xFE, 0x3B, 0x00, 0x1D, 0x39,
    0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58, 0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A,
    0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99, 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14
];

pub static S2: [u8, ..256] = [
    0xDD, 0x07, 0x8F, 0x5F, 0x7E, 0x12, 0x0E, 0x46, 0xCB, 0xB7, 0xEF, 0x4C, 0xCC, 0xB2, 0xE3, 0x9F,
    0x4A, 0xFD, 0x2F, 0x0F, 0xFF, 0x44, 0x27, 0x2D, 0x2B, 0x61, 0xF7, 0x90, 0x98, 0xDE, 0x20, 0xF6,
    0x87, 0x4F, 0x4D, 0xA3, 0xC8, 0x92, 0xAF, 0x57, 0xB5, 0x00, 0x6B, 0x1A, 0xB0, 0x8D, 0x01, 0x3D,
    0x62, 0xF0, 0x56, 0xFB, 0x9C, 0x58, 0x09, 0xC2, 0x72, 0xDF, 0xA7, 0xDC, 0x23, 0x08, 0x59, 0x47,
    0x9D, 0xBC, 0x29, 0x02, 0xF1, 0x80, 0x99, 0xA1, 0x64, 0x37, 0xCF, 0xEE, 0x1D, 0xBE, 0x31, 0x70,
    0xF2, 0xA5, 0xBF, 0xB1, 0x0A, 0xA0, 0x6D, 0x22, 0xE5, 0x83, 0x54, 0x89, 0xA9, 0x52, 0x69, 0x4E,
    0x91, 0x9A, 0x10, 0xD5, 0x84, 0x8B, 0xE4, 0x28, 0x41, 0x9B, 0xC0, 0x7A, 0xC4, 0xD7, 0xB3, 0x2A,
    0x82, 0x85, 0xEA, 0x16, 0x7D, 0xED, 0x78, 0xE9, 0xD0, 0x42, 0x3F, 0xCA, 0x06, 0x76, 0x9E, 0x51,
    0x50, 0xBD, 0x1E, 0xFE, 0xB6, 0xB4, 0x88, 0x86, 0xD1, 0x4B, 0x2C, 0xD3, 0x17, 0xFA, 0x3B, 0xF4,
    0x55, 0x43, 0x6A, 0x19, 0x48, 0xD2, 0x74, 0x5E, 0x18, 0xF9, 0x53, 0x21, 0x7C, 0x81, 0x35, 0xFC,
    0x38, 0x0B, 0x04, 0xA2, 0x75, 0x65, 0xE8, 0x11, 0x8E, 0x40, 0x6E, 0xC6, 0x6C, 0x93, 0x94, 0xA6,
    0x95, 0xCE, 0x45, 0x63, 0xF3, 0x66, 0x77, 0xE2, 0x71, 0x96, 0xAC, 0x3C, 0x1C, 0xCD, 0x30, 0x5C,
    0x14, 0xC5, 0x49, 0xA8, 0x32, 0xAD, 0x6F, 0x15, 0xC3, 0x03, 0x1F, 0xD9, 0x5A, 0xBA, 0xAB, 0x8A,
    0xE6, 0x67, 0x73, 0xB8, 0x25, 0xDA, 0x33, 0x68, 0x05, 0x1B, 0x34, 0xF8, 0xC1, 0xA4, 0x36, 0xB9,
    0x26, 0xC9, 0x7B, 0xD4, 0xE7, 0x2E, 0x8C, 0x5B, 0xD6, 0xD8, 0xAE, 0xEC, 0x0C, 0xF5, 0x3E, 0xE1,
    0x0D, 0x7F, 0xE0, 0x13, 0xBB, 0x3A, 0x97, 0x5D, 0xEB, 0xAA, 0xC7, 0x39, 0x79, 0x24, 0xDB, 0x60
];

pub fn md2_pad(msg: &[u8]) -> Vec<u8> {
    let mut msg = msg.to_vec();
    let pad = 16 - msg.len() % 16;
    msg.grow_fn(pad, |_| pad as u8);
    msg
}

pub fn md2_checksum(msg: &[u8]) -> [u8, ..16] {
    let mut checksum = [0u8, ..16];
    let mut last = 0u8;

    for chunk in msg.chunks(16) {
        for (i, byte) in checksum.iter_mut().enumerate() {
            *byte ^= S[(chunk[i] ^ last) as uint];
            last = *byte;
        }
    }

    checksum
}

pub fn md2_compress(state: &[u8], msg: &[u8]) -> [u8, ..16] {
    // Two 128 bit blocks in, one 128 bit block out.
    assert!(state.len() == 16 && msg.len() == 16);

    let mut x = [0u8, ..48];
    let mut result = [0u8, ..16];

    // Copy over the previous state.
    copy_memory(x.slice_mut(0, 16), state);

    // Copy over the message block.
    copy_memory(x.slice_mut(16, 32), msg);

    // XOR the previous state and the message block.
    for (i, byte) in msg.iter().enumerate() {
        x[32 + i] = *byte ^ x[i];
    }

    // Encrypt block (18 rounds).
    let mut t = 0u8;
    for i in range(0, 18) {
        for byte in x.iter_mut() {
            *byte ^= S[t as uint];
            t = *byte;
        }
        t += i;
    }

    // Copy the new state.
    copy_memory(&mut result, x.slice(0, 16));
    result
}

pub fn md2(msg: &[u8]) -> [u8, ..16] {
    // Pad the message to be a multiple of 16 bytes long.
    let msg = md2_pad(msg);
    assert!(msg.len() % 16 == 0);

    // Compress all message blocks.
    let state = msg.chunks(16).fold([0u8, ..16], |s, m| md2_compress(&s, m));

    // Compute the checksum.
    let checksum = md2_checksum(msg.as_slice());

    // Compress checksum and return.
    md2_compress(&state, &checksum)
}

#[cfg(test)]
mod test {
    use md2;

    fn hex(buf: &[u8]) -> String {
        buf.iter().fold(String::new(), |a, &b| format!("{}{:02x}", a, b))
    }

    fn cmp(d: &str, s: &str) {
        assert_eq!(d.to_string(), hex(&md2(s.as_bytes())));
    }

    #[test]
    fn test_md2() {
        cmp("8350e5a3e24c153df2275c9f80692773", "");
        cmp("32ec01ec4a6dac72c0ab96fb34c0b5d1", "a");
        cmp("da853b0d3f88d99b30283a69e6ded6bb", "abc");
        cmp("ab4f496bfb2a530b219ff33031fe06b0", "message digest");
        cmp("4e8ddff3650292ab5a4108c3aa47940b", "abcdefghijklmnopqrstuvwxyz");
        cmp("da33def2a42df13975352846c30338cd", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
        cmp("d5976f79d83d3a0dc9806c3c66f3efd8", "12345678901234567890123456789012345678901234567890123456789012345678901234567890");
    }
}
<|endoftext|>