<commit_before>#![cfg(target_os = "windows")]

use std::mem;
use std::ptr;
use std::ffi::OsStr;
use std::os::windows::ffi::OsStrExt;
use std::sync::{
    Arc,
    Mutex
};
use std::sync::mpsc::Receiver;
use libc;
use ContextError;
use {CreationError, Event, MouseCursor};
use CursorState;
use GlAttributes;
use GlContext;

use Api;
use PixelFormat;
use PixelFormatRequirements;
use WindowAttributes;

pub use self::monitor::{MonitorID, get_available_monitors, get_primary_monitor};

use winapi;
use user32;
use kernel32;

use api::wgl::Context as WglContext;
use api::egl::Context as EglContext;
use api::egl::ffi::egl::Egl;

use self::init::RawContext;

mod callback;
mod event;
mod init;
mod monitor;

lazy_static! {
    static ref WAKEUP_MSG_ID: u32 = unsafe { user32::RegisterWindowMessageA("Glutin::EventID".as_ptr() as *const i8) };
}

/// The Win32 implementation of the main `Window` object.
pub struct Window {
    /// Main handle for the window.
    window: WindowWrapper,

    /// OpenGL context.
    context: Context,

    /// Receiver for the events dispatched by the window callback.
    events_receiver: Receiver<Event>,

    /// The current cursor state.
    cursor_state: Arc<Mutex<CursorState>>,
}

unsafe impl Send for Window {}
unsafe impl Sync for Window {}

enum Context {
    Egl(EglContext),
    Wgl(WglContext),
}

/// A simple wrapper that destroys the window when it is destroyed.
// FIXME: remove `pub` (https://github.com/rust-lang/rust/issues/23585)
#[doc(hidden)]
pub struct WindowWrapper(pub winapi::HWND, pub winapi::HDC);

impl Drop for WindowWrapper {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            user32::DestroyWindow(self.0);
        }
    }
}

#[derive(Clone)]
pub struct WindowProxy {
    hwnd: winapi::HWND,
}

impl WindowProxy {
    #[inline]
    pub fn wakeup_event_loop(&self) {
        unsafe {
            user32::PostMessageA(self.hwnd, *WAKEUP_MSG_ID, 0, 0);
        }
    }
}

impl Window {
    /// See the docs in the crate root file.
    pub fn new(window: &WindowAttributes, pf_reqs: &PixelFormatRequirements,
               opengl: &GlAttributes<&Window>, egl: Option<&Egl>)
               -> Result<Window, CreationError>
    {
        let opengl = opengl.clone().map_sharing(|sharing| {
            match sharing.context {
                Context::Wgl(ref c) => RawContext::Wgl(c.get_hglrc()),
                Context::Egl(_) => unimplemented!(),        // FIXME:
            }
        });

        init::new_window(window, pf_reqs, &opengl, egl)
    }

    /// See the docs in the crate root file.
    ///
    /// Calls SetWindowText on the HWND.
    pub fn set_title(&self, text: &str) {
        let text = OsStr::new(text).encode_wide().chain(Some(0).into_iter())
                                   .collect::<Vec<_>>();

        unsafe {
            user32::SetWindowTextW(self.window.0, text.as_ptr() as winapi::LPCWSTR);
        }
    }

    #[inline]
    pub fn show(&self) {
        unsafe {
            user32::ShowWindow(self.window.0, winapi::SW_SHOW);
        }
    }

    #[inline]
    pub fn hide(&self) {
        unsafe {
            user32::ShowWindow(self.window.0, winapi::SW_HIDE);
        }
    }

    /// See the docs in the crate root file.
    pub fn get_position(&self) -> Option<(i32, i32)> {
        use std::mem;

        let mut placement: winapi::WINDOWPLACEMENT = unsafe { mem::zeroed() };
        placement.length = mem::size_of::<winapi::WINDOWPLACEMENT>() as winapi::UINT;

        if unsafe { user32::GetWindowPlacement(self.window.0, &mut placement) } == 0 {
            return None
        }

        let ref rect = placement.rcNormalPosition;
        Some((rect.left as i32, rect.top as i32))
    }

    /// See the docs in the crate root file.
    pub fn set_position(&self, x: i32, y: i32) {
        use libc;

        unsafe {
            user32::SetWindowPos(self.window.0, ptr::null_mut(), x as libc::c_int, y as libc::c_int,
                0, 0, winapi::SWP_NOZORDER | winapi::SWP_NOSIZE);
            user32::UpdateWindow(self.window.0);
        }
    }

    /// See the docs in the crate root file.
    #[inline]
    pub fn get_inner_size(&self) -> Option<(u32, u32)> {
        let mut rect: winapi::RECT = unsafe { mem::uninitialized() };

        if unsafe { user32::GetClientRect(self.window.0, &mut rect) } == 0 {
            return None
        }

        Some((
            (rect.right - rect.left) as u32,
            (rect.bottom - rect.top) as u32
        ))
    }

    /// See the docs in the crate root file.
    #[inline]
    pub fn get_outer_size(&self) -> Option<(u32, u32)> {
        let mut rect: winapi::RECT = unsafe { mem::uninitialized() };

        if unsafe { user32::GetWindowRect(self.window.0, &mut rect) } == 0 {
            return None
        }

        Some((
            (rect.right - rect.left) as u32,
            (rect.bottom - rect.top) as u32
        ))
    }

    /// See the docs in the crate root file.
    pub fn set_inner_size(&self, x: u32, y: u32) {
        use libc;

        unsafe {
            user32::SetWindowPos(self.window.0, ptr::null_mut(), 0, 0, x as libc::c_int,
                y as libc::c_int, winapi::SWP_NOZORDER | winapi::SWP_NOREPOSITION | winapi::SWP_NOMOVE);
            user32::UpdateWindow(self.window.0);
        }
    }

    #[inline]
    pub fn create_window_proxy(&self) -> WindowProxy {
        WindowProxy { hwnd: self.window.0 }
    }

    /// See the docs in the crate root file.
    #[inline]
    pub fn poll_events(&self) -> PollEventsIterator {
        PollEventsIterator {
            window: self,
        }
    }

    /// See the docs in the crate root file.
    #[inline]
    pub fn wait_events(&self) -> WaitEventsIterator {
        WaitEventsIterator {
            window: self,
        }
    }

    #[inline]
    pub fn platform_display(&self) -> *mut libc::c_void {
        // What should this return on win32?
        // It could be GetDC(NULL), but that requires a ReleaseDC()
        // to avoid leaking the DC.
        ptr::null_mut()
    }

    #[inline]
    pub fn platform_window(&self) -> *mut libc::c_void {
        self.window.0 as *mut libc::c_void
    }

    #[inline]
    pub fn set_window_resize_callback(&mut self, _: Option<fn(u32, u32)>) {
    }

    #[inline]
    pub fn set_cursor(&self, _cursor: MouseCursor) {
        unimplemented!()
    }

    pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
        let mut current_state = self.cursor_state.lock().unwrap();

        let foreground_thread_id = unsafe { user32::GetWindowThreadProcessId(self.window.0, ptr::null_mut()) };
        let current_thread_id = unsafe { kernel32::GetCurrentThreadId() };

        unsafe { user32::AttachThreadInput(foreground_thread_id, current_thread_id, 1) };

        let res = match (state, *current_state) {
            (CursorState::Normal, CursorState::Normal) => Ok(()),
            (CursorState::Hide, CursorState::Hide) => Ok(()),
            (CursorState::Grab, CursorState::Grab) => Ok(()),

            (CursorState::Hide, CursorState::Normal) => {
                unsafe {
                    user32::SetCursor(ptr::null_mut());
                    *current_state = CursorState::Hide;
                    Ok(())
                }
            },

            (CursorState::Normal, CursorState::Hide) => {
                unsafe {
                    user32::SetCursor(user32::LoadCursorW(ptr::null_mut(), winapi::IDC_ARROW));
                    *current_state = CursorState::Normal;
                    Ok(())
                }
            },

            (CursorState::Grab, CursorState::Normal) => {
                unsafe {
                    user32::SetCursor(ptr::null_mut());
                    let mut rect = mem::uninitialized();
                    if user32::GetClientRect(self.window.0, &mut rect) == 0 {
                        return Err(format!("GetWindowRect failed"));
                    }
                    user32::ClientToScreen(self.window.0, mem::transmute(&mut rect.left));
                    user32::ClientToScreen(self.window.0, mem::transmute(&mut rect.right));
                    if user32::ClipCursor(&rect) == 0 {
                        return Err(format!("ClipCursor failed"));
                    }
                    *current_state = CursorState::Grab;
                    Ok(())
                }
            },

            (CursorState::Normal, CursorState::Grab) => {
                unsafe {
                    user32::SetCursor(user32::LoadCursorW(ptr::null_mut(), winapi::IDC_ARROW));
                    if user32::ClipCursor(ptr::null()) == 0 {
                        return Err(format!("ClipCursor failed"));
                    }
                    *current_state = CursorState::Normal;
                    Ok(())
                }
            },

            _ => unimplemented!(),
        };

        unsafe { user32::AttachThreadInput(foreground_thread_id, current_thread_id, 0) };

        res
    }

    #[inline]
    pub fn hidpi_factor(&self) -> f32 {
        1.0
    }

    pub fn set_cursor_position(&self, x: i32, y: i32) -> Result<(), ()> {
        let mut point = winapi::POINT {
            x: x,
            y: y,
        };

        unsafe {
            if user32::ClientToScreen(self.window.0, &mut point) == 0 {
                return Err(());
            }

            if user32::SetCursorPos(point.x, point.y) == 0 {
                return Err(());
            }
        }

        Ok(())
    }
}

impl GlContext for Window {
    #[inline]
    unsafe fn make_current(&self) -> Result<(), ContextError> {
        match self.context {
            Context::Wgl(ref c) => c.make_current(),
            Context::Egl(ref c) => c.make_current(),
        }
    }

    #[inline]
    fn is_current(&self) -> bool {
        match self.context {
            Context::Wgl(ref c) => c.is_current(),
            Context::Egl(ref c) => c.is_current(),
        }
    }

    #[inline]
    fn get_proc_address(&self, addr: &str) -> *const libc::c_void {
        match self.context {
            Context::Wgl(ref c) => c.get_proc_address(addr),
            Context::Egl(ref c) => c.get_proc_address(addr),
        }
    }

    #[inline]
    fn swap_buffers(&self) -> Result<(), ContextError> {
        match self.context {
            Context::Wgl(ref c) => c.swap_buffers(),
            Context::Egl(ref c) => c.swap_buffers(),
        }
    }

    #[inline]
    fn get_api(&self) -> Api {
        match self.context {
            Context::Wgl(ref c) => c.get_api(),
            Context::Egl(ref c) => c.get_api(),
        }
    }

    #[inline]
    fn get_pixel_format(&self) -> PixelFormat {
        match self.context {
            Context::Wgl(ref c) => c.get_pixel_format(),
            Context::Egl(ref c) => c.get_pixel_format(),
        }
    }
}

pub struct PollEventsIterator<'a> {
    window: &'a Window,
}

impl<'a> Iterator for PollEventsIterator<'a> {
    type Item = Event;

    #[inline]
    fn next(&mut self) -> Option<Event> {
        self.window.events_receiver.try_recv().ok()
    }
}

pub struct WaitEventsIterator<'a> {
    window: &'a Window,
}

impl<'a> Iterator for WaitEventsIterator<'a> {
    type Item = Event;

    #[inline]
    fn next(&mut self) -> Option<Event> {
        self.window.events_receiver.recv().ok()
    }
}

impl Drop for Window {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            // we don't call MakeCurrent(0, 0) because we are not sure that the context
            // is still the current one
            user32::PostMessageW(self.window.0, winapi::WM_DESTROY, 0, 0);
        }
    }
}
<commit_msg>Fix WindowProxy not being Send and Sync on win32<commit_after>#![cfg(target_os = "windows")]

use std::mem;
use std::ptr;
use std::ffi::OsStr;
use std::os::windows::ffi::OsStrExt;
use std::sync::{
    Arc,
    Mutex
};
use std::sync::mpsc::Receiver;
use libc;
use ContextError;
use {CreationError, Event, MouseCursor};
use CursorState;
use GlAttributes;
use GlContext;

use Api;
use PixelFormat;
use PixelFormatRequirements;
use WindowAttributes;

pub use self::monitor::{MonitorID, get_available_monitors, get_primary_monitor};

use winapi;
use user32;
use kernel32;

use api::wgl::Context as WglContext;
use api::egl::Context as EglContext;
use api::egl::ffi::egl::Egl;

use self::init::RawContext;

mod callback;
mod event;
mod init;
mod monitor;

lazy_static! {
    static ref WAKEUP_MSG_ID: u32 = unsafe { user32::RegisterWindowMessageA("Glutin::EventID".as_ptr() as *const i8) };
}

/// The Win32 implementation of the main `Window` object.
pub struct Window {
    /// Main handle for the window.
    window: WindowWrapper,

    /// OpenGL context.
    context: Context,

    /// Receiver for the events dispatched by the window callback.
    events_receiver: Receiver<Event>,

    /// The current cursor state.
    cursor_state: Arc<Mutex<CursorState>>,
}

unsafe impl Send for Window {}
unsafe impl Sync for Window {}

enum Context {
    Egl(EglContext),
    Wgl(WglContext),
}

/// A simple wrapper that destroys the window when it is destroyed.
// FIXME: remove `pub` (https://github.com/rust-lang/rust/issues/23585)
#[doc(hidden)]
pub struct WindowWrapper(pub winapi::HWND, pub winapi::HDC);

impl Drop for WindowWrapper {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            user32::DestroyWindow(self.0);
        }
    }
}

#[derive(Clone)]
pub struct WindowProxy {
    hwnd: winapi::HWND,
}

unsafe impl Send for WindowProxy {}
unsafe impl Sync for WindowProxy {}

impl WindowProxy {
    #[inline]
    pub fn wakeup_event_loop(&self) {
        unsafe {
            user32::PostMessageA(self.hwnd, *WAKEUP_MSG_ID, 0, 0);
        }
    }
}

impl Window {
    /// See the docs in the crate root file.
    pub fn new(window: &WindowAttributes, pf_reqs: &PixelFormatRequirements,
               opengl: &GlAttributes<&Window>, egl: Option<&Egl>)
               -> Result<Window, CreationError>
    {
        let opengl = opengl.clone().map_sharing(|sharing| {
            match sharing.context {
                Context::Wgl(ref c) => RawContext::Wgl(c.get_hglrc()),
                Context::Egl(_) => unimplemented!(),        // FIXME:
            }
        });

        init::new_window(window, pf_reqs, &opengl, egl)
    }

    /// See the docs in the crate root file.
    ///
    /// Calls SetWindowText on the HWND.
    pub fn set_title(&self, text: &str) {
        let text = OsStr::new(text).encode_wide().chain(Some(0).into_iter())
                                   .collect::<Vec<_>>();

        unsafe {
            user32::SetWindowTextW(self.window.0, text.as_ptr() as winapi::LPCWSTR);
        }
    }

    #[inline]
    pub fn show(&self) {
        unsafe {
            user32::ShowWindow(self.window.0, winapi::SW_SHOW);
        }
    }

    #[inline]
    pub fn hide(&self) {
        unsafe {
            user32::ShowWindow(self.window.0, winapi::SW_HIDE);
        }
    }

    /// See the docs in the crate root file.
    pub fn get_position(&self) -> Option<(i32, i32)> {
        use std::mem;

        let mut placement: winapi::WINDOWPLACEMENT = unsafe { mem::zeroed() };
        placement.length = mem::size_of::<winapi::WINDOWPLACEMENT>() as winapi::UINT;

        if unsafe { user32::GetWindowPlacement(self.window.0, &mut placement) } == 0 {
            return None
        }

        let ref rect = placement.rcNormalPosition;
        Some((rect.left as i32, rect.top as i32))
    }

    /// See the docs in the crate root file.
    pub fn set_position(&self, x: i32, y: i32) {
        use libc;

        unsafe {
            user32::SetWindowPos(self.window.0, ptr::null_mut(), x as libc::c_int, y as libc::c_int,
                0, 0, winapi::SWP_NOZORDER | winapi::SWP_NOSIZE);
            user32::UpdateWindow(self.window.0);
        }
    }

    /// See the docs in the crate root file.
    #[inline]
    pub fn get_inner_size(&self) -> Option<(u32, u32)> {
        let mut rect: winapi::RECT = unsafe { mem::uninitialized() };

        if unsafe { user32::GetClientRect(self.window.0, &mut rect) } == 0 {
            return None
        }

        Some((
            (rect.right - rect.left) as u32,
            (rect.bottom - rect.top) as u32
        ))
    }

    /// See the docs in the crate root file.
    #[inline]
    pub fn get_outer_size(&self) -> Option<(u32, u32)> {
        let mut rect: winapi::RECT = unsafe { mem::uninitialized() };

        if unsafe { user32::GetWindowRect(self.window.0, &mut rect) } == 0 {
            return None
        }

        Some((
            (rect.right - rect.left) as u32,
            (rect.bottom - rect.top) as u32
        ))
    }

    /// See the docs in the crate root file.
    pub fn set_inner_size(&self, x: u32, y: u32) {
        use libc;

        unsafe {
            user32::SetWindowPos(self.window.0, ptr::null_mut(), 0, 0, x as libc::c_int,
                y as libc::c_int, winapi::SWP_NOZORDER | winapi::SWP_NOREPOSITION | winapi::SWP_NOMOVE);
            user32::UpdateWindow(self.window.0);
        }
    }

    #[inline]
    pub fn create_window_proxy(&self) -> WindowProxy {
        WindowProxy { hwnd: self.window.0 }
    }

    /// See the docs in the crate root file.
    #[inline]
    pub fn poll_events(&self) -> PollEventsIterator {
        PollEventsIterator {
            window: self,
        }
    }

    /// See the docs in the crate root file.
    #[inline]
    pub fn wait_events(&self) -> WaitEventsIterator {
        WaitEventsIterator {
            window: self,
        }
    }

    #[inline]
    pub fn platform_display(&self) -> *mut libc::c_void {
        // What should this return on win32?
        // It could be GetDC(NULL), but that requires a ReleaseDC()
        // to avoid leaking the DC.
        ptr::null_mut()
    }

    #[inline]
    pub fn platform_window(&self) -> *mut libc::c_void {
        self.window.0 as *mut libc::c_void
    }

    #[inline]
    pub fn set_window_resize_callback(&mut self, _: Option<fn(u32, u32)>) {
    }

    #[inline]
    pub fn set_cursor(&self, _cursor: MouseCursor) {
        unimplemented!()
    }

    pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
        let mut current_state = self.cursor_state.lock().unwrap();

        let foreground_thread_id = unsafe { user32::GetWindowThreadProcessId(self.window.0, ptr::null_mut()) };
        let current_thread_id = unsafe { kernel32::GetCurrentThreadId() };

        unsafe { user32::AttachThreadInput(foreground_thread_id, current_thread_id, 1) };

        let res = match (state, *current_state) {
            (CursorState::Normal, CursorState::Normal) => Ok(()),
            (CursorState::Hide, CursorState::Hide) => Ok(()),
            (CursorState::Grab, CursorState::Grab) => Ok(()),

            (CursorState::Hide, CursorState::Normal) => {
                unsafe {
                    user32::SetCursor(ptr::null_mut());
                    *current_state = CursorState::Hide;
                    Ok(())
                }
            },

            (CursorState::Normal, CursorState::Hide) => {
                unsafe {
                    user32::SetCursor(user32::LoadCursorW(ptr::null_mut(), winapi::IDC_ARROW));
                    *current_state = CursorState::Normal;
                    Ok(())
                }
            },

            (CursorState::Grab, CursorState::Normal) => {
                unsafe {
                    user32::SetCursor(ptr::null_mut());
                    let mut rect = mem::uninitialized();
                    if user32::GetClientRect(self.window.0, &mut rect) == 0 {
                        return Err(format!("GetWindowRect failed"));
                    }
                    user32::ClientToScreen(self.window.0, mem::transmute(&mut rect.left));
                    user32::ClientToScreen(self.window.0, mem::transmute(&mut rect.right));
                    if user32::ClipCursor(&rect) == 0 {
                        return Err(format!("ClipCursor failed"));
                    }
                    *current_state = CursorState::Grab;
                    Ok(())
                }
            },

            (CursorState::Normal, CursorState::Grab) => {
                unsafe {
                    user32::SetCursor(user32::LoadCursorW(ptr::null_mut(), winapi::IDC_ARROW));
                    if user32::ClipCursor(ptr::null()) == 0 {
                        return Err(format!("ClipCursor failed"));
                    }
                    *current_state = CursorState::Normal;
                    Ok(())
                }
            },

            _ => unimplemented!(),
        };

        unsafe { user32::AttachThreadInput(foreground_thread_id, current_thread_id, 0) };

        res
    }

    #[inline]
    pub fn hidpi_factor(&self) -> f32 {
        1.0
    }

    pub fn set_cursor_position(&self, x: i32, y: i32) -> Result<(), ()> {
        let mut point = winapi::POINT {
            x: x,
            y: y,
        };

        unsafe {
            if user32::ClientToScreen(self.window.0, &mut point) == 0 {
                return Err(());
            }

            if user32::SetCursorPos(point.x, point.y) == 0 {
                return Err(());
            }
        }

        Ok(())
    }
}

impl GlContext for Window {
    #[inline]
    unsafe fn make_current(&self) -> Result<(), ContextError> {
        match self.context {
            Context::Wgl(ref c) => c.make_current(),
            Context::Egl(ref c) => c.make_current(),
        }
    }

    #[inline]
    fn is_current(&self) -> bool {
        match self.context {
            Context::Wgl(ref c) => c.is_current(),
            Context::Egl(ref c) => c.is_current(),
        }
    }

    #[inline]
    fn get_proc_address(&self, addr: &str) -> *const libc::c_void {
        match self.context {
            Context::Wgl(ref c) => c.get_proc_address(addr),
            Context::Egl(ref c) => c.get_proc_address(addr),
        }
    }

    #[inline]
    fn swap_buffers(&self) -> Result<(), ContextError> {
        match self.context {
            Context::Wgl(ref c) => c.swap_buffers(),
            Context::Egl(ref c) => c.swap_buffers(),
        }
    }

    #[inline]
    fn get_api(&self) -> Api {
        match self.context {
            Context::Wgl(ref c) => c.get_api(),
            Context::Egl(ref c) => c.get_api(),
        }
    }

    #[inline]
    fn get_pixel_format(&self) -> PixelFormat {
        match self.context {
            Context::Wgl(ref c) => c.get_pixel_format(),
            Context::Egl(ref c) => c.get_pixel_format(),
        }
    }
}

pub struct PollEventsIterator<'a> {
    window: &'a Window,
}

impl<'a> Iterator for PollEventsIterator<'a> {
    type Item = Event;

    #[inline]
    fn next(&mut self) -> Option<Event> {
        self.window.events_receiver.try_recv().ok()
    }
}

pub struct WaitEventsIterator<'a> {
    window: &'a Window,
}

impl<'a> Iterator for WaitEventsIterator<'a> {
    type Item = Event;

    #[inline]
    fn next(&mut self) -> Option<Event> {
        self.window.events_receiver.recv().ok()
    }
}

impl Drop for Window {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            // we don't call MakeCurrent(0, 0) because we are not sure that the context
            // is still the current one
            user32::PostMessageW(self.window.0, winapi::WM_DESTROY, 0, 0);
        }
    }
}
<|endoftext|>


<commit_before>use std::ascii::AsciiExt;
use std::cmp::*;
use std::os;
use std::thread;
use std::sync::mpsc::*;

macro_rules! chars {
    ($str:expr) => (
        &$str.chars().collect::<Vec<char>>()
    );
}

pub fn compute_matches<'a>(choices: &[&'a str], query: &str) -> Vec<&'a str> {
    #[derive(PartialEq)]
    struct ScoredChoice {
        idx: usize,
        score: f64,
    }
    impl PartialOrd for ScoredChoice {
        fn partial_cmp(&self, other: &ScoredChoice) -> Option<Ordering> {
            if other.score == self.score {
                // We fall back to an array index comparison in order to guarantee a stable sort;
                // otherwise the matches may be displayed in a nondeterministic order.
                Some(self.idx.cmp(&other.idx))
            } else {
                other.score.partial_cmp(&self.score)
            }
        }
    }
    let mut join_guards = Vec::new();
    let (tx, rx) = channel();
    let workers = os::num_cpus();
    for current_worker in 0..workers {
        let tx = tx.clone();
        join_guards.push(thread::scoped(move|| {
            let (lower_bound, upper_bound) = get_slice_indices(choices.len(), workers, current_worker);
            for i in lower_bound..upper_bound {
                let score = score(choices[i], query);
                tx.send(ScoredChoice{ idx: i, score: score }).unwrap();
            }
        }));
    }

    let mut ret = Vec::new();
    for _ in 0..choices.len() {
        let scored_choice = rx.recv().unwrap();
        if scored_choice.score > 0_f64 {
            ret.push(scored_choice);
        }
    }

    ret.sort_by(|x, y| x.partial_cmp(y).unwrap());
    ret.iter().map(|x| choices[x.idx]).collect()
}

fn get_slice_indices(length: usize, workers: usize, idx: usize) -> (usize, usize) {
    let lb = (length as f64 / workers as f64) * idx as f64;
    let ub = (length as f64 / workers as f64) * (idx + 1) as f64;
    (lb as usize, ub as usize)
}

#[test]
fn get_slice_indices_test() {
    assert_eq!(get_slice_indices(100, 1, 0), (0, 100));

    assert_eq!(get_slice_indices(100, 2, 1), (50, 100));
    assert_eq!(get_slice_indices(100, 2, 0), (0, 50));

    assert_eq!(get_slice_indices(100, 3, 0), (0, 33));
    assert_eq!(get_slice_indices(100, 3, 1), (33, 66));
    assert_eq!(get_slice_indices(100, 3, 2), (66, 100));

    assert_eq!(get_slice_indices(100, 4, 0), (0, 25));
    assert_eq!(get_slice_indices(100, 4, 1), (25, 50));
    assert_eq!(get_slice_indices(100, 4, 2), (50, 75));
    assert_eq!(get_slice_indices(100, 4, 3), (75, 100));

    assert_eq!(get_slice_indices(12, 12, 11), (11, 12));
    assert_eq!(get_slice_indices(12, 12, 0), (0, 1));

    assert_eq!(get_slice_indices(1, 2, 0), (0, 0));
    assert_eq!(get_slice_indices(1, 2, 1), (0, 1));
}

fn score(choice: &str, query: &str) -> f64 {
    if query.len() == 0 {
        return 1.0;
    }
    if choice.len() == 0 {
        return 0.0;
    }

    let query = query.to_ascii_lowercase();
    let choice = choice.to_ascii_lowercase();
    let query = chars!(query);
    let choice = chars!(choice);

    match compute_match_length(choice, query) {
        None => return 0.0,
        Some(match_length) => {
            let score = query.len() as f64 / match_length as f64;
            return score as f64 / choice.len() as f64;
        }
    }
}

// This function is for picking out the matching characters for a given (choice, query) pair for
// rendering purposes. It assumes that the given choice is in fact a match for the given query, and
// will panic if this is not the case.
pub fn visual_score(choice: &str, query: &str) -> Vec<usize> {
    if query.len() == 0 || choice.len() == 0 {
        return Vec::new();
    }
    let query = query.to_ascii_lowercase();
    let choice = choice.to_ascii_lowercase();
    let query = chars!(query);
    let choice = chars!(choice);

    let (first_idx, _) = get_longest_match(&choice, &query).unwrap();
    get_match_indices(&choice, &query[1..], first_idx).unwrap()
}

fn compute_match_length(string: &[char], query: &[char]) -> Option<usize> {
    get_match_length(get_longest_match(string, query))
}

fn get_longest_match(string: &[char], query: &[char]) -> Option<(usize, usize)> {
    let first_char = query[0];
    let rest = &query[1..];
    let indices = find_char_in_string(string, first_char);

    let mut current_bounds: Option<(usize, usize)> = None;
    let smallest_possible_match = query.len();
    for &i in &indices {
        if let Some(last_index) = find_end_of_match(string, rest, i) {
            let last_bounds = Some((i, last_index));
            let last_match_len = get_match_length(last_bounds).unwrap();
            if current_bounds.is_none() || last_match_len < get_match_length(current_bounds).unwrap() {
                current_bounds = last_bounds;
                if last_match_len == smallest_possible_match {
                    break;
                }
            }
        }
    }
    current_bounds
}

fn get_match_length(bounds: Option<(usize, usize)>) -> Option<usize> {
    if let Some((lb, ub)) = bounds {
        Some(ub - lb + 1)
    } else {
        None
    }
}

fn find_char_in_string(string: &[char], char: char) -> Vec<usize> {
    let mut indices = Vec::new();
    for (i, c) in string.iter().enumerate() {
        if chars_equal(&char, c) {
            indices.push(i);
        }
    }
    return indices;
}

fn find_end_of_match(string: &[char], rest_of_query: &[char], first_index: usize) -> Option<usize> {
    if let Some(indices) = get_match_indices(string, rest_of_query, first_index) {
        Some(indices[indices.len() - 1])
    } else {
        None
    }
}

fn get_match_indices(string: &[char], rest_of_query: &[char], first_index: usize) -> Option<Vec<usize>> {
    let mut ret = Vec::new();
    let mut last_index = first_index + 1;
    ret.push(first_index);
    for c in rest_of_query.iter() {
        let current_substring = &string[last_index..];
        let mut index = None;
        for (i, x) in current_substring.iter().enumerate() {
            if chars_equal(c, x) {
                index = Some(i);
                break;
            }
        }
        if index.is_some() {
            last_index += index.unwrap() + 1;
            ret.push(last_index - 1);
        } else {
            return None;
        }
    }
    Some(ret)
}

fn chars_equal(q: &char, c: &char) -> bool {
    q.eq_ignore_ascii_case(c)
}

#[test]
fn chars_equal_test() {
    assert!(chars_equal(&'a', &'a'));
    assert!(!chars_equal(&'a', &'b'));
    assert!(chars_equal(&'A', &'A'));
    assert!(chars_equal(&'A', &'a'));
    assert!(chars_equal(&'a', &'A'));
}

#[test]
fn get_match_indices_test() {
    assert_eq!(get_match_indices(chars!("asdf"), chars!("sdf"), 0).unwrap(), vec![0, 1, 2, 3]);
    assert_eq!(get_match_indices(chars!("aoeuasdf"), chars!("sdf"), 4).unwrap(), vec![4, 5, 6, 7]);
    assert_eq!(get_match_indices(chars!(" a s d f"), chars!("sdf"), 1).unwrap(), vec![1, 3, 5, 7]);
}

#[test]
fn find_end_of_match_test() {
    assert_eq!(find_end_of_match(chars!("a"), chars!("a"), 0), None);
    assert_eq!(find_end_of_match(chars!("ba"), chars!("a"), 1), None);
    assert_eq!(find_end_of_match(chars!("aaa"), chars!("aa"), 0), Some(2));
    assert_eq!(find_end_of_match(chars!("aaa"), chars!("b"), 0), None);
    assert_eq!(find_end_of_match(chars!("this is a long match"), chars!("this is a match"), 0), None);
    assert_eq!(find_end_of_match(chars!("this is a long match"), chars!("his is a match"), 0), Some(19));
    assert_eq!(find_end_of_match(chars!("./rust/x86_64-apple-darwin/test/run-pass/process-spawn-with-unicode-params-πЯ音æ∞/child.stage2-x86_64-apple-darwin"), chars!("ust"), 2), Some(5));
}

#[test]
fn unicode_boundary_handling_test() {
    score("./rust/x86_64-apple-darwin/test/run-pass/process-spawn-with-unicode-params-πЯ音æ∞/child.stage2-x86_64-apple-darwin", "he");
}

#[test]
fn basic_scoring() {
    assert_eq!(score("", "a"), 0.0);
    assert_eq!(score("a", ""), 1.0);
    assert_eq!(score("short", "longer"), 0.0);
    assert_eq!(score("a", "b"), 0.0);
    assert_eq!(score("ab", "ac"), 0.0);

    assert!(score("a", "a") > 0.0);
    assert!(score("ab", "a") > 0.0);
    assert!(score("ba", "a") > 0.0);
    assert!(score("bab", "a") > 0.0);
    assert!(score("babababab", "aaaa") > 0.0);

    assert_eq!(score("a", "a"), 1_f64 / "a".len() as f64);
    assert_eq!(score("ab", "ab"), 0.5);
    assert_eq!(score("a long string", "a long string"), 1_f64 / "a long string".len() as f64);
    assert_eq!(score("spec/search_spec.rb", "sear"), 1_f64 / "spec/search_spec.rb".len() as f64);
}

#[test]
fn character_matching() {
    assert!(score("/! symbols $^", "/!$^") > 0.0);

    assert_eq!(score("a", "A"), 1.0);
    assert_eq!(score("A", "a"), 1.0);

    assert_eq!(score("a", "aa"), 0.0);
}

#[test]
fn match_equality() {
    assert!(score("selecta.gemspec", "asp") > score("algorithm4_spec.rb", "asp"));
    assert!(score("README.md", "em") > score("benchmark.rb", "em"));
    assert!(score("search.rb", "sear") > score("spec/search_spec.rb", "sear"));

    assert!(score("fbb", "fbb") > score("foo bar baz", "fbb"));
    assert!(score("foo", "foo") > score("longer foo", "foo"));
    assert!(score("foo", "foo") > score("foo longer", "foo"));
    assert!(score("1/2/3/4", "1/2/3") > score("1/9/2/3/4", "1/2/3"));

    assert!(score("long 12 long", "12") > score("1 long 2", "12"));

    assert_eq!(score("121padding2", "12"), 1.0 / "121padding2".len() as f64);
    assert_eq!(score("1padding212", "12"), 1.0 / "1padding212".len() as f64);
}
<commit_msg>Add smart case matching<commit_after>use std::ascii::AsciiExt;
use std::cmp::*;
use std::os;
use std::thread;
use std::sync::mpsc::*;

macro_rules! chars {
    ($str:expr) => (
        &$str.chars().collect::<Vec<char>>()
    );
}

pub fn compute_matches<'a>(choices: &[&'a str], query: &str) -> Vec<&'a str> {
    #[derive(PartialEq)]
    struct ScoredChoice {
        idx: usize,
        score: f64,
    }
    impl PartialOrd for ScoredChoice {
        fn partial_cmp(&self, other: &ScoredChoice) -> Option<Ordering> {
            if other.score == self.score {
                // We fall back to an array index comparison in order to guarantee a stable sort;
                // otherwise the matches may be displayed in a nondeterministic order.
                Some(self.idx.cmp(&other.idx))
            } else {
                other.score.partial_cmp(&self.score)
            }
        }
    }
    let mut join_guards = Vec::new();
    let (tx, rx) = channel();
    let workers = os::num_cpus();
    for current_worker in 0..workers {
        let tx = tx.clone();
        join_guards.push(thread::scoped(move|| {
            let (lower_bound, upper_bound) = get_slice_indices(choices.len(), workers, current_worker);
            for i in lower_bound..upper_bound {
                let score = score(choices[i], query);
                tx.send(ScoredChoice{ idx: i, score: score }).unwrap();
            }
        }));
    }

    let mut ret = Vec::new();
    for _ in 0..choices.len() {
        let scored_choice = rx.recv().unwrap();
        if scored_choice.score > 0_f64 {
            ret.push(scored_choice);
        }
    }

    ret.sort_by(|x, y| x.partial_cmp(y).unwrap());
    ret.iter().map(|x| choices[x.idx]).collect()
}

fn get_slice_indices(length: usize, workers: usize, idx: usize) -> (usize, usize) {
    let lb = (length as f64 / workers as f64) * idx as f64;
    let ub = (length as f64 / workers as f64) * (idx + 1) as f64;
    (lb as usize, ub as usize)
}

#[test]
fn get_slice_indices_test() {
    assert_eq!(get_slice_indices(100, 1, 0), (0, 100));

    assert_eq!(get_slice_indices(100, 2, 1), (50, 100));
    assert_eq!(get_slice_indices(100, 2, 0), (0, 50));

    assert_eq!(get_slice_indices(100, 3, 0), (0, 33));
    assert_eq!(get_slice_indices(100, 3, 1), (33, 66));
    assert_eq!(get_slice_indices(100, 3, 2), (66, 100));

    assert_eq!(get_slice_indices(100, 4, 0), (0, 25));
    assert_eq!(get_slice_indices(100, 4, 1), (25, 50));
    assert_eq!(get_slice_indices(100, 4, 2), (50, 75));
    assert_eq!(get_slice_indices(100, 4, 3), (75, 100));

    assert_eq!(get_slice_indices(12, 12, 11), (11, 12));
    assert_eq!(get_slice_indices(12, 12, 0), (0, 1));

    assert_eq!(get_slice_indices(1, 2, 0), (0, 0));
    assert_eq!(get_slice_indices(1, 2, 1), (0, 1));
}

fn score(choice: &str, query: &str) -> f64 {
    if query.len() == 0 {
        return 1.0;
    }
    if choice.len() == 0 {
        return 0.0;
    }

    let query = chars!(query);
    let choice = chars!(choice);

    match compute_match_length(choice, query) {
        None => return 0.0,
        Some(match_length) => {
            let score = query.len() as f64 / match_length as f64;
            return score as f64 / choice.len() as f64;
        }
    }
}

// This function is for picking out the matching characters for a given (choice, query) pair for
// rendering purposes. It assumes that the given choice is in fact a match for the given query, and
// will panic if this is not the case.
pub fn visual_score(choice: &str, query: &str) -> Vec<usize> {
    if query.len() == 0 || choice.len() == 0 {
        return Vec::new();
    }
    let query = chars!(query);
    let choice = chars!(choice);

    let (first_idx, _) = get_longest_match(&choice, &query).unwrap();
    get_match_indices(&choice, &query[1..], first_idx).unwrap()
}

fn compute_match_length(string: &[char], query: &[char]) -> Option<usize> {
    get_match_length(get_longest_match(string, query))
}

fn get_longest_match(string: &[char], query: &[char]) -> Option<(usize, usize)> {
    let first_char = query[0];
    let rest = &query[1..];
    let indices = find_char_in_string(string, first_char);

    let mut current_bounds: Option<(usize, usize)> = None;
    let smallest_possible_match = query.len();
    for &i in &indices {
        if let Some(last_index) = find_end_of_match(string, rest, i) {
            let last_bounds = Some((i, last_index));
            let last_match_len = get_match_length(last_bounds).unwrap();
            if current_bounds.is_none() || last_match_len < get_match_length(current_bounds).unwrap() {
                current_bounds = last_bounds;
                if last_match_len == smallest_possible_match {
                    break;
                }
            }
        }
    }
    current_bounds
}

fn get_match_length(bounds: Option<(usize, usize)>) -> Option<usize> {
    if let Some((lb, ub)) = bounds {
        Some(ub - lb + 1)
    } else {
        None
    }
}

fn find_char_in_string(string: &[char], char: char) -> Vec<usize> {
    let mut indices = Vec::new();
    for (i, c) in string.iter().enumerate() {
        if chars_equal(&char, c) {
            indices.push(i);
        }
    }
    return indices;
}

fn find_end_of_match(string: &[char], rest_of_query: &[char], first_index: usize) -> Option<usize> {
    if let Some(indices) = get_match_indices(string, rest_of_query, first_index) {
        Some(indices[indices.len() - 1])
    } else {
        None
    }
}

fn get_match_indices(string: &[char], rest_of_query: &[char], first_index: usize) -> Option<Vec<usize>> {
    let mut ret = Vec::new();
    let mut last_index = first_index + 1;
    ret.push(first_index);
    for c in rest_of_query.iter() {
        let current_substring = &string[last_index..];
        let mut index = None;
        for (i, x) in current_substring.iter().enumerate() {
            if chars_equal(c, x) {
                index = Some(i);
                break;
            }
        }
        if index.is_some() {
            last_index += index.unwrap() + 1;
            ret.push(last_index - 1);
        } else {
            return None;
        }
    }
    Some(ret)
}

fn chars_equal(q: &char, c: &char) -> bool {
    *q == *c || *q == c.to_ascii_lowercase()
}

#[test]
fn chars_equal_test() {
    assert!(chars_equal(&'a', &'a'));
    assert!(!chars_equal(&'a', &'b'));
    assert!(chars_equal(&'A', &'A'));
    assert!(!chars_equal(&'A', &'a'));
    assert!(chars_equal(&'a', &'A'));
}

#[test]
fn get_match_indices_test() {
    assert_eq!(get_match_indices(chars!("asdf"), chars!("sdf"), 0).unwrap(), vec![0, 1, 2, 3]);
    assert_eq!(get_match_indices(chars!("aoeuasdf"), chars!("sdf"), 4).unwrap(), vec![4, 5, 6, 7]);
    assert_eq!(get_match_indices(chars!(" a s d f"), chars!("sdf"), 1).unwrap(), vec![1, 3, 5, 7]);
}

#[test]
fn find_end_of_match_test() {
    assert_eq!(find_end_of_match(chars!("a"), chars!("a"), 0), None);
    assert_eq!(find_end_of_match(chars!("ba"), chars!("a"), 1), None);
    assert_eq!(find_end_of_match(chars!("aaa"), chars!("aa"), 0), Some(2));
    assert_eq!(find_end_of_match(chars!("aaa"), chars!("b"), 0), None);
    assert_eq!(find_end_of_match(chars!("this is a long match"), chars!("this is a match"), 0), None);
    assert_eq!(find_end_of_match(chars!("this is a long match"), chars!("his is a match"), 0), Some(19));
    assert_eq!(find_end_of_match(chars!("./rust/x86_64-apple-darwin/test/run-pass/process-spawn-with-unicode-params-πЯ音æ∞/child.stage2-x86_64-apple-darwin"), chars!("ust"), 2), Some(5));
}

#[test]
fn unicode_boundary_handling_test() {
    score("./rust/x86_64-apple-darwin/test/run-pass/process-spawn-with-unicode-params-πЯ音æ∞/child.stage2-x86_64-apple-darwin", "he");
}

#[test]
fn basic_scoring() {
    assert_eq!(score("", "a"), 0.0);
    assert_eq!(score("a", ""), 1.0);
    assert_eq!(score("short", "longer"), 0.0);
    assert_eq!(score("a", "b"), 0.0);
    assert_eq!(score("ab", "ac"), 0.0);

    assert!(score("a", "a") > 0.0);
    assert!(score("ab", "a") > 0.0);
    assert!(score("ba", "a") > 0.0);
    assert!(score("bab", "a") > 0.0);
    assert!(score("babababab", "aaaa") > 0.0);

    assert_eq!(score("a", "a"), 1_f64 / "a".len() as f64);
    assert_eq!(score("ab", "ab"), 0.5);
    assert_eq!(score("a long string", "a long string"), 1_f64 / "a long string".len() as f64);
    assert_eq!(score("spec/search_spec.rb", "sear"), 1_f64 / "spec/search_spec.rb".len() as f64);
}

#[test]
fn character_matching() {
    assert!(score("/! symbols $^", "/!$^") > 0.0);

    assert_eq!(score("a", "A"), 0.0);
    assert_eq!(score("A", "a"), 1.0);
    assert_eq!(score("A", "A"), 1.0);

    assert_eq!(score("a", "aa"), 0.0);
}

#[test]
fn match_equality() {
    assert!(score("selecta.gemspec", "asp") > score("algorithm4_spec.rb", "asp"));
    assert!(score("README.md", "em") > score("benchmark.rb", "em"));
    assert!(score("search.rb", "sear") > score("spec/search_spec.rb", "sear"));

    assert!(score("fbb", "fbb") > score("foo bar baz", "fbb"));
    assert!(score("foo", "foo") > score("longer foo", "foo"));
    assert!(score("foo", "foo") > score("foo longer", "foo"));
    assert!(score("1/2/3/4", "1/2/3") > score("1/9/2/3/4", "1/2/3"));

    assert!(score("long 12 long", "12") > score("1 long 2", "12"));

    assert_eq!(score("121padding2", "12"), 1.0 / "121padding2".len() as f64);
    assert_eq!(score("1padding212", "12"), 1.0 / "1padding212".len() as f64);
}
<|endoftext|>


<commit_before>//! A collection of newtypes defining type-strong IDs.

use chrono::NaiveDateTime;
use internal::prelude::*;
use serde::de::{Deserialize, Deserializer};
use std::fmt::{Display, Formatter, Result as FmtResult};
use super::utils::U64Visitor;

macro_rules! id_u64 {
    ($($name:ident;)*) => {
        $(
            impl $name {
                /// Retrieves the time that the Id was created at.
                pub fn created_at(&self) -> NaiveDateTime {
                    let offset = (self.0 >> 22) / 1000;

                    NaiveDateTime::from_timestamp(1_420_070_400 + offset as i64, 0)
                }
            }

            // This is a hack so functions can accept iterators that either:
            // 1. return the id itself (e.g: `MessageId`)
            // 2. return a reference to it (`&MessageId`).
            impl AsRef<$name> for $name {
                fn as_ref(&self) -> &Self {
                    self
                }
            }

            impl From<u64> for $name {
                fn from(id_as_u64: u64) -> $name {
                    $name(id_as_u64)
                }
            }

            impl PartialEq for $name {
                fn eq(&self, other: &Self) -> bool {
                    self.0 == other.0
                }
            }

            impl PartialEq<u64> for $name {
                fn eq(&self, u: &u64) -> bool {
                    self.0 == *u
                }
            }

            impl Display for $name {
                fn fmt(&self, f: &mut Formatter) -> FmtResult {
                    Display::fmt(&self.0, f)
                }
            }

            impl<'de> Deserialize<'de> for $name {
                fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
                    deserializer.deserialize_any(U64Visitor).map($name)
                }
            }
        )*
    }
}

/// An identifier for an Application.
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialOrd, Ord, Serialize)]
#[allow(derive_hash_xor_eq)]
pub struct ApplicationId(pub u64);

/// An identifier for a Channel
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialOrd, Ord, Serialize)]
#[allow(derive_hash_xor_eq)]
pub struct ChannelId(pub u64);

/// An identifier for an Emoji
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialOrd, Ord, Serialize)]
#[allow(derive_hash_xor_eq)]
pub struct EmojiId(pub u64);

/// An identifier for a Guild
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialOrd, Ord, Serialize)]
#[allow(derive_hash_xor_eq)]
pub struct GuildId(pub u64);

/// An identifier for an Integration
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialOrd, Ord, Serialize)]
#[allow(derive_hash_xor_eq)]
pub struct IntegrationId(pub u64);

/// An identifier for a Message
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialOrd, Ord, Serialize)]
#[allow(derive_hash_xor_eq)]
pub struct MessageId(pub u64);

/// An identifier for a Role
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialOrd, Ord, Serialize)]
#[allow(derive_hash_xor_eq)]
pub struct RoleId(pub u64);

/// An identifier for a User
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialOrd, Ord, Serialize)]
#[allow(derive_hash_xor_eq)]
pub struct UserId(pub u64);

/// An identifier for a [`Webhook`](struct.Webhook.html).
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialOrd, Ord, Serialize)]
#[allow(derive_hash_xor_eq)]
pub struct WebhookId(pub u64);

/// An identifier for an audit log entry.
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialOrd, Ord, Serialize)]
#[allow(derive_hash_xor_eq)]
pub struct AuditLogEntryId(pub u64);

id_u64! {
    ApplicationId;
    ChannelId;
    EmojiId;
    GuildId;
    IntegrationId;
    MessageId;
    RoleId;
    UserId;
    WebhookId;
    AuditLogEntryId;
}
<commit_msg>impl Form<&$ID> for $ID<commit_after>//! A collection of newtypes defining type-strong IDs.

use chrono::NaiveDateTime;
use internal::prelude::*;
use serde::de::{Deserialize, Deserializer};
use std::fmt::{Display, Formatter, Result as FmtResult};
use super::utils::U64Visitor;

macro_rules! id_u64 {
    ($($name:ident;)*) => {
        $(
            impl $name {
                /// Retrieves the time that the Id was created at.
                pub fn created_at(&self) -> NaiveDateTime {
                    let offset = (self.0 >> 22) / 1000;

                    NaiveDateTime::from_timestamp(1_420_070_400 + offset as i64, 0)
                }
            }

            // This is a hack so functions can accept iterators that either:
            // 1. return the id itself (e.g: `MessageId`)
            // 2. return a reference to it (`&MessageId`).
            impl AsRef<$name> for $name {
                fn as_ref(&self) -> &Self {
                    self
                }
            }

            impl<'a> From<&'a $name> for $name {
                fn from(id: &'a $name) -> $name {
                    id.clone()
                }
            }

            impl From<u64> for $name {
                fn from(id_as_u64: u64) -> $name {
                    $name(id_as_u64)
                }
            }

            impl PartialEq for $name {
                fn eq(&self, other: &Self) -> bool {
                    self.0 == other.0
                }
            }

            impl PartialEq<u64> for $name {
                fn eq(&self, u: &u64) -> bool {
                    self.0 == *u
                }
            }

            impl Display for $name {
                fn fmt(&self, f: &mut Formatter) -> FmtResult {
                    Display::fmt(&self.0, f)
                }
            }

            impl<'de> Deserialize<'de> for $name {
                fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
                    deserializer.deserialize_any(U64Visitor).map($name)
                }
            }
        )*
    }
}

/// An identifier for an Application.
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialOrd, Ord, Serialize)]
#[allow(derive_hash_xor_eq)]
pub struct ApplicationId(pub u64);

/// An identifier for a Channel
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialOrd, Ord, Serialize)]
#[allow(derive_hash_xor_eq)]
pub struct ChannelId(pub u64);

/// An identifier for an Emoji
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialOrd, Ord, Serialize)]
#[allow(derive_hash_xor_eq)]
pub struct EmojiId(pub u64);

/// An identifier for a Guild
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialOrd, Ord, Serialize)]
#[allow(derive_hash_xor_eq)]
pub struct GuildId(pub u64);

/// An identifier for an Integration
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialOrd, Ord, Serialize)]
#[allow(derive_hash_xor_eq)]
pub struct IntegrationId(pub u64);

/// An identifier for a Message
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialOrd, Ord, Serialize)]
#[allow(derive_hash_xor_eq)]
pub struct MessageId(pub u64);

/// An identifier for a Role
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialOrd, Ord, Serialize)]
#[allow(derive_hash_xor_eq)]
pub struct RoleId(pub u64);

/// An identifier for a User
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialOrd, Ord, Serialize)]
#[allow(derive_hash_xor_eq)]
pub struct UserId(pub u64);

/// An identifier for a [`Webhook`](struct.Webhook.html).
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialOrd, Ord, Serialize)]
#[allow(derive_hash_xor_eq)]
pub struct WebhookId(pub u64);

/// An identifier for an audit log entry.
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialOrd, Ord, Serialize)]
#[allow(derive_hash_xor_eq)]
pub struct AuditLogEntryId(pub u64);

id_u64! {
    ApplicationId;
    ChannelId;
    EmojiId;
    GuildId;
    IntegrationId;
    MessageId;
    RoleId;
    UserId;
    WebhookId;
    AuditLogEntryId;
}
<|endoftext|>


<commit_before>//  Copyright 2015 Nathanael Merrill

//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at

//    http://www.apache.org/licenses/LICENSE-2.0

//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.

use std::string;

pub struct Playlist {
    music: string::String,
}

impl Playlist {
    pub fn new(song: &str) -> Playlist {
        Playlist{music: song.to_string()}
    }

    pub fn get_next_song(&self) -> &str {
        &self.music
    }
}
<commit_msg>Make playlist module work for multiple songs.<commit_after>//  Copyright 2015 Nathanael Merrill
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.

use std::string;

pub struct Playlist {
    songs: Vec<String>,
    song_index: i32,
}

impl Playlist {
    pub fn new(songs: Vec<String>) -> Playlist {
        Playlist{songs: songs,
                 song_index: -1}
    }

    pub fn get_next_song(&mut self) -> Option<&str> {
        self.song_index += 1;
        match self.songs.get(self.song_index as usize) {
            Some(a) => Some(&a),
            None => None,
        }
    }
}
<|endoftext|>


<commit_before>/*
 * How to read a file.
 * Future work: as a variant, we may use the C bindings to call mmap/munmap
 */

/* read the file path by calling the read_whole_file_str function */
fn read_file_whole(path: ~str) -> ~str {
   let res = io::read_whole_file_str(&Path(path));
   if result::is_err(&res) {
      fail!(~"file_reader error: " + result::get_err(&res));
   }
   res.get()
}

/* read the file path line by line */
fn read_file_lines(path: ~str) -> ~str {
   let res = io::file_reader(&Path(path));
   if result::is_err(&res) {
      fail!(~"file_reader error: " + result::get_err(&res));
   }

   let mut content = ~"";
   let reader = res.get();
   loop {
      let line = (~(reader as io::ReaderUtil)).read_line();
      if reader.eof() {
         break;
      }
      // read_line does not return the '\n', so we add it
      content += line + ~"\n";
   }

   content
}

fn main() {
   let filename = ~"read_file.rs";
   //let content = read_file_whole(copy filename);
   let content = read_file_lines(copy filename);
   io::println(~"the content of " + filename + ~" is [\n" + content + ~"]");
}
<commit_msg>read_file.rs fails to compile<commit_after>/*
 * How to read a file.
 * Future work: as a variant, we may use the C bindings to call mmap/munmap
 */

/* read the file path by calling the read_whole_file_str function */
fn read_file_whole(path: ~str) -> ~str {
   let res = io::read_whole_file_str(&Path(path));
   if result::is_err(&res) {
      fail!(~"file_reader error: " + result::get_err(&res));
   }
   res.get()
}

/* read the file path line by line */
fn read_file_lines(path: ~str) -> ~str {
   let res = io::file_reader(&Path(path));
   if result::is_err(&res) {
      fail!(~"file_reader error: " + result::get_err(&res));
   }

   let mut content = ~"";
   let reader = res.get();
   loop {
      //FIXME: rust 0.6, this line does not compile:
      //error: a sigil (`@`, `~`, or `&`) must be specified when casting to a trait
      let line = (reader as io::ReaderUtil).read_line();
      if reader.eof() {
         break;
      }
      // read_line does not return the '\n', so we add it
      content += line + ~"\n";
   }

   content
}

fn main() {
   let filename = ~"read_file.rs";
   //let content = read_file_whole(copy filename);
   let content = read_file_lines(copy filename);
   io::println(~"the content of " + filename + ~" is [\n" + content + ~"]");
}
<|endoftext|>


<commit_before>use rand;
use rand::Rng;
use rand::distributions::{IndependentSample, Range};
use std::thread;
use std::sync::{Mutex, MutexGuard};
use time;
use std::time::Duration;
use std::collections::{BTreeMap, HashMap};
use self::state_machine::master::{MasterStateMachine, StateMachineCmds};
use std::cmp::min;
use std::cell::RefCell;
use bifrost_plugins::hash_str;

#[macro_use]
mod state_machine;

trait RaftMsg {
    fn encode(&self) -> (usize, Vec<u8>);
}

const CHECKER_MS: u64 = 50;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct LogEntry {
    id: u64,
    term: u64,
    sm_id: u64,
    fn_id: u64,
    data: Vec<u8>
}

type LogEntries = Vec<LogEntry>;

service! {
    rpc append_entries(term: u64, leaderId: u64, prev_log_id: u64, prev_log_term: u64, entries: Option<LogEntries>, leader_commit: u64) -> (u64, bool);
    rpc request_vote(term: u64, candidate_id: u64, last_log_id: u64, last_log_term: u64) -> (u64, bool); // term, voteGranted
    rpc install_snapshot(term: u64, leader_id: u64, last_included_index: u64, last_included_term: u64, data: Vec<u8>, done: bool) -> u64;
}

fn gen_rand(lower: u64, higher: u64) -> u64 {
    let between = Range::new(lower, higher);
    let mut rng = rand::thread_rng();
    between.ind_sample(&mut rng) + 1
}

fn get_time() -> u64 {
    let timespec = time::get_time();
    let mills: f64 = timespec.sec as f64 + (timespec.nsec as f64 / 1000.0 / 1000.0 / 1000.0 );
    mills as u64
}

fn gen_timeout() -> u64 {
    gen_rand(100, 500)
}

pub struct LeaderMeta {
    last_updated: u64,
    next_index: HashMap<u64, u64>,
    match_index: HashMap<u64, u64>,
}

impl LeaderMeta {
    fn new() -> LeaderMeta {
        LeaderMeta{
            last_updated: get_time(),
            next_index: HashMap::new(),
            match_index: HashMap::new(),
        }
    }
}

pub struct FollowerMeta {
    leader_id: u64,
}

impl FollowerMeta {
    fn new() -> FollowerMeta {
        FollowerMeta{
            leader_id: 0
        }
    }
    fn with_leader(id: u64) -> FollowerMeta {
        FollowerMeta{
            leader_id: id
        }
    }
}

pub struct CandidateMeta {

}

impl CandidateMeta {
    fn  new() -> CandidateMeta {
        CandidateMeta{

        }
    }
}

pub enum Membership {
    LEADER(LeaderMeta),
    FOLLOWER(FollowerMeta),
    CANDIDATE(CandidateMeta),
    OFFLINE,
}

pub struct RaftMeta {
    term: u64,
    vote_for: Option<u64>,
    timeout: u64,
    last_checked: u64,
    membership: Membership,
    logs: BTreeMap<u64, LogEntry>,
    state_machine: RefCell<MasterStateMachine>,
    commit_index: u64,
    last_applied: u64,
}

#[derive(Clone)]
pub enum Storage {
    MEMORY,
    DISK(String),
}

impl Storage {
    pub fn Default() -> Storage {
        Storage::MEMORY
    }
}

#[derive(Clone)]
pub struct Options {
    pub storage: Storage,
    pub address: String,
}

pub struct RaftServer {
    meta: Arc<Mutex<RaftMeta>>,
    pub id: u64,
    pub options: Options,
}

enum CheckerAction {
    SEND_HEARTBEAT,
    BECOME_CANDIDATE,
    EXIT_LOOP,
    NONE
}
impl RaftServer {
    pub fn new(opts: Options) -> Arc<RaftServer> {
        let server = Arc::new(RaftServer {
            meta: Arc::new(Mutex::new(
                RaftMeta {
                    term: 0, //TODO: read from persistent state
                    vote_for: None, //TODO: read from persistent state
                    timeout: gen_timeout(), // 10~500 ms for timeout
                    last_checked: get_time(),
                    membership: Membership::FOLLOWER(FollowerMeta::new()),
                    logs: BTreeMap::new(), //TODO: read from persistent state
                    state_machine: RefCell::new(MasterStateMachine::new()),
                    commit_index: 0,
                    last_applied: 0,
                }
            )),
            options: opts.clone(),
            id: hash_str(opts.address.clone()),
        });
        let svr_ref = server.clone();
        thread::spawn(move ||{
            listen(svr_ref, &opts.address);
        });
        let checker_ref = server.clone();
        thread::spawn(move ||{
            let server = checker_ref;
            loop {
                {
                    let mut meta = server.meta.lock().unwrap(); //WARNING: Reentering not supported
                    let action = match meta.membership {
                        Membership::LEADER(ref leader_meta) => {
                            if get_time() > (leader_meta.last_updated + CHECKER_MS) {
                                CheckerAction::SEND_HEARTBEAT
                            } else {
                                CheckerAction::NONE
                            }
                        },
                        Membership::FOLLOWER(_) | Membership::CANDIDATE(_) => {
                            if get_time() > (meta.timeout + meta.last_checked) {
                                //Timeout, require election
                                CheckerAction::BECOME_CANDIDATE
                            } else {
                                CheckerAction::NONE
                            }
                        },
                        Membership::OFFLINE => {
                            CheckerAction::EXIT_LOOP
                        }
                    };
                    match action {
                        CheckerAction::SEND_HEARTBEAT => {
                            server.send_heartbeat(&mut meta, None);
                        },
                        CheckerAction::BECOME_CANDIDATE => {
                            server.become_candidate(&mut meta);
                        },
                        CheckerAction::EXIT_LOOP => {
                            break;
                        },
                        CheckerAction::NONE => {}
                    }
                }
                thread::sleep(Duration::from_millis(CHECKER_MS));
            }
        });
        server
    }
    fn become_candidate(&self, meta: &mut MutexGuard<RaftMeta>) {
        self.reset_last_checked(meta);
        meta.term += 1;
        meta.vote_for = Some(self.id);
        meta.membership = Membership::CANDIDATE(CandidateMeta::new());

    }
    fn become_follower(&self, meta: &mut MutexGuard<RaftMeta>, leader_id: u64) {
        meta.membership = Membership::FOLLOWER(FollowerMeta::with_leader(leader_id));
    }
    fn become_leader(&self, meta: &mut MutexGuard<RaftMeta>) {
        meta.membership = Membership::LEADER(LeaderMeta::new());
    }
    fn send_heartbeat(&self, meta: &mut MutexGuard<RaftMeta>, entries: Option<LogEntries>) {

    }

    //check term number, return reject = false if server term is stale
    fn check_term(&self, meta: &mut MutexGuard<RaftMeta>, remote_term: u64, leader_id: u64) -> bool {
        if remote_term > meta.term {
            meta.term = remote_term;
            meta.vote_for = None;
            self.become_follower(meta, leader_id)
        } else if remote_term < meta.term {
            return false;
        }
        return true;
    }

    fn check_commit(&self, meta: &mut MutexGuard<RaftMeta>) { //not need to return result for follower
        while meta.commit_index > meta.last_applied {
            (*meta).last_applied += 1;
            let last_applied = meta.last_applied;
            if let Some(entry) = meta.logs.get(&last_applied) {
                meta.state_machine.borrow_mut().commit(&entry);
            };
        }
    }
    fn reset_last_checked(&self, meta: &mut MutexGuard<RaftMeta>) {
        meta.last_checked = get_time();
        meta.timeout = gen_timeout();
    }
}

impl Server for RaftServer {
    fn append_entries(
        &self,
        term: u64, leader_id: u64, prev_log_id: u64,
        prev_log_term: u64, entries: Option<LogEntries>,
        leader_commit: u64
    ) -> Result<(u64, bool), ()>  {
        let mut meta = self.meta.lock().unwrap();
        let term_ok = self.check_term(&mut meta, term, leader_id); // RI, 1
        self.reset_last_checked(&mut meta);
        if term_ok {
            self.check_commit(&mut meta);
            { //RI, 2
                let contains_prev_log = (*meta).logs.contains_key(&prev_log_id);
                let mut log_mismatch = false;
                if contains_prev_log {
                    let entry = (*meta).logs.get(&prev_log_id).unwrap();
                    log_mismatch = entry.term != prev_log_term;
                } else {
                    return Ok((meta.term, false))
                }
                if log_mismatch { //RI, 3
                    let keys: Vec<u64> = (*meta).logs.keys().cloned().collect();
                    for id in keys {
                        if id >= prev_log_id {
                            (*meta).logs.remove(&id);
                        }
                    }
                    return Ok((meta.term, false))
                }
            }
            if let Some(entries) = entries { // entry not empty
                let entries_len = entries.len();
                for entry in entries {
                    meta.logs.entry(entry.id).or_insert(entry);// RI, 4
                }
                if leader_commit > meta.commit_index { //RI, 5
                    meta.commit_index = min(leader_commit, prev_log_id + entries_len as u64);
                }
            }
            Ok((meta.term, true))
        } else {
            Ok((meta.term, false))
        }
    }

    fn request_vote(
        &self,
        term: u64, candidate_id: u64,
        last_log_id: u64, last_log_term: u64
    ) -> Result<(u64, bool), ()> {
        let mut meta = self.meta.lock().unwrap();
        let vote_for = meta.vote_for;
        let mut vote_granted = false;
        if term >= meta.term {
            self.check_commit(&mut meta);
            if vote_for.is_none() || vote_for.unwrap() == candidate_id {
                if !meta.logs.is_empty() {
                    let (last_id, _) = meta.logs.iter().next_back().unwrap();
                    let last_term = meta.logs.get(last_id).unwrap().term;
                    if last_log_id >= *last_id && last_log_term >= last_term {
                        vote_granted = true;
                    }
                } else {
                    vote_granted = true;
                }
            }
        }
        if vote_granted {
            meta.vote_for = Some(candidate_id);
        }
        Ok((meta.term, vote_granted))
    }

    fn install_snapshot(
        &self,
        term: u64, leader_id: u64, last_included_index: u64,
        last_included_term: u64, data: Vec<u8>, done: bool
    ) -> Result<u64, ()> {
        let mut meta = self.meta.lock().unwrap();
        let term_ok = self.check_term(&mut meta, term, leader_id);
        if term_ok {
            self.check_commit(&mut meta);
        }
        Ok(meta.term)
    }
}
<commit_msg>rename for codestyle<commit_after>use rand;
use rand::Rng;
use rand::distributions::{IndependentSample, Range};
use std::thread;
use std::sync::{Mutex, MutexGuard};
use time;
use std::time::Duration;
use std::collections::{BTreeMap, HashMap};
use self::state_machine::master::{MasterStateMachine, StateMachineCmds};
use std::cmp::min;
use std::cell::RefCell;
use bifrost_plugins::hash_str;

#[macro_use]
mod state_machine;

trait RaftMsg {
    fn encode(&self) -> (usize, Vec<u8>);
}

const CHECKER_MS: u64 = 50;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct LogEntry {
    id: u64,
    term: u64,
    sm_id: u64,
    fn_id: u64,
    data: Vec<u8>
}

type LogEntries = Vec<LogEntry>;

service! {
    rpc append_entries(term: u64, leaderId: u64, prev_log_id: u64, prev_log_term: u64, entries: Option<LogEntries>, leader_commit: u64) -> (u64, bool);
    rpc request_vote(term: u64, candidate_id: u64, last_log_id: u64, last_log_term: u64) -> (u64, bool); // term, voteGranted
    rpc install_snapshot(term: u64, leader_id: u64, last_included_index: u64, last_included_term: u64, data: Vec<u8>, done: bool) -> u64;
}

fn gen_rand(lower: u64, higher: u64) -> u64 {
    let between = Range::new(lower, higher);
    let mut rng = rand::thread_rng();
    between.ind_sample(&mut rng) + 1
}

fn get_time() -> u64 {
    let timespec = time::get_time();
    let mills: f64 = timespec.sec as f64 + (timespec.nsec as f64 / 1000.0 / 1000.0 / 1000.0 );
    mills as u64
}

fn gen_timeout() -> u64 {
    gen_rand(100, 500)
}

pub struct LeaderMeta {
    last_updated: u64,
    next_index: HashMap<u64, u64>,
    match_index: HashMap<u64, u64>,
}

impl LeaderMeta {
    fn new() -> LeaderMeta {
        LeaderMeta{
            last_updated: get_time(),
            next_index: HashMap::new(),
            match_index: HashMap::new(),
        }
    }
}

pub struct FollowerMeta {
    leader_id: u64,
}

impl FollowerMeta {
    fn new() -> FollowerMeta {
        FollowerMeta{
            leader_id: 0
        }
    }
    fn with_leader(id: u64) -> FollowerMeta {
        FollowerMeta{
            leader_id: id
        }
    }
}

pub struct CandidateMeta {

}

impl CandidateMeta {
    fn  new() -> CandidateMeta {
        CandidateMeta{

        }
    }
}

pub enum Membership {
    Leader(LeaderMeta),
    Follower(FollowerMeta),
    Candidate(CandidateMeta),
    Offline,
}

pub struct RaftMeta {
    term: u64,
    vote_for: Option<u64>,
    timeout: u64,
    last_checked: u64,
    membership: Membership,
    logs: BTreeMap<u64, LogEntry>,
    state_machine: RefCell<MasterStateMachine>,
    commit_index: u64,
    last_applied: u64,
}

#[derive(Clone)]
pub enum Storage {
    MEMORY,
    DISK(String),
}

impl Storage {
    pub fn Default() -> Storage {
        Storage::MEMORY
    }
}

#[derive(Clone)]
pub struct Options {
    pub storage: Storage,
    pub address: String,
}

pub struct RaftServer {
    meta: Arc<Mutex<RaftMeta>>,
    pub id: u64,
    pub options: Options,
}

enum CheckerAction {
    SendHeartbeat,
    BecomeCandidate,
    ExitLoop,
    None
}
impl RaftServer {
    pub fn new(opts: Options) -> Arc<RaftServer> {
        let server = Arc::new(RaftServer {
            meta: Arc::new(Mutex::new(
                RaftMeta {
                    term: 0, //TODO: read from persistent state
                    vote_for: None, //TODO: read from persistent state
                    timeout: gen_timeout(), // 10~500 ms for timeout
                    last_checked: get_time(),
                    membership: Membership::Follower(FollowerMeta::new()),
                    logs: BTreeMap::new(), //TODO: read from persistent state
                    state_machine: RefCell::new(MasterStateMachine::new()),
                    commit_index: 0,
                    last_applied: 0,
                }
            )),
            options: opts.clone(),
            id: hash_str(opts.address.clone()),
        });
        let svr_ref = server.clone();
        thread::spawn(move ||{
            listen(svr_ref, &opts.address);
        });
        let checker_ref = server.clone();
        thread::spawn(move ||{
            let server = checker_ref;
            loop {
                {
                    let mut meta = server.meta.lock().unwrap(); //WARNING: Reentering not supported
                    let action = match meta.membership {
                        Membership::Leader(ref leader_meta) => {
                            if get_time() > (leader_meta.last_updated + CHECKER_MS) {
                                CheckerAction::SendHeartbeat
                            } else {
                                CheckerAction::None
                            }
                        },
                        Membership::Follower(_) | Membership::Candidate(_) => {
                            if get_time() > (meta.timeout + meta.last_checked) {
                                //Timeout, require election
                                CheckerAction::BecomeCandidate
                            } else {
                                CheckerAction::None
                            }
                        },
                        Membership::Offline => {
                            CheckerAction::ExitLoop
                        }
                    };
                    match action {
                        CheckerAction::SendHeartbeat => {
                            server.send_heartbeat(&mut meta, None);
                        },
                        CheckerAction::BecomeCandidate => {
                            server.become_candidate(&mut meta);
                        },
                        CheckerAction::ExitLoop => {
                            break;
                        },
                        CheckerAction::None => {}
                    }
                }
                thread::sleep(Duration::from_millis(CHECKER_MS));
            }
        });
        server
    }
    fn become_candidate(&self, meta: &mut MutexGuard<RaftMeta>) {
        self.reset_last_checked(meta);
        meta.term += 1;
        meta.vote_for = Some(self.id);
        meta.membership = Membership::Candidate(CandidateMeta::new());

    }
    fn become_follower(&self, meta: &mut MutexGuard<RaftMeta>, leader_id: u64) {
        meta.membership = Membership::Follower(FollowerMeta::with_leader(leader_id));
    }
    fn become_leader(&self, meta: &mut MutexGuard<RaftMeta>) {
        meta.membership = Membership::Leader(LeaderMeta::new());
    }
    fn send_heartbeat(&self, meta: &mut MutexGuard<RaftMeta>, entries: Option<LogEntries>) {

    }

    //check term number, return reject = false if server term is stale
    fn check_term(&self, meta: &mut MutexGuard<RaftMeta>, remote_term: u64, leader_id: u64) -> bool {
        if remote_term > meta.term {
            meta.term = remote_term;
            meta.vote_for = None;
            self.become_follower(meta, leader_id)
        } else if remote_term < meta.term {
            return false;
        }
        return true;
    }

    fn check_commit(&self, meta: &mut MutexGuard<RaftMeta>) { //not need to return result for follower
        while meta.commit_index > meta.last_applied {
            (*meta).last_applied += 1;
            let last_applied = meta.last_applied;
            if let Some(entry) = meta.logs.get(&last_applied) {
                meta.state_machine.borrow_mut().commit(&entry);
            };
        }
    }
    fn reset_last_checked(&self, meta: &mut MutexGuard<RaftMeta>) {
        meta.last_checked = get_time();
        meta.timeout = gen_timeout();
    }
}

impl Server for RaftServer {
    fn append_entries(
        &self,
        term: u64, leader_id: u64, prev_log_id: u64,
        prev_log_term: u64, entries: Option<LogEntries>,
        leader_commit: u64
    ) -> Result<(u64, bool), ()>  {
        let mut meta = self.meta.lock().unwrap();
        let term_ok = self.check_term(&mut meta, term, leader_id); // RI, 1
        self.reset_last_checked(&mut meta);
        if term_ok {
            self.check_commit(&mut meta);
            { //RI, 2
                let contains_prev_log = (*meta).logs.contains_key(&prev_log_id);
                let mut log_mismatch = false;
                if contains_prev_log {
                    let entry = (*meta).logs.get(&prev_log_id).unwrap();
                    log_mismatch = entry.term != prev_log_term;
                } else {
                    return Ok((meta.term, false))
                }
                if log_mismatch { //RI, 3
                    let keys: Vec<u64> = (*meta).logs.keys().cloned().collect();
                    for id in keys {
                        if id >= prev_log_id {
                            (*meta).logs.remove(&id);
                        }
                    }
                    return Ok((meta.term, false))
                }
            }
            if let Some(entries) = entries { // entry not empty
                let entries_len = entries.len();
                for entry in entries {
                    meta.logs.entry(entry.id).or_insert(entry);// RI, 4
                }
                if leader_commit > meta.commit_index { //RI, 5
                    meta.commit_index = min(leader_commit, prev_log_id + entries_len as u64);
                }
            }
            Ok((meta.term, true))
        } else {
            Ok((meta.term, false))
        }
    }

    fn request_vote(
        &self,
        term: u64, candidate_id: u64,
        last_log_id: u64, last_log_term: u64
    ) -> Result<(u64, bool), ()> {
        let mut meta = self.meta.lock().unwrap();
        let vote_for = meta.vote_for;
        let mut vote_granted = false;
        if term >= meta.term {
            self.check_commit(&mut meta);
            if vote_for.is_none() || vote_for.unwrap() == candidate_id {
                if !meta.logs.is_empty() {
                    let (last_id, _) = meta.logs.iter().next_back().unwrap();
                    let last_term = meta.logs.get(last_id).unwrap().term;
                    if last_log_id >= *last_id && last_log_term >= last_term {
                        vote_granted = true;
                    }
                } else {
                    vote_granted = true;
                }
            }
        }
        if vote_granted {
            meta.vote_for = Some(candidate_id);
        }
        Ok((meta.term, vote_granted))
    }

    fn install_snapshot(
        &self,
        term: u64, leader_id: u64, last_included_index: u64,
        last_included_term: u64, data: Vec<u8>, done: bool
    ) -> Result<u64, ()> {
        let mut meta = self.meta.lock().unwrap();
        let term_ok = self.check_term(&mut meta, term, leader_id);
        if term_ok {
            self.check_commit(&mut meta);
        }
        Ok(meta.term)
    }
}
<|endoftext|>


<commit_before>//!
//! The script interpreter runs scripts directly from their parse tree. This is
//! a fairly slow way to run scripts but comparatively simple to implement.
//!

use std::result::Result;
use serde_json::*;

use gossyp_base::*;
use gossyp_base::basic::*;

use super::script::*;
use super::evaluate_statement::*;
use super::bind_statement::*;
use super::bound_script::*;

///
/// A tool representing a script that will be interepreted
///
pub struct InterpretedScriptTool {
    statements: Script
}

///
/// Script evaluation error
///
#[derive(Serialize, Deserialize)]
pub enum ScriptEvaluationError {
    /// Tried to evaluate an expression type that's not implemented yet
    ExpressionNotImplemented,

    /// Tried to evaluate a statement type that's not implemented yet
    StatementNotImplemented,

    /// Tried to look up a tool and it couldn't be found
    ToolNameNotFound,

    /// Found an expression that can't be treated as a tool where a tool name was expected
    ExpressionDoesNotEvaluateToTool,

    /// Expressions used as keys in a map must evaluate to a string
    MapKeysMustEvaluateToAString,

    /// In index expression like foo[bar], foo must be either an array, a string or a map
    IndexMustApplyToAnArrayOrAMap,

    /// When indexing an array or a string, the index must be a number
    ArrayIndexMustBeANumber,

    /// When indexing a map, the index must be a string
    MapIndexMustBeAString,

    /// When indexing an array, the index must be in the array bounds
    IndexOutOfBounds,

    /// Object value is not present in a map
    ObjectValueNotPresent,

    /// In a field access (a.b), the '.b' part must be an identifier
    FieldMustBeIdentifier
}

impl InterpretedScriptTool {
    ///
    /// Creates a tool that can evaluate a script
    ///
    pub fn new_script_eval_tool() -> Box<Tool> {
        Box::new(make_dynamic_tool(|script: Vec<Script>, environment: &Environment| {
            let script_tool = InterpretedScriptTool::from_statements(script);

            script_tool.invoke_json(Value::Null, environment)
        }))
    }

    ///
    /// Creates a new interpreted script tool from a set of statements
    ///
    pub fn from_statements(statements: Vec<Script>) -> InterpretedScriptTool {
        InterpretedScriptTool { statements: Script::Sequence(statements) }
    }
}

impl Tool for InterpretedScriptTool {
    fn invoke_json(&self, _input: Value, environment: &Environment) -> Result<Value, Value> {
        // Make the environment that this script will run in
        let mut script_environment = ScriptExecutionEnvironment::new(environment);

        // Bind the values contained within the script
        let bound_script = bind_statement(&self.statements, &mut script_environment)?;

        // Evaluate them
        evaluate_statement(&bound_script, &mut script_environment)
    }
}

///
/// Represents an execution environment for a running script
///
pub struct ScriptExecutionEnvironment<'a> {
    /// Current values of the variables in this environment
    variable_values: Vec<Value>,

    /// The environment where tools are drawn from
    parent_environment: &'a Environment
}

impl<'a> ScriptExecutionEnvironment<'a> {
    ///
    /// Creates a new script execution environment
    ///
    pub fn new(parent_environment: &'a Environment) -> ScriptExecutionEnvironment<'a> {
        ScriptExecutionEnvironment { variable_values: vec![], parent_environment: parent_environment }
    }

    ///
    /// Fetches a tool from this environment
    ///
    #[inline]
    pub fn get_json_tool(&self, tool: &str) -> Result<Box<Tool>, RetrieveToolError> {
        self.parent_environment.get_json_tool(tool)
    }

    ///
    /// Invokes a JSON tool in this environment
    ///
    #[inline]
    pub fn invoke_tool(&self, tool: &Box<Tool>, input: Value) -> Result<Value, Value> {
        tool.invoke_json(input, self.parent_environment)
    }
}
<commit_msg>Fix a warning<commit_after>//!
//! The script interpreter runs scripts directly from their parse tree. This is
//! a fairly slow way to run scripts but comparatively simple to implement.
//!

use std::result::Result;
use serde_json::*;

use gossyp_base::*;
use gossyp_base::basic::*;

use super::script::Script;
use super::evaluate_statement::evaluate_statement;
use super::bind_statement::bind_statement;

///
/// A tool representing a script that will be interepreted
///
pub struct InterpretedScriptTool {
    statements: Script
}

///
/// Script evaluation error
///
#[derive(Serialize, Deserialize)]
pub enum ScriptEvaluationError {
    /// Tried to evaluate an expression type that's not implemented yet
    ExpressionNotImplemented,

    /// Tried to evaluate a statement type that's not implemented yet
    StatementNotImplemented,

    /// Tried to look up a tool and it couldn't be found
    ToolNameNotFound,

    /// Found an expression that can't be treated as a tool where a tool name was expected
    ExpressionDoesNotEvaluateToTool,

    /// Expressions used as keys in a map must evaluate to a string
    MapKeysMustEvaluateToAString,

    /// In index expression like foo[bar], foo must be either an array, a string or a map
    IndexMustApplyToAnArrayOrAMap,

    /// When indexing an array or a string, the index must be a number
    ArrayIndexMustBeANumber,

    /// When indexing a map, the index must be a string
    MapIndexMustBeAString,

    /// When indexing an array, the index must be in the array bounds
    IndexOutOfBounds,

    /// Object value is not present in a map
    ObjectValueNotPresent,

    /// In a field access (a.b), the '.b' part must be an identifier
    FieldMustBeIdentifier
}

impl InterpretedScriptTool {
    ///
    /// Creates a tool that can evaluate a script
    ///
    pub fn new_script_eval_tool() -> Box<Tool> {
        Box::new(make_dynamic_tool(|script: Vec<Script>, environment: &Environment| {
            let script_tool = InterpretedScriptTool::from_statements(script);

            script_tool.invoke_json(Value::Null, environment)
        }))
    }

    ///
    /// Creates a new interpreted script tool from a set of statements
    ///
    pub fn from_statements(statements: Vec<Script>) -> InterpretedScriptTool {
        InterpretedScriptTool { statements: Script::Sequence(statements) }
    }
}

impl Tool for InterpretedScriptTool {
    fn invoke_json(&self, _input: Value, environment: &Environment) -> Result<Value, Value> {
        // Make the environment that this script will run in
        let mut script_environment = ScriptExecutionEnvironment::new(environment);

        // Bind the values contained within the script
        let bound_script = bind_statement(&self.statements, &mut script_environment)?;

        // Evaluate them
        evaluate_statement(&bound_script, &mut script_environment)
    }
}

///
/// Represents an execution environment for a running script
///
pub struct ScriptExecutionEnvironment<'a> {
    /// Current values of the variables in this environment
    variable_values: Vec<Value>,

    /// The environment where tools are drawn from
    parent_environment: &'a Environment
}

impl<'a> ScriptExecutionEnvironment<'a> {
    ///
    /// Creates a new script execution environment
    ///
    pub fn new(parent_environment: &'a Environment) -> ScriptExecutionEnvironment<'a> {
        ScriptExecutionEnvironment { variable_values: vec![], parent_environment: parent_environment }
    }

    ///
    /// Fetches a tool from this environment
    ///
    #[inline]
    pub fn get_json_tool(&self, tool: &str) -> Result<Box<Tool>, RetrieveToolError> {
        self.parent_environment.get_json_tool(tool)
    }

    ///
    /// Invokes a JSON tool in this environment
    ///
    #[inline]
    pub fn invoke_tool(&self, tool: &Box<Tool>, input: Value) -> Result<Value, Value> {
        tool.invoke_json(input, self.parent_environment)
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use serialize::json::ToJson;
use template::{Template, TemplateError};
use render::{Renderable, RenderError, RenderContext};
use helpers::{HelperDef};
use context::{Context};
use helpers;

pub struct Registry {
    templates: HashMap<String, Template>,
    helpers: HashMap<String, Box<HelperDef + 'static>>
}

impl Registry {
    pub fn new() -> Registry {
        let mut r = Registry {
            templates: HashMap::new(),
            helpers: HashMap::new()
        };

        r.register_helper("if", Box::new(helpers::IF_HELPER));
        r.register_helper("unless", Box::new(helpers::UNLESS_HELPER));
        r.register_helper("each", Box::new(helpers::EACH_HELPER));
        r.register_helper("with", Box::new(helpers::WITH_HELPER));
        r.register_helper("lookup", Box::new(helpers::LOOKUP_HELPER));
        r.register_helper("raw", Box::new(helpers::RAW_HELPER));
        r.register_helper(">", Box::new(helpers::INCLUDE_HELPER));
        r.register_helper("block", Box::new(helpers::BLOCK_HELPER));
        r.register_helper("partial", Box::new(helpers::PARTIAL_HELPER));
        r.register_helper("log", Box::new(helpers::LOG_HELPER));

        r
    }

    pub fn register_template(&mut self, name: &str, template: Template) {
        self.templates.insert(name.to_string(), template);
    }

    pub fn register_template_string(&mut self, name: &str, tpl_str: String) -> Result<(), TemplateError>{
        let t = Template::compile(tpl_str);
        if let Ok(tpl) = t {
            self.templates.insert(name.to_string(), tpl);
            Ok(())
        } else {
            Err(t.err().unwrap())
        }
    }

    pub fn register_helper(&mut self, name: &str, def: Box<HelperDef + 'static>) -> Option<Box<HelperDef + 'static>> {
        self.helpers.insert(name.to_string(), def)
    }

    pub fn get_template(&self, name: &String) -> Option<&Template> {
        self.templates.get(name)
    }

    pub fn get_helper(&self, name: &String) -> Option<&Box<HelperDef + 'static>> {
        self.helpers.get(name)
    }

    pub fn get_templates(&self) -> &HashMap<String, Template> {
        &self.templates
    }

    pub fn render<T>(&self, name: &str, ctx: &T) -> Result<String, RenderError>
        where T: ToJson {
            let template = self.get_template(&name.to_string());
            let context = Context::wraps(ctx);
            let mut render_context = RenderContext::new();
            if let Some(t) = template {
                (*t).render(&context, self, &mut render_context)
            } else {
                Err(RenderError{
                    desc: "Template not found."
                })
            }
        }
}

#[cfg(test)]
mod test {
    use template::{Template, Helper};
    use registry::{Registry};
    use render::{RenderContext, Renderable, RenderError};
    use helpers::{HelperDef};
    use context::{Context};

    #[derive(Clone, Copy)]
    struct DummyHelper;

    impl HelperDef for DummyHelper {
        fn call(&self, c: &Context, h: &Helper, r: &Registry, rc: &mut RenderContext) -> Result<String, RenderError> {
            h.template().unwrap().render(c, r, rc)
        }
    }

    static DUMMY_HELPER: DummyHelper = DummyHelper;

    #[test]
    fn test_registry_operations() {
        let mut r = Registry::new();

        let t = Template::compile("

".to_string()).ok().unwrap();
        r.register_template("index", t.clone());

        assert_eq!((*r.get_template(&("index".to_string())).unwrap()).to_string(),
                   t.to_string());
        assert_eq!(r.templates.len(), 1);

        r.register_helper("dummy", Box::new(DUMMY_HELPER));

        // built-in helpers plus 1
        assert_eq!(r.helpers.len(), 10+1);
    }
}
<commit_msg>(feat) added option to unregister template and clear all.<commit_after>use std::collections::HashMap;
use serialize::json::ToJson;
use template::{Template, TemplateError};
use render::{Renderable, RenderError, RenderContext};
use helpers::{HelperDef};
use context::{Context};
use helpers;

pub struct Registry {
    templates: HashMap<String, Template>,
    helpers: HashMap<String, Box<HelperDef + 'static>>
}

impl Registry {
    pub fn new() -> Registry {
        let mut r = Registry {
            templates: HashMap::new(),
            helpers: HashMap::new()
        };

        r.register_helper("if", Box::new(helpers::IF_HELPER));
        r.register_helper("unless", Box::new(helpers::UNLESS_HELPER));
        r.register_helper("each", Box::new(helpers::EACH_HELPER));
        r.register_helper("with", Box::new(helpers::WITH_HELPER));
        r.register_helper("lookup", Box::new(helpers::LOOKUP_HELPER));
        r.register_helper("raw", Box::new(helpers::RAW_HELPER));
        r.register_helper(">", Box::new(helpers::INCLUDE_HELPER));
        r.register_helper("block", Box::new(helpers::BLOCK_HELPER));
        r.register_helper("partial", Box::new(helpers::PARTIAL_HELPER));
        r.register_helper("log", Box::new(helpers::LOG_HELPER));

        r
    }

    pub fn register_template(&mut self, name: &str, template: Template) {
        self.templates.insert(name.to_string(), template);
    }

    pub fn register_template_string(&mut self, name: &str, tpl_str: String) -> Result<(), TemplateError>{
        let t = Template::compile(tpl_str);
        if let Ok(tpl) = t {
            self.templates.insert(name.to_string(), tpl);
            Ok(())
        } else {
            Err(t.err().unwrap())
        }
    }

    pub fn unregister_template(&mut self, name: &String) {
        self.templates.remove(name);
    }

    pub fn register_helper(&mut self, name: &str, def: Box<HelperDef + 'static>) -> Option<Box<HelperDef + 'static>> {
        self.helpers.insert(name.to_string(), def)
    }

    pub fn get_template(&self, name: &String) -> Option<&Template> {
        self.templates.get(name)
    }

    pub fn get_helper(&self, name: &String) -> Option<&Box<HelperDef + 'static>> {
        self.helpers.get(name)
    }

    pub fn get_templates(&self) -> &HashMap<String, Template> {
        &self.templates
    }

    pub fn clear_templates(&mut self) {
        self.templates.clear();
    }

    pub fn render<T>(&self, name: &str, ctx: &T) -> Result<String, RenderError>
        where T: ToJson {
            let template = self.get_template(&name.to_string());
            let context = Context::wraps(ctx);
            let mut render_context = RenderContext::new();
            if let Some(t) = template {
                (*t).render(&context, self, &mut render_context)
            } else {
                Err(RenderError{
                    desc: "Template not found."
                })
            }
        }
}

#[cfg(test)]
mod test {
    use template::{Template, Helper};
    use registry::{Registry};
    use render::{RenderContext, Renderable, RenderError};
    use helpers::{HelperDef};
    use context::{Context};

    #[derive(Clone, Copy)]
    struct DummyHelper;

    impl HelperDef for DummyHelper {
        fn call(&self, c: &Context, h: &Helper, r: &Registry, rc: &mut RenderContext) -> Result<String, RenderError> {
            h.template().unwrap().render(c, r, rc)
        }
    }

    static DUMMY_HELPER: DummyHelper = DummyHelper;

    #[test]
    fn test_registry_operations() {
        let mut r = Registry::new();

        let t = Template::compile("

".to_string()).ok().unwrap();
        r.register_template("index", t.clone());

        let t2 = Template::compile("

".to_string()).ok().unwrap();
        r.register_template("index2", t2.clone());

        assert_eq!((*r.get_template(&("index".to_string())).unwrap()).to_string(),
                   t.to_string());
        assert_eq!(r.templates.len(), 2);

        r.unregister_template(&("index".to_string()));
        assert_eq!(r.templates.len(), 1);

        r.clear_templates();
        assert_eq!(r.templates.len(), 0);

        r.register_helper("dummy", Box::new(DUMMY_HELPER));

        // built-in helpers plus 1
        assert_eq!(r.helpers.len(), 10+1);
    }
}
<|endoftext|>


<commit_before>// fibonacci.rs
// Calulate Fibonacci numbers in Rust
//
// vim: ft=rust sw=4 ts=4
//

//extern crate num;

use num::bigint::BigInt;
use num::{One, Zero};

// a naive recursive implementation
pub fn fib_naive(n: u64) -> u64 {
    if n < 2 {
        n
    } else {
        fib_naive(n - 1) + fib_naive(n - 2)
    }
}

// optimzed tail-recursive implmentation
pub fn fib(n: u64) -> BigInt {
    fib_loop(n, BigInt::zero(), BigInt::one())
}
fn fib_loop(n: u64, a: BigInt, b: BigInt) -> BigInt {
    if n == 0 {
        return a;
    }
    return fib_loop(n - 1, b.clone(), a + b);
}
<commit_msg>- remove obsolete extern<commit_after>// fibonacci.rs
// Calulate Fibonacci numbers in Rust
//
// vim: ft=rust sw=4 ts=4
//

use num::bigint::BigInt;
use num::{One, Zero};

// a naive recursive implementation
pub fn fib_naive(n: u64) -> u64 {
    if n < 2 {
        n
    } else {
        fib_naive(n - 1) + fib_naive(n - 2)
    }
}

// optimzed tail-recursive implmentation
pub fn fib(n: u64) -> BigInt {
    fib_loop(n, BigInt::zero(), BigInt::one())
}
fn fib_loop(n: u64, a: BigInt, b: BigInt) -> BigInt {
    if n == 0 {
        return a;
    }
    return fib_loop(n - 1, b.clone(), a + b);
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::io;
use std::fmt;

const TITLE: (u16, u16) = (0x0134, 0x0143);
const CARTRIDGE_TYPE: u16 = 0x0147;
const ROM_SIZE: u16 = 0x0148;
const RAM_SIZE: u16 = 0x0149;

#[derive(Debug)]
pub enum MBC {
    ROM, MBC1,
    MBC2, MBC3,
    MBC4, MBC5
}

pub struct Cartridge(Vec<u8>);

impl Cartridge {

    /// Load rom file
    pub fn new<P: AsRef<Path>>(path: P) -> io::Result<Cartridge> {
        let mut rom: Vec<u8> = Vec::new();
        let mut file = File::open(path)?;
        let _ = file.read_to_end(&mut rom)?;
        Ok(Cartridge(rom))
    }

    /// Read a byte from the rom
    pub fn read_byte(&self, addr: u16) -> u8 {
        self.0[addr as usize]
    }

    /// Read a range of bytes from the rom
    pub fn read_range(&self, addr: (u16, u16)) -> Vec<u8> {
        let mut a: Vec<u8> = Vec::new();
        for x in addr.0..addr.1 {
            a.push(self.0[x as usize])
        }
        a
    }

    /// Read the rom's title
    pub fn read_title(&self) -> String {
        let mut title = String::with_capacity(16);
        for letter in self.read_range(TITLE) {
            if letter == 0 {
                break;
            }
            title.push(letter as char)
        }
        title
    }

    /// Read mem type
    pub fn cartridge_type(&self) -> MBC {
        match self.read_byte(CARTRIDGE_TYPE) {
            0x00 | 0x8 | 0x9 => MBC::ROM,
            0x1 | 0x2 | 0x3 => MBC::MBC1,
            0x5 | 0x6 => MBC::MBC2,
            0xF | 0x10 | 0x11 | 0x12 | 0x13 => MBC::MBC3,
            0x15 | 0x16 | 0x17 => MBC::MBC4,
            0x19 | 0x1B | 0x1C | 0x1D | 0x1E => MBC::MBC5,
            _ => unreachable!()
        }
    }

}

impl fmt::Debug for Cartridge {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "=== ROM DEBUG ===\n\
            > title game {}\n\
            > cartridge type: {:?}\n\
            > ROM size: {:#x}\n\
            > RAM size: {:#x}",
            self.read_title(),
            self.cartridge_type(),
            self.read_byte(ROM_SIZE),
            self.read_byte(RAM_SIZE))
    }
}
<commit_msg>read range memory allocation<commit_after>use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::io;
use std::fmt;

const TITLE: (u16, u16) = (0x0134, 0x0143);
const CARTRIDGE_TYPE: u16 = 0x0147;
const ROM_SIZE: u16 = 0x0148;
const RAM_SIZE: u16 = 0x0149;

#[derive(Debug)]
pub enum MBC {
    ROM, MBC1,
    MBC2, MBC3,
    MBC4, MBC5
}

pub struct Cartridge(Vec<u8>);

impl Cartridge {

    /// Load rom file
    pub fn new<P: AsRef<Path>>(path: P) -> io::Result<Cartridge> {
        let mut rom: Vec<u8> = Vec::new();
        let mut file = File::open(path)?;
        let _ = file.read_to_end(&mut rom)?;
        Ok(Cartridge(rom))
    }

    /// Read a byte from the rom
    pub fn read_byte(&self, addr: u16) -> u8 {
        self.0[addr as usize]
    }

    /// Read a range of bytes from the rom
    pub fn read_range(&self, addr: (u16, u16)) -> Vec<u8> {
        let mut a: Vec<u8> = Vec::with_capacity((addr.1 - addr.0) as usize);
        for x in addr.0..addr.1 {
            a.push(self.0[x as usize])
        }
        a
    }

    /// Read the rom's title
    pub fn read_title(&self) -> String {
        let mut title = String::with_capacity(16);
        for letter in self.read_range(TITLE) {
            if letter == 0 {
                break;
            }
            title.push(letter as char)
        }
        title
    }

    /// Read mem type
    pub fn cartridge_type(&self) -> MBC {
        match self.read_byte(CARTRIDGE_TYPE) {
            0x00 | 0x8  | 0x9 => MBC::ROM,
            0x1  | 0x2  | 0x3 => MBC::MBC1,
            0x5  | 0x6  => MBC::MBC2,
            0xF  | 0x10 | 0x11 | 0x12 | 0x13 => MBC::MBC3,
            0x15 | 0x16 | 0x17 => MBC::MBC4,
            0x19 | 0x1B | 0x1C | 0x1D | 0x1E => MBC::MBC5,
            _ => unreachable!()
        }
    }

}

impl fmt::Debug for Cartridge {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "=== ROM DEBUG ===\n\
            > title game {}\n\
            > cartridge type: {:?}\n\
            > ROM size: {:#x}\n\
            > RAM size: {:#x}",
            self.read_title(),
            self.cartridge_type(),
            self.read_byte(ROM_SIZE),
            self.read_byte(RAM_SIZE))
    }
}
<|endoftext|>