<commit_before>#![deny(missing_docs)]

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

extern crate sdl2;
extern crate piston;
extern crate shader_version;
extern crate gl;
extern crate num;

// External crates.
use std::mem::transmute;
use piston::window::{
    OpenGLWindow,
    ProcAddress,
    Window,
    AdvancedWindow,
    WindowSettings,
    Size,
};
use piston::input::{ keyboard, Button, MouseButton, Input, Motion };

pub use shader_version::OpenGL;

/// A widow implemented by SDL2 back-end.
pub struct Sdl2Window {
    /// SDL window handle.
    pub window: sdl2::video::Window,
    /// Allow dead code because this keeps track of the OpenGL context.
    /// Will be released on drop.
    #[allow(dead_code)]
    pub context: sdl2::video::GLContext,
    /// SDL context.
    pub sdl_context: sdl2::Sdl,
    should_close: bool,
    mouse_relative: Option<(f64, f64)>,
    exit_on_esc: bool,
    title: String,
    size: Size,
    draw_size: Size,
}

impl Sdl2Window {
    /// Creates a new game window for SDL2.
    pub fn new(opengl: OpenGL, settings: WindowSettings) -> Sdl2Window {
        let sdl_context = sdl2::init().everything().unwrap();

        // Not all drivers default to 32bit color, so explicitly set it to 32bit color.
        sdl2::video::gl_set_attribute(sdl2::video::GLAttr::GLRedSize, 8);
        sdl2::video::gl_set_attribute(sdl2::video::GLAttr::GLGreenSize, 8);
        sdl2::video::gl_set_attribute(sdl2::video::GLAttr::GLBlueSize, 8);
        sdl2::video::gl_set_attribute(sdl2::video::GLAttr::GLAlphaSize, 8);
        sdl2::video::gl_set_attribute(sdl2::video::GLAttr::GLStencilSize, 8);

        let (major, minor) = opengl.get_major_minor();
        sdl2::video::gl_set_attribute(
            sdl2::video::GLAttr::GLContextMajorVersion,
            major as i32
        );
        sdl2::video::gl_set_attribute(
            sdl2::video::GLAttr::GLContextMinorVersion,
            minor as i32
        );
        if opengl >= OpenGL::_3_2 {
            sdl2::video::gl_set_attribute(
                sdl2::video::GLAttr::GLContextProfileMask,
                sdl2::video::GLProfile::GLCoreProfile as i32
            );
        }
        if settings.get_samples() != 0 {
            sdl2::video::gl_set_attribute(
                sdl2::video::GLAttr::GLMultiSampleBuffers,
                1
            );
            sdl2::video::gl_set_attribute(
                sdl2::video::GLAttr::GLMultiSampleSamples,
                settings.get_samples() as i32
            );
        }

        let mut window_builder = sdl_context.window(&settings.get_title(), settings.get_size().width as u32, settings.get_size().height as u32);

        let window_builder = window_builder.position_centered()
            .opengl()
            .resizable();

        let window_builder = if settings.get_fullscreen() {
            window_builder.fullscreen()
        } else {
            window_builder
        };

        let window = window_builder.build();

        let window = match window {
            Ok(w) => w,
            Err(_) =>
                if settings.get_samples() != 0 {
                    // Retry without requiring anti-aliasing.
                    sdl2::video::gl_set_attribute(
                        sdl2::video::GLAttr::GLMultiSampleBuffers,
                        0
                            );
                    sdl2::video::gl_set_attribute(
                        sdl2::video::GLAttr::GLMultiSampleSamples,
                        0
                            );
                    window_builder.build().unwrap()
                } else {
                    window.unwrap() // Panic.
                }
        };

        // Send text input events.
        sdl2::keyboard::start_text_input();

        let context = window.gl_create_context().unwrap();

        // Load the OpenGL function pointers.
        gl::load_with(|s| unsafe {
            transmute(sdl2::video::gl_get_proc_address(s))
        });

        if settings.get_vsync() {
            sdl2::video::gl_set_swap_interval(1);
        } else {
            sdl2::video::gl_set_swap_interval(0);
        }

        let mut window = Sdl2Window {
            exit_on_esc: settings.get_exit_on_esc(),
            should_close: false,
            window: window,
            context: context,
            sdl_context: sdl_context,
            mouse_relative: None,
            title: settings.get_title() ,
            size: settings.get_size(),
            draw_size: settings.get_size(),
        };
        window.update_draw_size();
        window
    }

    fn update_draw_size(&mut self) {
        let event_pump = self.sdl_context.event_pump();
        let properties = self.window.properties(&event_pump);
        let (w, h) = properties.get_drawable_size();
        self.draw_size = Size { width: w as u32, height: h as u32 };
    }

    fn poll_event(&mut self) -> Option<Input> {
        // First check for a pending relative mouse move event.
        match self.mouse_relative {
            Some((x, y)) => {
                self.mouse_relative = None;
                return Some(Input::Move(Motion::MouseRelative(x, y)));
            }
            None => {}
        }

        // Even though we create a new EventPump each time we poll an event
        // this should not be a problem since it only contains phantom data
        // and therefore should actually not have any overhead.
        let event = match self.sdl_context.event_pump().poll_event() {
            Some( ev ) => ev,
            None => return None
        };
        match event {
            sdl2::event::Event::Quit{..} => {
                self.should_close = true;
            }
            sdl2::event::Event::TextInput { text, .. } => {
                return Some(Input::Text(text));
            }
            sdl2::event::Event::KeyDown { keycode: key, repeat, ..} => {
                // SDL2 repeats the key down event.
                // If the event is the same as last one, ignore it.
                if repeat {
                    return self.poll_event()
                }

                if self.exit_on_esc
                && key == sdl2::keycode::KeyCode::Escape {
                    self.should_close = true;
                } else {
                    return Some(Input::Press(Button::Keyboard(sdl2_map_key(key))));
                }
            }
            sdl2::event::Event::KeyUp { keycode: key, repeat, .. } => {
                if repeat {
                    return self.poll_event()
                }
                return Some(Input::Release(Button::Keyboard(sdl2_map_key(key))));
            }
            sdl2::event::Event::MouseButtonDown { mouse_btn: button, .. } => {
                return Some(Input::Press(Button::Mouse(sdl2_map_mouse(button))));
            }
            sdl2::event::Event::MouseButtonUp { mouse_btn: button, .. } => {
                return Some(Input::Release(Button::Mouse(sdl2_map_mouse(button))));
            }
            sdl2::event::Event::MouseMotion { x, y, xrel: dx, yrel: dy, .. } => {
                // Send relative move movement next time.
                self.mouse_relative = Some((dx as f64, dy as f64));
                return Some(Input::Move(Motion::MouseCursor(x as f64, y as f64)));
            },
            sdl2::event::Event::MouseWheel { x, y, .. } => {
                return Some(Input::Move(Motion::MouseScroll(x as f64, y as f64)));
            }
            sdl2::event::Event::Window {
                win_event_id: sdl2::event::WindowEventId::Resized, data1: w, data2: h, .. } => {
                self.size.width = w as u32;
                self.size.height = h as u32;
                self.update_draw_size();
                return Some(Input::Resize(w as u32, h as u32));
            }
            sdl2::event::Event::Window { win_event_id: sdl2::event::WindowEventId::FocusGained, .. } => {
                return Some(Input::Focus(true));
            }
            sdl2::event::Event::Window { win_event_id: sdl2::event::WindowEventId::FocusLost, .. } => {
                return Some(Input::Focus(false));
            }
            _ => {}
        }
        None
    }
}

impl Drop for Sdl2Window {
    fn drop(&mut self) {
        self.set_capture_cursor(false);
    }
}

impl Window for Sdl2Window {
    type Event = Input;

    fn should_close(&self) -> bool { self.should_close }
    fn swap_buffers(&mut self) { self.window.gl_swap_window(); }
    fn size(&self) -> Size { self.size }
    fn poll_event(&mut self) -> Option<Input> { self.poll_event() }
    fn draw_size(&self) -> Size { self.draw_size }
}

impl AdvancedWindow for Sdl2Window {
    fn get_title(&self) -> String {
        self.title.clone()
    }
    fn set_title(&mut self, value: String) {
        let event_pump = self.sdl_context.event_pump();
        let _ = self.window.properties(&event_pump).set_title(&value);
        self.title = value
    }
    fn get_exit_on_esc(&self) -> bool { self.exit_on_esc }
    fn set_exit_on_esc(&mut self, value: bool) { self.exit_on_esc = value; }
    fn set_capture_cursor(&mut self, value: bool) {
        sdl2::mouse::set_relative_mouse_mode(value);
    }
}

impl OpenGLWindow for Sdl2Window {
    fn get_proc_address(&mut self, proc_name: &str) -> ProcAddress {
        unsafe {
            transmute(sdl2::video::gl_get_proc_address(proc_name))
        }
    }

    fn is_current(&self) -> bool {
        unsafe {
            let this_context = self.context.raw();
            let current_context = sdl2::video::gl_get_current_context().unwrap().raw();

            this_context == current_context
        }
    }

    fn make_current(&mut self) {
        let _ = self.window.gl_make_current(&self.context);
    }
}

/// Maps a SDL2 key to piston-input key.
pub fn sdl2_map_key(keycode: sdl2::keycode::KeyCode) -> keyboard::Key {
    use num::FromPrimitive;
    FromPrimitive::from_u64(keycode as u64).unwrap()
}

/// Maps a SDL2 mouse button to piston-input button.
pub fn sdl2_map_mouse(button: sdl2::mouse::Mouse) -> MouseButton {
    match button {
        sdl2::mouse::Mouse::Left => MouseButton::Left,
        sdl2::mouse::Mouse::Right => MouseButton::Right,
        sdl2::mouse::Mouse::Middle => MouseButton::Middle,
        sdl2::mouse::Mouse::X1 => MouseButton::X1,
        sdl2::mouse::Mouse::X2 => MouseButton::X2,
        sdl2::mouse::Mouse::Unknown(_) => MouseButton::Unknown,
    }
}
<commit_msg>Upgrade to latest sdl2 and remove transmute.<commit_after>#![deny(missing_docs)]

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

extern crate sdl2;
extern crate piston;
extern crate shader_version;
extern crate gl;
extern crate num;

// External crates.
use piston::window::{
    OpenGLWindow,
    ProcAddress,
    Window,
    AdvancedWindow,
    WindowSettings,
    Size,
};
use piston::input::{ keyboard, Button, MouseButton, Input, Motion };

pub use shader_version::OpenGL;

/// A widow implemented by SDL2 back-end.
pub struct Sdl2Window {
    /// SDL window handle.
    pub window: sdl2::video::Window,
    /// Allow dead code because this keeps track of the OpenGL context.
    /// Will be released on drop.
    #[allow(dead_code)]
    pub context: sdl2::video::GLContext,
    /// SDL context.
    pub sdl_context: sdl2::Sdl,
    should_close: bool,
    mouse_relative: Option<(f64, f64)>,
    exit_on_esc: bool,
    title: String,
    size: Size,
    draw_size: Size,
}

impl Sdl2Window {
    /// Creates a new game window for SDL2.
    pub fn new(opengl: OpenGL, settings: WindowSettings) -> Self {
        use sdl2::video::{ GLProfile, gl_attr };

        let sdl_context = sdl2::init().everything().unwrap();
        let (major, minor) = opengl.get_major_minor();

        // Not all drivers default to 32bit color, so explicitly set it to 32bit color.
        gl_attr::set_red_size(8);
        gl_attr::set_green_size(8);
        gl_attr::set_blue_size(8);
        gl_attr::set_alpha_size(8);
        gl_attr::set_stencil_size(8);
        gl_attr::set_context_version(major as u8, minor as u8);

        if opengl >= OpenGL::_3_2 {
            gl_attr::set_context_profile(GLProfile::Core);
        }
        if settings.get_samples() != 0 {
            gl_attr::set_multisample_buffers(1);
            gl_attr::set_multisample_samples(settings.get_samples());
        }

        let mut window_builder = sdl_context.window(
            &settings.get_title(),
            settings.get_size().width as u32,
            settings.get_size().height as u32
        );

        let window_builder = window_builder.position_centered()
            .opengl()
            .resizable();

        let window_builder = if settings.get_fullscreen() {
            window_builder.fullscreen()
        } else {
            window_builder
        };

        let window = window_builder.build();

        let window = match window {
            Ok(w) => w,
            Err(_) =>
                if settings.get_samples() != 0 {
                    // Retry without requiring anti-aliasing.
                    gl_attr::set_multisample_buffers(0);
                    gl_attr::set_multisample_samples(0);
                    window_builder.build().unwrap()
                } else {
                    window.unwrap() // Panic.
                }
        };

        // Send text input events.
        sdl2::keyboard::start_text_input();

        let context = window.gl_create_context().unwrap();

        // Load the OpenGL function pointers.
        gl::load_with(sdl2::video::gl_get_proc_address);

        if settings.get_vsync() {
            sdl2::video::gl_set_swap_interval(1);
        } else {
            sdl2::video::gl_set_swap_interval(0);
        }

        let mut window = Sdl2Window {
            exit_on_esc: settings.get_exit_on_esc(),
            should_close: false,
            window: window,
            context: context,
            sdl_context: sdl_context,
            mouse_relative: None,
            title: settings.get_title() ,
            size: settings.get_size(),
            draw_size: settings.get_size(),
        };
        window.update_draw_size();
        window
    }

    fn update_draw_size(&mut self) {
        let event_pump = self.sdl_context.event_pump();
        let properties = self.window.properties(&event_pump);
        let (w, h) = properties.get_drawable_size();
        self.draw_size = Size { width: w as u32, height: h as u32 };
    }

    fn poll_event(&mut self) -> Option<Input> {
        // First check for a pending relative mouse move event.
        if let Some((x, y)) = self.mouse_relative {
            self.mouse_relative = None;
            return Some(Input::Move(Motion::MouseRelative(x, y)));
        }

        // Even though we create a new EventPump each time we poll an event
        // this should not be a problem since it only contains phantom data
        // and therefore should actually not have any overhead.
        let event = match self.sdl_context.event_pump().poll_event() {
            Some( ev ) => ev,
            None => return None
        };
        match event {
            sdl2::event::Event::Quit{..} => {
                self.should_close = true;
            }
            sdl2::event::Event::TextInput { text, .. } => {
                return Some(Input::Text(text));
            }
            sdl2::event::Event::KeyDown { keycode: key, repeat, ..} => {
                // SDL2 repeats the key down event.
                // If the event is the same as last one, ignore it.
                if repeat {
                    return self.poll_event()
                }

                if self.exit_on_esc
                && key == sdl2::keycode::KeyCode::Escape {
                    self.should_close = true;
                } else {
                    return Some(Input::Press(Button::Keyboard(sdl2_map_key(key))));
                }
            }
            sdl2::event::Event::KeyUp { keycode: key, repeat, .. } => {
                if repeat {
                    return self.poll_event()
                }
                return Some(Input::Release(Button::Keyboard(sdl2_map_key(key))));
            }
            sdl2::event::Event::MouseButtonDown { mouse_btn: button, .. } => {
                return Some(Input::Press(Button::Mouse(sdl2_map_mouse(button))));
            }
            sdl2::event::Event::MouseButtonUp { mouse_btn: button, .. } => {
                return Some(Input::Release(Button::Mouse(sdl2_map_mouse(button))));
            }
            sdl2::event::Event::MouseMotion { x, y, xrel: dx, yrel: dy, .. } => {
                // Send relative move movement next time.
                self.mouse_relative = Some((dx as f64, dy as f64));
                return Some(Input::Move(Motion::MouseCursor(x as f64, y as f64)));
            },
            sdl2::event::Event::MouseWheel { x, y, .. } => {
                return Some(Input::Move(Motion::MouseScroll(x as f64, y as f64)));
            }
            sdl2::event::Event::Window {
                win_event_id: sdl2::event::WindowEventId::Resized, data1: w, data2: h, .. } => {
                self.size.width = w as u32;
                self.size.height = h as u32;
                self.update_draw_size();
                return Some(Input::Resize(w as u32, h as u32));
            }
            sdl2::event::Event::Window { win_event_id: sdl2::event::WindowEventId::FocusGained, .. } => {
                return Some(Input::Focus(true));
            }
            sdl2::event::Event::Window { win_event_id: sdl2::event::WindowEventId::FocusLost, .. } => {
                return Some(Input::Focus(false));
            }
            _ => {}
        }
        None
    }
}

impl Drop for Sdl2Window {
    fn drop(&mut self) {
        self.set_capture_cursor(false);
    }
}

impl Window for Sdl2Window {
    type Event = Input;

    fn should_close(&self) -> bool { self.should_close }
    fn swap_buffers(&mut self) { self.window.gl_swap_window(); }
    fn size(&self) -> Size { self.size }
    fn poll_event(&mut self) -> Option<Input> { self.poll_event() }
    fn draw_size(&self) -> Size { self.draw_size }
}

impl AdvancedWindow for Sdl2Window {
    fn get_title(&self) -> String {
        self.title.clone()
    }
    fn set_title(&mut self, value: String) {
        let event_pump = self.sdl_context.event_pump();
        let _ = self.window.properties(&event_pump).set_title(&value);
        self.title = value
    }
    fn get_exit_on_esc(&self) -> bool { self.exit_on_esc }
    fn set_exit_on_esc(&mut self, value: bool) { self.exit_on_esc = value; }
    fn set_capture_cursor(&mut self, value: bool) {
        sdl2::mouse::set_relative_mouse_mode(value);
    }
}

impl OpenGLWindow for Sdl2Window {
    fn get_proc_address(&mut self, proc_name: &str) -> ProcAddress {
        sdl2::video::gl_get_proc_address(proc_name)
    }

    fn is_current(&self) -> bool {
        unsafe {
            let this_context = self.context.raw();
            let current_context = sdl2::video::gl_get_current_context().unwrap().raw();

            this_context == current_context
        }
    }

    fn make_current(&mut self) {
        self.window.gl_make_current(&self.context).unwrap();
    }
}

/// Maps a SDL2 key to piston-input key.
pub fn sdl2_map_key(keycode: sdl2::keycode::KeyCode) -> keyboard::Key {
    num::FromPrimitive::from_u64(keycode as u64).unwrap()
}

/// Maps a SDL2 mouse button to piston-input button.
pub fn sdl2_map_mouse(button: sdl2::mouse::Mouse) -> MouseButton {
    match button {
        sdl2::mouse::Mouse::Left => MouseButton::Left,
        sdl2::mouse::Mouse::Right => MouseButton::Right,
        sdl2::mouse::Mouse::Middle => MouseButton::Middle,
        sdl2::mouse::Mouse::X1 => MouseButton::X1,
        sdl2::mouse::Mouse::X2 => MouseButton::X2,
        sdl2::mouse::Mouse::Unknown(_) => MouseButton::Unknown,
    }
}
<|endoftext|>


<commit_before>extern crate route_recognizer as router;
extern crate conduit;

use std::collections::hash_map::{HashMap, Entry};
use std::error::Error;
use std::fmt;

use router::{Router, Match};
use conduit::{Method, Handler, Request, Response};

pub struct RouteBuilder {
    routers: HashMap<Method, Router<Box<Handler>>>,
}

#[derive(Debug)]
pub struct RouterError(String);

impl RouteBuilder {
    pub fn new() -> RouteBuilder {
        RouteBuilder { routers: HashMap::new() }
    }

    pub fn recognize<'a>(&'a self, method: &Method, path: &str)
                         -> Result<Match<&'a Box<Handler>>,
                                   RouterError>
    {
        match self.routers.get(method) {
            Some(router) => router.recognize(path),
            None => Err(format!("No router found for {:?}", method)),
        }.map_err(RouterError)
    }

    pub fn map<'a, H: Handler>(&'a mut self, method: Method, pattern: &str,
                               handler: H) -> &'a mut RouteBuilder {
        {
            let router = match self.routers.entry(method) {
                Entry::Occupied(e) => e.into_mut(),
                Entry::Vacant(e) => e.insert(Router::new()),
            };
            router.add(pattern, Box::new(handler));
        }
        self
    }

    pub fn get<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                               -> &'a mut RouteBuilder {
        self.map(Method::Get, pattern, handler)
    }

    pub fn post<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                                -> &'a mut RouteBuilder {
        self.map(Method::Post, pattern, handler)
    }

    pub fn put<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                               -> &'a mut RouteBuilder {
        self.map(Method::Put, pattern, handler)
    }

    pub fn delete<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                                  -> &'a mut RouteBuilder {
        self.map(Method::Delete, pattern, handler)
    }

    pub fn head<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                                -> &'a mut RouteBuilder {
        self.map(Method::Head, pattern, handler)
    }
}

impl conduit::Handler for RouteBuilder {
    fn call(&self, request: &mut Request) -> Result<Response, Box<Error+Send>> {
        let m = {
            let method = request.method();
            let path = request.path();

            match self.recognize(&method, path) {
                Ok(m) => m,
                Err(e) => return Err(Box::new(e) as Box<Error+Send>)
            }
        };

        {
            let extensions = request.mut_extensions();
            extensions.insert(m.params.clone());
        }

        (*m.handler).call(request)
    }
}

impl Error for RouterError {
    fn description(&self) -> &str { &self.0 }
}

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

pub trait RequestParams<'a> {
    fn params(self) -> &'a router::Params;
}

pub fn params<'a>(req: &'a Request) -> &'a router::Params {
    req.extensions().find::<router::Params>()
        .expect("Missing params")
}

impl<'a> RequestParams<'a> for &'a (Request + 'a) {
    fn params(self) -> &'a router::Params {
        params(self)
    }
}

#[cfg(test)]
mod tests {
    extern crate semver;
    use std::collections::HashMap;
    use std::io;
    use std::net::SocketAddr;

    use {RouteBuilder, RequestParams};

    use conduit;
    use conduit::{Handler, Method, Scheme, Host, Headers, Extensions, TypeMap};

    struct RequestSentinel {
        method: Method,
        path: String,
        extensions: conduit::Extensions
    }

    impl RequestSentinel {
        fn new(method: Method, path: &'static str) -> RequestSentinel {
            RequestSentinel {
                path: path.to_string(),
                extensions: TypeMap::new(),
                method: method
            }
        }
    }

    impl conduit::Request for RequestSentinel {
        fn http_version(&self) -> semver::Version { unimplemented!() }
        fn conduit_version(&self) -> semver::Version { unimplemented!() }
        fn method(&self) -> Method { self.method.clone() }
        fn scheme(&self) -> Scheme { unimplemented!() }
        fn host<'a>(&'a self) -> Host<'a> { unimplemented!() }
        fn virtual_root<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn path<'a>(&'a self) -> &'a str { &self.path }
        fn query_string<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn remote_addr(&self) -> SocketAddr { unimplemented!() }
        fn content_length(&self) -> Option<u64> { unimplemented!() }
        fn headers<'a>(&'a self) -> &'a Headers { unimplemented!() }
        fn body<'a>(&'a mut self) -> &'a mut io::Read { unimplemented!() }
        fn extensions<'a>(&'a self) -> &'a Extensions {
            &self.extensions
        }
        fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
            &mut self.extensions
        }
    }

    #[test]
    fn basic_get() {
        let router = test_router();
        let mut req = RequestSentinel::new(Method::Get, "/posts/1");
        let mut res = router.call(&mut req).ok().expect("No response");

        assert_eq!(res.status, (200, "OK"));
        let mut s = Vec::new();
        res.body.write_body(&mut s).unwrap();
        assert_eq!(s, b"1, Get");
    }

    #[test]
    fn basic_post() {
        let router = test_router();
        let mut req = RequestSentinel::new(Method::Post, "/posts/10");
        let mut res = router.call(&mut req).ok().expect("No response");

        assert_eq!(res.status, (200, "OK"));
        let mut s = Vec::new();
        res.body.write_body(&mut s).unwrap();
        assert_eq!(s, b"10, Post");
    }

    #[test]
    fn nonexistent_route() {
        let router = test_router();
        let mut req = RequestSentinel::new(Method::Post, "/nonexistent");
        router.call(&mut req).err().expect("No response");
    }

    fn test_router() -> RouteBuilder {
        let mut router = RouteBuilder::new();
        router.post("/posts/:id", test_handler);
        router.get("/posts/:id", test_handler);
        router
    }

    fn test_handler(req: &mut conduit::Request) -> io::Result<conduit::Response> {
        let mut res = vec!();
        res.push(req.params()["id"].clone());
        res.push(format!("{:?}", req.method()));

        Ok(conduit::Response {
            status: (200, "OK"),
            headers: HashMap::new(),
            body: Box::new(io::Cursor::new(res.connect(", ").into_bytes()))
        })
    }
}
<commit_msg>Add dyn keyword to address warnings<commit_after>extern crate route_recognizer as router;
extern crate conduit;

use std::collections::hash_map::{HashMap, Entry};
use std::error::Error;
use std::fmt;

use router::{Router, Match};
use conduit::{Method, Handler, Request, Response};

pub struct RouteBuilder {
    routers: HashMap<Method, Router<Box<dyn Handler>>>,
}

#[derive(Debug)]
pub struct RouterError(String);

impl RouteBuilder {
    pub fn new() -> RouteBuilder {
        RouteBuilder { routers: HashMap::new() }
    }

    pub fn recognize<'a>(&'a self, method: &Method, path: &str)
                         -> Result<Match<&'a Box<dyn Handler>>,
                                   RouterError>
    {
        match self.routers.get(method) {
            Some(router) => router.recognize(path),
            None => Err(format!("No router found for {:?}", method)),
        }.map_err(RouterError)
    }

    pub fn map<'a, H: Handler>(&'a mut self, method: Method, pattern: &str,
                               handler: H) -> &'a mut RouteBuilder {
        {
            let router = match self.routers.entry(method) {
                Entry::Occupied(e) => e.into_mut(),
                Entry::Vacant(e) => e.insert(Router::new()),
            };
            router.add(pattern, Box::new(handler));
        }
        self
    }

    pub fn get<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                               -> &'a mut RouteBuilder {
        self.map(Method::Get, pattern, handler)
    }

    pub fn post<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                                -> &'a mut RouteBuilder {
        self.map(Method::Post, pattern, handler)
    }

    pub fn put<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                               -> &'a mut RouteBuilder {
        self.map(Method::Put, pattern, handler)
    }

    pub fn delete<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                                  -> &'a mut RouteBuilder {
        self.map(Method::Delete, pattern, handler)
    }

    pub fn head<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                                -> &'a mut RouteBuilder {
        self.map(Method::Head, pattern, handler)
    }
}

impl conduit::Handler for RouteBuilder {
    fn call(&self, request: &mut dyn Request) -> Result<Response, Box<dyn Error+Send>> {
        let m = {
            let method = request.method();
            let path = request.path();

            match self.recognize(&method, path) {
                Ok(m) => m,
                Err(e) => return Err(Box::new(e) as Box<dyn Error+Send>)
            }
        };

        {
            let extensions = request.mut_extensions();
            extensions.insert(m.params.clone());
        }

        (*m.handler).call(request)
    }
}

impl Error for RouterError {
    fn description(&self) -> &str { &self.0 }
}

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

pub trait RequestParams<'a> {
    fn params(self) -> &'a router::Params;
}

pub fn params<'a>(req: &'a dyn Request) -> &'a router::Params {
    req.extensions().find::<router::Params>()
        .expect("Missing params")
}

impl<'a> RequestParams<'a> for &'a (dyn Request + 'a) {
    fn params(self) -> &'a router::Params {
        params(self)
    }
}

#[cfg(test)]
mod tests {
    extern crate semver;
    use std::collections::HashMap;
    use std::io;
    use std::net::SocketAddr;

    use {RouteBuilder, RequestParams};

    use conduit;
    use conduit::{Handler, Method, Scheme, Host, Headers, Extensions, TypeMap};

    struct RequestSentinel {
        method: Method,
        path: String,
        extensions: conduit::Extensions
    }

    impl RequestSentinel {
        fn new(method: Method, path: &'static str) -> RequestSentinel {
            RequestSentinel {
                path: path.to_string(),
                extensions: TypeMap::new(),
                method: method
            }
        }
    }

    impl conduit::Request for RequestSentinel {
        fn http_version(&self) -> semver::Version { unimplemented!() }
        fn conduit_version(&self) -> semver::Version { unimplemented!() }
        fn method(&self) -> Method { self.method.clone() }
        fn scheme(&self) -> Scheme { unimplemented!() }
        fn host<'a>(&'a self) -> Host<'a> { unimplemented!() }
        fn virtual_root<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn path<'a>(&'a self) -> &'a str { &self.path }
        fn query_string<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn remote_addr(&self) -> SocketAddr { unimplemented!() }
        fn content_length(&self) -> Option<u64> { unimplemented!() }
        fn headers<'a>(&'a self) -> &'a dyn Headers { unimplemented!() }
        fn body<'a>(&'a mut self) -> &'a mut dyn io::Read { unimplemented!() }
        fn extensions<'a>(&'a self) -> &'a Extensions {
            &self.extensions
        }
        fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
            &mut self.extensions
        }
    }

    #[test]
    fn basic_get() {
        let router = test_router();
        let mut req = RequestSentinel::new(Method::Get, "/posts/1");
        let mut res = router.call(&mut req).ok().expect("No response");

        assert_eq!(res.status, (200, "OK"));
        let mut s = Vec::new();
        res.body.write_body(&mut s).unwrap();
        assert_eq!(s, b"1, Get");
    }

    #[test]
    fn basic_post() {
        let router = test_router();
        let mut req = RequestSentinel::new(Method::Post, "/posts/10");
        let mut res = router.call(&mut req).ok().expect("No response");

        assert_eq!(res.status, (200, "OK"));
        let mut s = Vec::new();
        res.body.write_body(&mut s).unwrap();
        assert_eq!(s, b"10, Post");
    }

    #[test]
    fn nonexistent_route() {
        let router = test_router();
        let mut req = RequestSentinel::new(Method::Post, "/nonexistent");
        router.call(&mut req).err().expect("No response");
    }

    fn test_router() -> RouteBuilder {
        let mut router = RouteBuilder::new();
        router.post("/posts/:id", test_handler);
        router.get("/posts/:id", test_handler);
        router
    }

    fn test_handler(req: &mut dyn conduit::Request) -> io::Result<conduit::Response> {
        let mut res = vec!();
        res.push(req.params()["id"].clone());
        res.push(format!("{:?}", req.method()));

        Ok(conduit::Response {
            status: (200, "OK"),
            headers: HashMap::new(),
            body: Box::new(io::Cursor::new(res.connect(", ").into_bytes()))
        })
    }
}
<|endoftext|>


<commit_before>//! LZO is a compression library with focus on decompression speed.
//! minilzo is a lightweight subset of the full LZO library.
//!
//! It is available [online](http://www.oberhumer.com/opensource/lzo/#minilzo).
//!
//! This rust library is a wrapper around the minilzo library
//! and is fully compatible with LZO/minilzo compressed data.
//!
//! # Basic Operation
//!
//! ```rust,no_run
//! # use minilzo;
//! let data = b"foobar";
//!
//! let compressed = minilzo::compress(&data[..]).unwrap();
//!
//! let decompressed = minilzo::decompress(&compressed, data.len()).unwrap();
//! ```

extern crate minilzo_sys;
extern crate libc;

use std::mem::size_of;
use std::ptr;

use libc::{c_int, c_short, c_long};
use minilzo_sys::{
    // Types
    lzo_uint,
    lzo_callback_t,

    // Helpers
    LZO1X_1_MEM_COMPRESS,
    lzo_version,
    __lzo_init_v2,

    // (De)compress
    lzo1x_1_compress,
    lzo1x_decompress_safe,
};

/// Errors of Compression or Decompression
///
/// These are the same as minilzo returns,
/// just nicely wrapped as an enum.
#[derive(Debug, PartialEq)]
pub enum Error {
    Error,
    OutOfMemory,
    NotCompressible,
    InputOverrun,
    OutputOverrun,
    LookbehindOverrun,
    EOFNotFound,
    InputNotConsumed,
    NotYetImplemented,
    InvalidArgument,
    InvalidAlignment,
    OutputNotConsumed,
    InternalError,
}

impl Error {
    pub fn from_code(code: i32) -> Error {
        match code {
             -1 => Error::Error,
             -2 => Error::OutOfMemory,
             -3 => Error::NotCompressible,
             -4 => Error::InputOverrun,
             -5 => Error::OutputOverrun,
             -6 => Error::LookbehindOverrun,
             -7 => Error::EOFNotFound,
             -8 => Error::InputNotConsumed,
             -9 => Error::NotYetImplemented,
            -10 => Error::InvalidArgument,
            -11 => Error::InvalidAlignment,
            -12 => Error::OutputNotConsumed,
            -99 => Error::InternalError,
            _ => Error::Error,
        }
    }
}

fn _lzo_init() -> i32 {
    unsafe {
        __lzo_init_v2(lzo_version(),
                      size_of::<c_short>() as c_int,
                      size_of::<c_int>() as c_int,
                      size_of::<c_long>() as c_int,
                      size_of::<u32>() as c_int, // lzo_uint32_t
                      size_of::<lzo_uint>() as c_int,
                      size_of::<usize>() as c_int, // lzo_sizeof_dict_t
                      size_of::<usize>() as c_int, // char*
                      size_of::<usize>() as c_int, // lzo_voidp
                      size_of::<lzo_callback_t>() as c_int
                     )
    }
}

/// Compress the given data, if possible.
/// An error will be returned if compression fails.
///
/// Example
///
/// ```rust
/// let data = b"foobar";
/// let compressed = minilzo::compress(&data[..]);
/// ```
pub fn compress(indata: &[u8]) -> Result<Vec<u8>, Error> {
    let mut wrkmem : [u8; LZO1X_1_MEM_COMPRESS] = unsafe {
        std::mem::uninitialized()
    };

    let inlen = indata.len();
    let outlen = inlen + inlen / 16 + 64 + 3;
    let mut outdata = Vec::with_capacity(outlen);

    unsafe {
        let r = lzo1x_1_compress(
            indata.as_ptr(),
            inlen as u64,
            outdata.as_mut_ptr(),
            &outlen as *const _ as *mut _,
            wrkmem.as_mut_ptr() as *mut _);

        if r == 0 {
            if outlen > inlen {
                return Err(Error::NotCompressible)
            }

            outdata.set_len(outlen);
            return Ok(outdata)
        }

        return Err(Error::from_code(r))
    }
}

/// Decompress the given data, if possible.
/// An error will be returned if decompression fails.
///
/// The length of the output buffer can be specified.
/// If the output buffer is not large enough to hold the decompressed data,
/// a `OutputOverrun` is returned.
///
/// If an error in the compressed data is detected, a minilzo error is returned.
///
/// Example:
///
/// ```rust,no_run
/// let data = b"[your-compressed-data]";
/// let decompressed = minilzo::decompress(&data[..], 100);
/// ```
pub fn decompress(indata: &[u8], newlen: usize) -> Result<Vec<u8>, Error> {
    let inlen = indata.len();
    let mut outdata = Vec::with_capacity(newlen);

    unsafe {
        let r = lzo1x_decompress_safe(
            indata.as_ptr(),
            inlen as u64,
            outdata.as_mut_ptr(),
            &newlen as *const _ as *mut _,
            ptr::null_mut());

        if r == 0 {
            outdata.set_len(newlen);
            return Ok(outdata)
        }

        return Err(Error::from_code(r))
    }
}

#[test]
fn init() {
    // We test this, but we don't export it to the user right now
    assert_eq!(0, _lzo_init());
}

#[test]
fn test_compress_skips_short() {
    assert_eq!(Err(Error::NotCompressible), compress("foo".as_bytes()));
}

#[test]
fn test_compress_fails_with_short_output() {
    let data = [0; 128*1024];
    let compressed = compress(&data[..]).unwrap();

    assert_eq!(Err(Error::OutputOverrun),
               decompress(&compressed, 128));
}

#[test]
fn simple_compress_decompress() {
    let data = [0; 128*1024];
    let compressed = compress(&data[..]).unwrap();

    assert_eq!(593, compressed.len());

    let decompressed = decompress(&compressed, 128*1024).unwrap();
    assert_eq!(128*1024, decompressed.len());
}

#[test]
fn test_compress_decompress_lorem_round() {
    let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod \
                 tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At \
                 vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, \
                 no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit \
                 amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut \
                 labore et dolore magna aliquyam erat, sed diam voluptua.";

    let compressed = compress(lorem.as_bytes()).unwrap();
    let decompressed = decompress(&compressed, lorem.len()).unwrap();

    assert_eq!(lorem.len(), decompressed.len());
    assert_eq!(lorem.as_bytes(), &decompressed[..]);
}

#[test]
fn test_alice_wonderland_both() {
    let alice = "\r\n\r\n\r\n\r\n                ALICE'S ADVENTURES IN WONDERLAND\r\n";

    let compressed = compress(alice.as_bytes()).unwrap();
    let decompressed = decompress(&compressed, alice.len()).unwrap();

    assert_eq!(alice.len(), decompressed.len());
    assert_eq!(alice.as_bytes(), &decompressed[..]);
}
<commit_msg>Use same type as function expects<commit_after>//! LZO is a compression library with focus on decompression speed.
//! minilzo is a lightweight subset of the full LZO library.
//!
//! It is available [online](http://www.oberhumer.com/opensource/lzo/#minilzo).
//!
//! This rust library is a wrapper around the minilzo library
//! and is fully compatible with LZO/minilzo compressed data.
//!
//! # Basic Operation
//!
//! ```rust,no_run
//! # use minilzo;
//! let data = b"foobar";
//!
//! let compressed = minilzo::compress(&data[..]).unwrap();
//!
//! let decompressed = minilzo::decompress(&compressed, data.len()).unwrap();
//! ```

extern crate minilzo_sys;
extern crate libc;

use std::mem::size_of;
use std::ptr;

use libc::{c_int, c_short, c_long};
use minilzo_sys::{
    // Types
    lzo_uint,
    lzo_callback_t,

    // Helpers
    LZO1X_1_MEM_COMPRESS,
    lzo_version,
    __lzo_init_v2,

    // (De)compress
    lzo1x_1_compress,
    lzo1x_decompress_safe,
};

/// Errors of Compression or Decompression
///
/// These are the same as minilzo returns,
/// just nicely wrapped as an enum.
#[derive(Debug, PartialEq)]
pub enum Error {
    Error,
    OutOfMemory,
    NotCompressible,
    InputOverrun,
    OutputOverrun,
    LookbehindOverrun,
    EOFNotFound,
    InputNotConsumed,
    NotYetImplemented,
    InvalidArgument,
    InvalidAlignment,
    OutputNotConsumed,
    InternalError,
}

impl Error {
    pub fn from_code(code: i32) -> Error {
        match code {
             -1 => Error::Error,
             -2 => Error::OutOfMemory,
             -3 => Error::NotCompressible,
             -4 => Error::InputOverrun,
             -5 => Error::OutputOverrun,
             -6 => Error::LookbehindOverrun,
             -7 => Error::EOFNotFound,
             -8 => Error::InputNotConsumed,
             -9 => Error::NotYetImplemented,
            -10 => Error::InvalidArgument,
            -11 => Error::InvalidAlignment,
            -12 => Error::OutputNotConsumed,
            -99 => Error::InternalError,
            _ => Error::Error,
        }
    }
}

fn _lzo_init() -> i32 {
    unsafe {
        __lzo_init_v2(lzo_version(),
                      size_of::<c_short>() as c_int,
                      size_of::<c_int>() as c_int,
                      size_of::<c_long>() as c_int,
                      size_of::<u32>() as c_int, // lzo_uint32_t
                      size_of::<lzo_uint>() as c_int,
                      size_of::<usize>() as c_int, // lzo_sizeof_dict_t
                      size_of::<usize>() as c_int, // char*
                      size_of::<usize>() as c_int, // lzo_voidp
                      size_of::<lzo_callback_t>() as c_int
                     )
    }
}

/// Compress the given data, if possible.
/// An error will be returned if compression fails.
///
/// Example
///
/// ```rust
/// let data = b"foobar";
/// let compressed = minilzo::compress(&data[..]);
/// ```
pub fn compress(indata: &[u8]) -> Result<Vec<u8>, Error> {
    let mut wrkmem : [u8; LZO1X_1_MEM_COMPRESS] = unsafe {
        std::mem::uninitialized()
    };

    let inlen = indata.len();
    let outlen = inlen + inlen / 16 + 64 + 3;
    let mut outdata = Vec::with_capacity(outlen);

    unsafe {
        let r = lzo1x_1_compress(
            indata.as_ptr(),
            inlen as lzo_uint,
            outdata.as_mut_ptr(),
            &outlen as *const _ as *mut _,
            wrkmem.as_mut_ptr() as *mut _);

        if r == 0 {
            if outlen > inlen {
                return Err(Error::NotCompressible)
            }

            outdata.set_len(outlen);
            return Ok(outdata)
        }

        return Err(Error::from_code(r))
    }
}

/// Decompress the given data, if possible.
/// An error will be returned if decompression fails.
///
/// The length of the output buffer can be specified.
/// If the output buffer is not large enough to hold the decompressed data,
/// a `OutputOverrun` is returned.
///
/// If an error in the compressed data is detected, a minilzo error is returned.
///
/// Example:
///
/// ```rust,no_run
/// let data = b"[your-compressed-data]";
/// let decompressed = minilzo::decompress(&data[..], 100);
/// ```
pub fn decompress(indata: &[u8], newlen: usize) -> Result<Vec<u8>, Error> {
    let inlen = indata.len();
    let mut outdata = Vec::with_capacity(newlen);

    unsafe {
        let r = lzo1x_decompress_safe(
            indata.as_ptr(),
            inlen as lzo_uint,
            outdata.as_mut_ptr(),
            &newlen as *const _ as *mut _,
            ptr::null_mut());

        if r == 0 {
            outdata.set_len(newlen);
            return Ok(outdata)
        }

        return Err(Error::from_code(r))
    }
}

#[test]
fn init() {
    // We test this, but we don't export it to the user right now
    assert_eq!(0, _lzo_init());
}

#[test]
fn test_compress_skips_short() {
    assert_eq!(Err(Error::NotCompressible), compress("foo".as_bytes()));
}

#[test]
fn test_compress_fails_with_short_output() {
    let data = [0; 128*1024];
    let compressed = compress(&data[..]).unwrap();

    assert_eq!(Err(Error::OutputOverrun),
               decompress(&compressed, 128));
}

#[test]
fn simple_compress_decompress() {
    let data = [0; 128*1024];
    let compressed = compress(&data[..]).unwrap();

    assert_eq!(593, compressed.len());

    let decompressed = decompress(&compressed, 128*1024).unwrap();
    assert_eq!(128*1024, decompressed.len());
}

#[test]
fn test_compress_decompress_lorem_round() {
    let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod \
                 tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At \
                 vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, \
                 no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit \
                 amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut \
                 labore et dolore magna aliquyam erat, sed diam voluptua.";

    let compressed = compress(lorem.as_bytes()).unwrap();
    let decompressed = decompress(&compressed, lorem.len()).unwrap();

    assert_eq!(lorem.len(), decompressed.len());
    assert_eq!(lorem.as_bytes(), &decompressed[..]);
}

#[test]
fn test_alice_wonderland_both() {
    let alice = "\r\n\r\n\r\n\r\n                ALICE'S ADVENTURES IN WONDERLAND\r\n";

    let compressed = compress(alice.as_bytes()).unwrap();
    let decompressed = decompress(&compressed, alice.len()).unwrap();

    assert_eq!(alice.len(), decompressed.len());
    assert_eq!(alice.as_bytes(), &decompressed[..]);
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate exempi_sys as c;
#[macro_use]
extern crate bitflags;

mod xmp;
mod xmpstring;
mod xmpfile;
mod xmpiterator;

use std::ffi::{CString};
use std::cmp::Ordering;
use std::mem::transmute;
use std::result;
use std::sync::{Once, ONCE_INIT};

pub use xmp::Xmp as Xmp;
pub use xmpfile::XmpFile as XmpFile;
pub use xmpstring::XmpString as XmpString;
pub use xmpiterator::XmpIterator as XmpIterator;
pub use c::FileType as FileType;
pub use c::XmpError as Error;
pub use c::consts::*;
pub use c::TzSign as XmpTzSign;
// all the flags.
pub use xmpfile::flags::*;
pub use xmp::flags::*;
pub use xmpiterator::flags::*;

/// Result type
pub type Result<T> = result::Result<T, Error>;

static START: Once = ONCE_INIT;

/// Initialize the library.
///
/// This will ensure xmp_init() is called only once so that
/// concurrent calls are exclusive.
pub fn init() -> bool {
    let mut inited = true;
    START.call_once(|| {
        // run initialization here
        inited = unsafe { c::xmp_init() };
    });
    inited
}

/// Force initialize the library.
///
/// Can be safely called more than once or after `init()`
/// but can't be called concurrently from different threads.
pub fn force_init() -> bool {
    unsafe { c::xmp_init() }
}

/// Terminate the library. (use is discouraged)
///
/// As a side effect, you can't counter balance it with a `init()`
/// hence its use is discouraged.
pub fn terminate() {
    unsafe { c::xmp_terminate() }
}

/// Get the last error code on the thread
/// Set when a function return false or None.
pub fn get_error() -> Error {
    let err = unsafe { c::xmp_get_error() };
    match err {
        -15...0 |
        -110...-101 |
        -211...-201 => unsafe { transmute(err) },
        _ => Error::TBD
    }
}

/// Register namespace with uri and suggested prefix
/// Returns the actual registered prefix.
pub fn register_namespace(uri: &str, prefix: &str) -> Option<XmpString> {
    let s_uri = CString::new(uri).unwrap();
    let s_prefix = CString::new(prefix).unwrap();
    let mut reg_prefix = XmpString::new();
    if unsafe { c::xmp_register_namespace(s_uri.as_ptr(), s_prefix.as_ptr(),
                                          reg_prefix.as_mut_ptr()) } {
        Some(reg_prefix)
    } else {
        None
    }
}

/// Return the prefix for the namespace uri.
pub fn namespace_prefix(uri: &str) -> Option<XmpString> {
    let s = CString::new(uri).unwrap();
    let mut prefix = XmpString::new();
    if unsafe { c::xmp_namespace_prefix(s.as_ptr(), prefix.as_mut_ptr()) } {
        Some(prefix)
    } else {
        None
    }
}

/// Return the namespace uri for the prefix.
pub fn prefix_namespace(prefix: &str) -> Option<XmpString> {
    let s = CString::new(prefix).unwrap();
    let mut uri = XmpString::new();
    if unsafe { c::xmp_prefix_namespace_uri(s.as_ptr(), uri.as_mut_ptr()) } {
        Some(uri)
    } else {
        None
    }
}

/// A wrapper around the C type DateTime
#[derive(Clone, Debug, Default)]
pub struct DateTime {
    c: c::XmpDateTime
}

impl DateTime {
    pub fn new() -> Self {
        DateTime::default()
    }
    /// Construct from the native C type
    pub fn from(d: c::XmpDateTime) -> DateTime {
        DateTime { c: d }
    }
    /// Return the native pointer
    pub fn as_ptr(&self) -> *const c::XmpDateTime {
        &self.c as *const c::XmpDateTime
    }
    /// Return the native mutable pointer
    pub fn as_mut_ptr(&mut self) -> *mut c::XmpDateTime {
        &mut self.c as *mut c::XmpDateTime
    }
    /// Set date
    pub fn set_date(&mut self, year: i32, month: i32, day: i32) {
        self.c.year = year;
        self.c.month = month;
        self.c.day = day;
        self.c.has_date = 1;
    }
    /// Set time
    pub fn set_time(&mut self, hour: i32, min: i32, sec: i32) {
        self.c.hour = hour;
        self.c.minute = min;
        self.c.second = sec;
        self.c.has_time = 1;
    }
    /// Set Timezone
    pub fn set_timezone(&mut self, sign: XmpTzSign, hour: i32, min: i32) {
        self.c.tz_sign = sign;
        self.c.tz_hour = hour;
        self.c.tz_minute = min;
        self.c.has_tz = 1;
    }
}

impl PartialEq for DateTime {
    fn eq(&self, other: &DateTime) -> bool {
        unsafe {
            c::xmp_datetime_compare(&self.c as *const c::XmpDateTime,
                                    &other.c as *const c::XmpDateTime) == 0
        }
    }
}
impl PartialOrd for DateTime {
    fn partial_cmp(&self, other: &DateTime) -> Option<Ordering> {
        match unsafe {
            c::xmp_datetime_compare(&self.c as *const c::XmpDateTime,
                                    &other.c as *const c::XmpDateTime)
        } {
            0 => Some(Ordering::Equal),
            n if n < 0 => Some(Ordering::Less),
            n if n > 0 => Some(Ordering::Greater),
            _ => None
        }
    }
}
impl Eq for DateTime {

}
impl Ord for DateTime {
    fn cmp(&self, other: &DateTime) -> Ordering {
        match unsafe {
            c::xmp_datetime_compare(&self.c as *const c::XmpDateTime,
                                    &other.c as *const c::XmpDateTime)
        } {
            n if n < 0 => Ordering::Less,
            n if n > 0 => Ordering::Greater,
            _ => Ordering::Equal
        }
    }
}

<commit_msg>exempi::DateTime: added accessors<commit_after>extern crate libc;
extern crate exempi_sys as c;
#[macro_use]
extern crate bitflags;

mod xmp;
mod xmpstring;
mod xmpfile;
mod xmpiterator;

use std::ffi::{CString};
use std::cmp::Ordering;
use std::mem::transmute;
use std::result;
use std::sync::{Once, ONCE_INIT};

pub use xmp::Xmp as Xmp;
pub use xmpfile::XmpFile as XmpFile;
pub use xmpstring::XmpString as XmpString;
pub use xmpiterator::XmpIterator as XmpIterator;
pub use c::FileType as FileType;
pub use c::XmpError as Error;
pub use c::consts::*;
pub use c::TzSign as XmpTzSign;
// all the flags.
pub use xmpfile::flags::*;
pub use xmp::flags::*;
pub use xmpiterator::flags::*;

/// Result type
pub type Result<T> = result::Result<T, Error>;

static START: Once = ONCE_INIT;

/// Initialize the library.
///
/// This will ensure xmp_init() is called only once so that
/// concurrent calls are exclusive.
pub fn init() -> bool {
    let mut inited = true;
    START.call_once(|| {
        // run initialization here
        inited = unsafe { c::xmp_init() };
    });
    inited
}

/// Force initialize the library.
///
/// Can be safely called more than once or after `init()`
/// but can't be called concurrently from different threads.
pub fn force_init() -> bool {
    unsafe { c::xmp_init() }
}

/// Terminate the library. (use is discouraged)
///
/// As a side effect, you can't counter balance it with a `init()`
/// hence its use is discouraged.
pub fn terminate() {
    unsafe { c::xmp_terminate() }
}

/// Get the last error code on the thread
/// Set when a function return false or None.
pub fn get_error() -> Error {
    let err = unsafe { c::xmp_get_error() };
    match err {
        -15...0 |
        -110...-101 |
        -211...-201 => unsafe { transmute(err) },
        _ => Error::TBD
    }
}

/// Register namespace with uri and suggested prefix
/// Returns the actual registered prefix.
pub fn register_namespace(uri: &str, prefix: &str) -> Option<XmpString> {
    let s_uri = CString::new(uri).unwrap();
    let s_prefix = CString::new(prefix).unwrap();
    let mut reg_prefix = XmpString::new();
    if unsafe { c::xmp_register_namespace(s_uri.as_ptr(), s_prefix.as_ptr(),
                                          reg_prefix.as_mut_ptr()) } {
        Some(reg_prefix)
    } else {
        None
    }
}

/// Return the prefix for the namespace uri.
pub fn namespace_prefix(uri: &str) -> Option<XmpString> {
    let s = CString::new(uri).unwrap();
    let mut prefix = XmpString::new();
    if unsafe { c::xmp_namespace_prefix(s.as_ptr(), prefix.as_mut_ptr()) } {
        Some(prefix)
    } else {
        None
    }
}

/// Return the namespace uri for the prefix.
pub fn prefix_namespace(prefix: &str) -> Option<XmpString> {
    let s = CString::new(prefix).unwrap();
    let mut uri = XmpString::new();
    if unsafe { c::xmp_prefix_namespace_uri(s.as_ptr(), uri.as_mut_ptr()) } {
        Some(uri)
    } else {
        None
    }
}

/// A wrapper around the C type DateTime
#[derive(Clone, Debug, Default)]
pub struct DateTime {
    c: c::XmpDateTime
}

impl DateTime {
    pub fn new() -> Self {
        DateTime::default()
    }
    /// Construct from the native C type
    pub fn from(d: c::XmpDateTime) -> DateTime {
        DateTime { c: d }
    }
    /// Return the native pointer
    pub fn as_ptr(&self) -> *const c::XmpDateTime {
        &self.c as *const c::XmpDateTime
    }
    /// Return the native mutable pointer
    pub fn as_mut_ptr(&mut self) -> *mut c::XmpDateTime {
        &mut self.c as *mut c::XmpDateTime
    }
    /// Set date
    pub fn set_date(&mut self, year: i32, month: i32, day: i32) {
        self.c.year = year;
        self.c.month = month;
        self.c.day = day;
        self.c.has_date = 1;
    }
    /// Set time
    pub fn set_time(&mut self, hour: i32, min: i32, sec: i32) {
        self.c.hour = hour;
        self.c.minute = min;
        self.c.second = sec;
        self.c.has_time = 1;
    }
    /// Set Timezone
    pub fn set_timezone(&mut self, sign: XmpTzSign, hour: i32, min: i32) {
        self.c.tz_sign = sign;
        self.c.tz_hour = hour;
        self.c.tz_minute = min;
        self.c.has_tz = 1;
    }
    pub fn year(&self) -> i32 {
        self.c.year
    }
    pub fn month(&self) -> i32 {
        self.c.month
    }
    pub fn day(&self) -> i32 {
        self.c.day
    }
    pub fn hour(&self) -> i32 {
        self.c.hour
    }
    pub fn minute(&self) -> i32 {
        self.c.minute
    }
    pub fn second(&self) -> i32 {
        self.c.second
    }
}

impl PartialEq for DateTime {
    fn eq(&self, other: &DateTime) -> bool {
        unsafe {
            c::xmp_datetime_compare(&self.c as *const c::XmpDateTime,
                                    &other.c as *const c::XmpDateTime) == 0
        }
    }
}
impl PartialOrd for DateTime {
    fn partial_cmp(&self, other: &DateTime) -> Option<Ordering> {
        match unsafe {
            c::xmp_datetime_compare(&self.c as *const c::XmpDateTime,
                                    &other.c as *const c::XmpDateTime)
        } {
            0 => Some(Ordering::Equal),
            n if n < 0 => Some(Ordering::Less),
            n if n > 0 => Some(Ordering::Greater),
            _ => None
        }
    }
}
impl Eq for DateTime {

}
impl Ord for DateTime {
    fn cmp(&self, other: &DateTime) -> Ordering {
        match unsafe {
            c::xmp_datetime_compare(&self.c as *const c::XmpDateTime,
                                    &other.c as *const c::XmpDateTime)
        } {
            n if n < 0 => Ordering::Less,
            n if n > 0 => Ordering::Greater,
            _ => Ordering::Equal
        }
    }
}

<|endoftext|>


<commit_before>#[macro_use]
extern crate nickel;
extern crate mustache;
extern crate rustc_serialize;

use rustc_serialize::Encodable;
use mustache::{Data, Template};
use nickel::{Response, MiddlewareResult, Halt};

use std::borrow::Cow;
use std::path::{Path, PathBuf};
use std::sync::RwLock;
use std::collections::HashMap;
use std::collections::hash_map::Entry::*;

pub trait Render {
    type Output;

    fn render<T, P>(self, path: P, data: &T) -> Self::Output
    where T: Encodable,
          P: AsRef<Path>;

    fn render_data<P>(self, path: P, data: &Data) -> Self::Output
    where P: AsRef<Path>;
}

pub trait TemplateSupport {
    type Cache: TemplateCache;

    fn cache(&self) -> Option<&Self::Cache> {
        None
    }

    fn adjust_path<'a>(&self, path: &'a Path) -> Cow<'a, Path> {
        Cow::Borrowed(path)
    }
}

impl TemplateSupport for () {
    type Cache = ();
}

pub trait TemplateCache {
    fn handle<'a, P, F, R>(&self, path: &'a Path, handle: P, on_miss: F) -> R
    where P: FnOnce(&Template) -> R,
          F: FnOnce(&'a Path) -> Template;
}

impl TemplateCache for () {
    fn handle<'a, P, F, R>(&self, _: &'a Path, _: P, _: F) -> R
    where P: FnOnce(&Template) -> R,
          F: FnOnce(&'a Path) -> Template
    {
        unreachable!()
    }
}

impl TemplateCache for RwLock<HashMap<PathBuf, Template>> {
    fn handle<'a, P, F, R>(&self, path: &'a Path, handle: P, on_miss: F) -> R
    where P: FnOnce(&Template) -> R,
          F: FnOnce(&'a Path) -> Template
    {
        // Fast path doesn't need writer lock
        if let Some(t) = self.read().unwrap().get(path) {
            return handle(t);
        }

        // We didn't find the template, get writers lock
        let mut templates = self.write().unwrap();

        // Search again incase there was a race to compile the template
        let template = match templates.entry(path.into()) {
            Vacant(entry) => {
                let template = on_miss(path);
                entry.insert(template)
            }
            Occupied(entry) => entry.into_mut(),
        };

        handle(template)
    }
}

impl<'a, 'mw, D> Render for Response<'mw, D>
where D: TemplateSupport {
    type Output = MiddlewareResult<'mw, D>;

    fn render<T, P>(self, path: P, data: &T) -> Self::Output
    where T: Encodable,
          P: AsRef<Path> {
        with_template(path.as_ref(),
                             self.server_data(),
                             |template| {
                                 let mut stream = try!(self.start());
                                 match template.render(&mut stream, data) {
                                     Ok(()) => Ok(Halt(stream)),
                                     Err(e) => stream.bail(format!("Problem rendering template: {:?}", e)),
                                 }
                             })
    }

    fn render_data<P>(self, path: P, data: &Data) -> Self::Output
    where P: AsRef<Path> {
        with_template(path.as_ref(),
                             self.server_data(),
                             |template| {
                                 let mut stream = try!(self.start());
                                 template.render_data(&mut stream, data);
                                 Ok(Halt(stream))
                             })
    }
}

fn with_template<F, D, T>(path: &Path, data: &D, f: F) -> T
where D: TemplateSupport,
      F: FnOnce(&Template) -> T {
    let path = &*data.adjust_path(path);

    let compile = |path| {
            mustache::compile_path(path).unwrap()
            // .map_err(|e| format!("Failed to compile template '{}': {:?}",
            //             path, e))
    };

    if let Some(cache) = data.cache() {
        return cache.handle(path, f, compile);
    }

    let template = compile(path);
    f(&template)
}

#[cfg(test)]
mod tests {
    use std::path::Path;
    use std::cell::Cell;
    use mustache::{self, Template};

    use super::*;

    struct Foo {
        use_cache: bool,
        cache: FooCacher
    }

    impl Foo {
        fn new() -> Foo {
            Foo {
                use_cache: true,
                cache: FooCacher::new()
            }
        }
    }

    struct FooCacher {
        called: Cell<usize>,
        fake_cache_hit: bool,
    }

    impl FooCacher {
        fn new() -> FooCacher {
            FooCacher {
                called: Cell::new(0),
                fake_cache_hit: false
            }
        }
    }

    impl TemplateSupport for Foo {
        type Cache = FooCacher;

        fn cache(&self) -> Option<&Self::Cache> {
            if self.use_cache {
                Some(&self.cache)
            } else {
                None
            }
        }
    }

    impl TemplateCache for FooCacher {
        fn handle<'a, P, F, R>(&self, path: &'a Path, handle: P, on_miss: F) -> R
        where P: FnOnce(&Template) -> R,
              F: FnOnce(&'a Path) -> Template {
            let val = self.called.get();
            self.called.set(val + 1);

            let template = if self.fake_cache_hit {
                mustache::compile_str("")
            } else {
                on_miss(path)
            };

            handle(&template)
        }
    }

    #[test]
    fn cache_called() {
        let path = Path::new("examples/assets/my_template");
        let data = Foo::new();

        super::with_template(&path, &data, |_| ());
        assert_eq!(data.cache.called.get(), 1);
        super::with_template(&path, &data, |_| ());
        assert_eq!(data.cache.called.get(), 2);
    }

    #[test]
    fn cache_used() {
        let path = Path::new("fake_file");
        let mut data = Foo::new();

        data.cache.fake_cache_hit = true;
        // This would try to compile the fake path if the cache doesn't pretend to hit.
        super::with_template(&path, &data, |_| ());
    }

    #[test]
    #[should_panic(expected = "No such file or directory")]
    fn cache_sanity() {
        let path = Path::new("fake_file");
        let mut data = Foo::new();

        data.cache.fake_cache_hit = false;
        // If this doesn't panic, then the `cache_used` test isn't actually doing a valid test.
        super::with_template(&path, &data, |_| ());
    }

    #[test]
    fn cache_ignored() {
        let path = Path::new("examples/assets/my_template");
        let mut data = Foo::new();
        data.use_cache = false;

        super::with_template(&path, &data, |_| ());
        super::with_template(&path, &data, |_| ());
        super::with_template(&path, &data, |_| ());
        super::with_template(&path, &data, |_| ());
        super::with_template(&path, &data, |_| ());
        super::with_template(&path, &data, |_| ());
        super::with_template(&path, &data, |_| ());
        super::with_template(&path, &data, |_| ());
        super::with_template(&path, &data, |_| ());
        super::with_template(&path, &data, |_| ());
        super::with_template(&path, &data, |_| ());
        super::with_template(&path, &data, |_| ());

        assert_eq!(data.cache.called.get(), 0);
    }
}
<commit_msg>refactor(tests): group the cache tests<commit_after>#[macro_use]
extern crate nickel;
extern crate mustache;
extern crate rustc_serialize;

use rustc_serialize::Encodable;
use mustache::{Data, Template};
use nickel::{Response, MiddlewareResult, Halt};

use std::borrow::Cow;
use std::path::{Path, PathBuf};
use std::sync::RwLock;
use std::collections::HashMap;
use std::collections::hash_map::Entry::*;

pub trait Render {
    type Output;

    fn render<T, P>(self, path: P, data: &T) -> Self::Output
    where T: Encodable,
          P: AsRef<Path>;

    fn render_data<P>(self, path: P, data: &Data) -> Self::Output
    where P: AsRef<Path>;
}

pub trait TemplateSupport {
    type Cache: TemplateCache;

    fn cache(&self) -> Option<&Self::Cache> {
        None
    }

    fn adjust_path<'a>(&self, path: &'a Path) -> Cow<'a, Path> {
        Cow::Borrowed(path)
    }
}

impl TemplateSupport for () {
    type Cache = ();
}

pub trait TemplateCache {
    fn handle<'a, P, F, R>(&self, path: &'a Path, handle: P, on_miss: F) -> R
    where P: FnOnce(&Template) -> R,
          F: FnOnce(&'a Path) -> Template;
}

impl TemplateCache for () {
    fn handle<'a, P, F, R>(&self, _: &'a Path, _: P, _: F) -> R
    where P: FnOnce(&Template) -> R,
          F: FnOnce(&'a Path) -> Template
    {
        unreachable!()
    }
}

impl TemplateCache for RwLock<HashMap<PathBuf, Template>> {
    fn handle<'a, P, F, R>(&self, path: &'a Path, handle: P, on_miss: F) -> R
    where P: FnOnce(&Template) -> R,
          F: FnOnce(&'a Path) -> Template
    {
        // Fast path doesn't need writer lock
        if let Some(t) = self.read().unwrap().get(path) {
            return handle(t);
        }

        // We didn't find the template, get writers lock
        let mut templates = self.write().unwrap();

        // Search again incase there was a race to compile the template
        let template = match templates.entry(path.into()) {
            Vacant(entry) => {
                let template = on_miss(path);
                entry.insert(template)
            }
            Occupied(entry) => entry.into_mut(),
        };

        handle(template)
    }
}

impl<'a, 'mw, D> Render for Response<'mw, D>
where D: TemplateSupport {
    type Output = MiddlewareResult<'mw, D>;

    fn render<T, P>(self, path: P, data: &T) -> Self::Output
    where T: Encodable,
          P: AsRef<Path> {
        with_template(path.as_ref(),
                             self.server_data(),
                             |template| {
                                 let mut stream = try!(self.start());
                                 match template.render(&mut stream, data) {
                                     Ok(()) => Ok(Halt(stream)),
                                     Err(e) => stream.bail(format!("Problem rendering template: {:?}", e)),
                                 }
                             })
    }

    fn render_data<P>(self, path: P, data: &Data) -> Self::Output
    where P: AsRef<Path> {
        with_template(path.as_ref(),
                             self.server_data(),
                             |template| {
                                 let mut stream = try!(self.start());
                                 template.render_data(&mut stream, data);
                                 Ok(Halt(stream))
                             })
    }
}

fn with_template<F, D, T>(path: &Path, data: &D, f: F) -> T
where D: TemplateSupport,
      F: FnOnce(&Template) -> T {
    let path = &*data.adjust_path(path);

    let compile = |path| {
            mustache::compile_path(path).unwrap()
            // .map_err(|e| format!("Failed to compile template '{}': {:?}",
            //             path, e))
    };

    if let Some(cache) = data.cache() {
        return cache.handle(path, f, compile);
    }

    let template = compile(path);
    f(&template)
}

#[cfg(test)]
mod tests {
    use std::path::Path;
    use std::cell::Cell;
    use mustache::{self, Template};

    use super::*;

    struct Foo {
        use_cache: bool,
        cache: FooCacher
    }

    impl Foo {
        fn new() -> Foo {
            Foo {
                use_cache: true,
                cache: FooCacher::new()
            }
        }
    }

    struct FooCacher {
        called: Cell<usize>,
        fake_cache_hit: bool,
    }

    impl FooCacher {
        fn new() -> FooCacher {
            FooCacher {
                called: Cell::new(0),
                fake_cache_hit: false
            }
        }
    }

    impl TemplateSupport for Foo {
        type Cache = FooCacher;

        fn cache(&self) -> Option<&Self::Cache> {
            if self.use_cache {
                Some(&self.cache)
            } else {
                None
            }
        }
    }

    impl TemplateCache for FooCacher {
        fn handle<'a, P, F, R>(&self, path: &'a Path, handle: P, on_miss: F) -> R
        where P: FnOnce(&Template) -> R,
              F: FnOnce(&'a Path) -> Template {
            let val = self.called.get();
            self.called.set(val + 1);

            let template = if self.fake_cache_hit {
                mustache::compile_str("")
            } else {
                on_miss(path)
            };

            handle(&template)
        }
    }

    mod cache {
        use std::path::Path;

        use super::Foo;
        use super::super::with_template;

        #[test]
        fn called() {
            let path = Path::new("examples/assets/my_template");
            let data = Foo::new();

            with_template(&path, &data, |_| ());
            assert_eq!(data.cache.called.get(), 1);
            with_template(&path, &data, |_| ());
            assert_eq!(data.cache.called.get(), 2);
        }

        #[test]
        fn used() {
            let path = Path::new("fake_file");
            let mut data = Foo::new();

            data.cache.fake_cache_hit = true;
            // This would try to compile the fake path if the cache doesn't pretend to hit.
            with_template(&path, &data, |_| ());
        }

        #[test]
        #[should_panic(expected = "No such file or directory")]
        fn sanity() {
            let path = Path::new("fake_file");
            let mut data = Foo::new();

            data.cache.fake_cache_hit = false;
            // If this doesn't panic, then the `cache_used` test isn't actually doing a valid test.
            with_template(&path, &data, |_| ());
        }

        #[test]
        fn ignored_when_none() {
            let path = Path::new("examples/assets/my_template");
            let mut data = Foo::new();
            data.use_cache = false;

            with_template(&path, &data, |_| ());
            with_template(&path, &data, |_| ());
            with_template(&path, &data, |_| ());
            with_template(&path, &data, |_| ());
            with_template(&path, &data, |_| ());
            with_template(&path, &data, |_| ());
            with_template(&path, &data, |_| ());
            with_template(&path, &data, |_| ());
            with_template(&path, &data, |_| ());
            with_template(&path, &data, |_| ());
            with_template(&path, &data, |_| ());
            with_template(&path, &data, |_| ());

            assert_eq!(data.cache.called.get(), 0);
        }
    }
}
<|endoftext|>


<commit_before>// lib.rs
// Copyright 2016 Alexander Altman
//
// 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::ops::Index;
use std::marker::PhantomData;
use std::fmt;

#[macro_use]
extern crate error_chain;

pub mod turn {
  pub enum Black {}

  pub enum White {}

  pub trait Turn {
    type Next: Turn;

    fn piece_type() -> super::Position;
  }

  impl Turn for Black {
    type Next = White;

    fn piece_type() -> super::Position { super::Position::Black }
  }

  impl Turn for White {
    type Next = Black;

    fn piece_type() -> super::Position { super::Position::White }
  }

  pub mod errors {
    error_chain! {
      types {
        Error, ErrorKind, ChainErr, Result;
      }
      links {}
      foreign_links {}
      errors {
        IllegalTarget(source_pos: ::Position, target_pos: ::Position) {
          description("Cannot move {} piece from ")
        }
      }
    }
  }
}

pub mod errors {
  error_chain! {
    types {
      Error, ErrorKind, ChainErr, Result;
    }
    links {
      ::turn::errors::Error, ::turn::errors::ErrorKind, Turn;
    }
    foreign_links {}
    errors {}
  }
}

#[derive(Clone,Copy,PartialEq,Eq,Debug,Hash)]
pub enum Position {
  White,
  Black,
  Empty,
}

impl fmt::Display for Position {
  fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
    match *self {
      Position::White => write!(fmtr, "white"),
      Position::Black => write!(fmtr, "black"),
      Position::Empty => write!(fmtr, "empty"),
    }
  }
}

impl Position {
  pub fn is_occupied(&self) -> bool { self != &Position::Empty }

  pub fn is_empty(&self) -> bool { self == &Position::Empty }

  pub fn is_white(&self) -> bool { self == &Position::White }

  pub fn is_black(&self) -> bool { self == &Position::Black }
}

#[derive(Clone,Copy,PartialEq,Eq,Debug,Hash)]
pub struct Papamu {
  board: [[Position; 10]; 10],
}

impl Default for Papamu {
  fn default() -> Papamu {
    let mut board = [[Position::White; 10]; 10];
    for (_, pos) in board.iter_mut().enumerate().flat_map(|(x, part)| {
      part.iter_mut().enumerate().filter(move |&(y, _)| (x + y) % 2 == 0)
    }) {
      *pos = Position::Black;
    }
    Papamu { board: board }
  }
}

#[derive(Clone,Copy,PartialEq,Eq,Debug,Hash)]
pub struct Ix {
  x: u8,
  y: u8,
}

impl fmt::Display for Ix {
  fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
    let (x, y) = <(char, u8)>::from(*self);
    write!(fmtr, "position {}{}", x, y)
  }
}

impl Ix {
  pub fn mk(x: u8, y: u8) -> Option<Ix> { if x <= 9 && y <= 9 { Some(Ix { x: x, y: y }) } else { None } }

  pub fn x(&self) -> u8 { self.x }

  pub fn set_x(&mut self, new_x: u8) -> bool {
    if new_x <= 9 {
      self.x = new_x;
      true
    } else {
      false
    }
  }

  pub fn y(&self) -> u8 { self.y }

  pub fn set_y(&mut self, new_y: u8) -> bool {
    if new_y <= 9 {
      self.y = new_y;
      true
    } else {
      false
    }
  }
}

impl From<Ix> for (u8, u8) {
  fn from(ix: Ix) -> (u8, u8) { (ix.x, ix.y) }
}

impl From<Ix> for (char, u8) {
  fn from(ix: Ix) -> (char, u8) { ((ix.x + 65) as char, ix.y) }
}

impl From<Ix> for (u8, char) {
  fn from(ix: Ix) -> (u8, char) { (ix.x, (ix.y + 65) as char) }
}

impl From<Ix> for (char, char) {
  fn from(ix: Ix) -> (char, char) { ((ix.x + 65) as char, (ix.y + 65) as char) }
}

impl Index<Ix> for Papamu {
  type Output = Position;

  fn index(&self, ix: Ix) -> &Position { &self.board[usize::from(ix.x)][usize::from(ix.y)] }
}

pub struct Game<Tn: turn::Turn> {
  papamu: Papamu,
  phantom_turn: PhantomData<Tn>,
}

impl<Tn: turn::Turn> fmt::Debug for Game<Tn> {
  fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
    fmtr.debug_struct("Game").field("papamu", &self.papamu).field("phantom_turn", &self.phantom_turn).finish()
  }
}

impl<Tn: turn::Turn> Default for Game<Tn> {
  fn default() -> Game<Tn> {
    Game {
      papamu: Papamu::default(),
      phantom_turn: PhantomData,
    }
  }
}

#[allow(unknown_lints, expl_impl_clone_on_copy)]
impl<Tn: turn::Turn> Clone for Game<Tn> {
  fn clone(&self) -> Game<Tn> { *self }
}

impl<Tn: turn::Turn> Copy for Game<Tn> {}

impl<Tn: turn::Turn> Index<Ix> for Game<Tn> {
  type Output = Position;

  fn index(&self, ix: Ix) -> &Position { &self.papamu[ix] }
}

impl<Tn: turn::Turn> Game<Tn> {
  pub fn papamu(&self) -> Papamu { self.papamu }
}
<commit_msg>Some renaming<commit_after>// lib.rs
// Copyright 2016 Alexander Altman
//
// 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::ops::Index;
use std::marker::PhantomData;
use std::fmt;

#[macro_use]
extern crate error_chain;

pub mod turn {
  pub enum Black {}

  pub enum White {}

  pub trait Turn {
    type Next: Turn;

    fn piece_type() -> super::Occupancy;
  }

  impl Turn for Black {
    type Next = White;

    fn piece_type() -> super::Occupancy { super::Occupancy::Black }
  }

  impl Turn for White {
    type Next = Black;

    fn piece_type() -> super::Occupancy { super::Occupancy::White }
  }

  pub mod errors {
    error_chain! {
      types {
        Error, ErrorKind, ChainErr, Result;
      }
      links {}
      foreign_links {}
      errors {
        IllegalTarget(source_occ: ::Occupancy, source_pos: ::Position, target_pos: ::Position) {
          description("Cannot move indicated piece to target position")
          display("Cannot move {} piece at source {} to target {}", source_occ, source_pos, target_pos)
        }
      }
    }
  }
}

pub mod errors {
  error_chain! {
    types {
      Error, ErrorKind, ChainErr, Result;
    }
    links {
      ::turn::errors::Error, ::turn::errors::ErrorKind, Turn;
    }
    foreign_links {}
    errors {}
  }
}

#[derive(Clone,Copy,PartialEq,Eq,Debug,Hash)]
pub enum Occupancy {
  White,
  Black,
  Empty,
}

impl fmt::Display for Occupancy {
  fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
    match *self {
      Occupancy::White => write!(fmtr, "white"),
      Occupancy::Black => write!(fmtr, "black"),
      Occupancy::Empty => write!(fmtr, "empty"),
    }
  }
}

impl Occupancy {
  pub fn is_empty(&self) -> bool { *self == Occupancy::Empty }

  pub fn is_occupied(&self) -> bool { *self != Occupancy::Empty }

  pub fn is_white(&self) -> bool { *self == Occupancy::White }

  pub fn is_nonwhite(&self) -> bool { *self != Occupancy::White }

  pub fn is_black(&self) -> bool { *self == Occupancy::Black }

  pub fn is_nonblack(&self) -> bool { *self != Occupancy::Black }
}

#[derive(Clone,Copy,PartialEq,Eq,Debug,Hash)]
pub struct Papamu {
  board: [[Occupancy; 10]; 10],
}

impl Default for Papamu {
  fn default() -> Papamu {
    let mut board = [[Occupancy::White; 10]; 10];
    for (_, pos) in board.iter_mut().enumerate().flat_map(|(x, part)| {
      part.iter_mut().enumerate().filter(move |&(y, _)| (x + y) % 2 == 0)
    }) {
      *pos = Occupancy::Black;
    }
    Papamu { board: board }
  }
}

#[derive(Clone,Copy,PartialEq,Eq,Debug,Hash)]
pub struct Position {
  x: u8,
  y: u8,
}

impl fmt::Display for Position {
  fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
    let (x, y) = <(char, u8)>::from(*self);
    write!(fmtr, "position {}{}", x, y)
  }
}

impl Position {
  pub fn mk(x: u8, y: u8) -> Option<Position> {
    if x <= 9 && y <= 9 { Some(Position { x: x, y: y }) } else { None }
  }

  pub fn x(&self) -> u8 { self.x }

  pub fn set_x(&mut self, new_x: u8) -> bool {
    if new_x <= 9 {
      self.x = new_x;
      true
    } else {
      false
    }
  }

  pub fn y(&self) -> u8 { self.y }

  pub fn set_y(&mut self, new_y: u8) -> bool {
    if new_y <= 9 {
      self.y = new_y;
      true
    } else {
      false
    }
  }
}

impl From<Position> for (u8, u8) {
  fn from(ix: Position) -> (u8, u8) { (ix.x, ix.y) }
}

impl From<Position> for (char, u8) {
  fn from(ix: Position) -> (char, u8) { ((ix.x + 65) as char, ix.y) }
}

impl From<Position> for (u8, char) {
  fn from(ix: Position) -> (u8, char) { (ix.x, (ix.y + 65) as char) }
}

impl From<Position> for (char, char) {
  fn from(ix: Position) -> (char, char) { ((ix.x + 65) as char, (ix.y + 65) as char) }
}

impl Index<Position> for Papamu {
  type Output = Occupancy;

  fn index(&self, ix: Position) -> &Occupancy { &self.board[usize::from(ix.x)][usize::from(ix.y)] }
}

pub struct Game<Tn: turn::Turn> {
  papamu: Papamu,
  phantom_turn: PhantomData<Tn>,
}

impl<Tn: turn::Turn> fmt::Debug for Game<Tn> {
  fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
    fmtr.debug_struct("Game").field("papamu", &self.papamu).field("phantom_turn", &self.phantom_turn).finish()
  }
}

impl<Tn: turn::Turn> Default for Game<Tn> {
  fn default() -> Game<Tn> {
    Game {
      papamu: Papamu::default(),
      phantom_turn: PhantomData,
    }
  }
}

#[allow(unknown_lints, expl_impl_clone_on_copy)]
impl<Tn: turn::Turn> Clone for Game<Tn> {
  fn clone(&self) -> Game<Tn> { *self }
}

impl<Tn: turn::Turn> Copy for Game<Tn> {}

impl<Tn: turn::Turn> Index<Position> for Game<Tn> {
  type Output = Occupancy;

  fn index(&self, ix: Position) -> &Occupancy { &self.papamu[ix] }
}

impl<Tn: turn::Turn> Game<Tn> {
  pub fn papamu(&self) -> Papamu { self.papamu }
}
<|endoftext|>


<commit_before>// Copyright 2015 Joe Neeman.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!
This crate provides tools for converting regular expressions into deterministic finite automata
(DFAs). The most interesting type is `Program`, which is a DFA represented as a sequence of
instructions for a virtual machine.

# Example: creating and running a `Program`

```rust
use regex_dfa::Regex;
let re = Regex::new(r"\d{4}-\d{2}-\d{2}").unwrap();
assert_eq!(re.shortest_match("My birthday is 1986-08-22!"), Some((15, 25)));
```

# Caveats

The most useful function in this crate is `Program::shortest_match`, which looks for substrings of
the given string that match the language of the DFA. The first index of the return value is fairly
self-explanatory but the second index should be used with caution because it is only a bound on the
ending index you will get from running a standard regex engine. This is because a regex specifies
not only a language, but also a preferred execution order (for example, by specifying lazy or
greedy repetition operators). This information is lost when moving to a DFA, so we cannot
necessarily find the exact same match that a standard regex engine will.
*/

#![feature(range_inclusive, slice_splits, str_char, test)]

extern crate aho_corasick;
extern crate ascii_set;
extern crate bit_set;
extern crate memchr;
extern crate regex_syntax;
extern crate test;

mod backtracking;
mod builder;
mod char_map;
mod dfa;
mod engine;
mod error;
mod nfa;
mod prefix;
mod program;
mod regex;
mod searcher;
mod threaded;
mod transition;
mod unicode;

pub use error::Error;
pub use regex::Regex;

<commit_msg>Update module docs.<commit_after>// Copyright 2015 Joe Neeman.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!
This crate provides tools for converting regular expressions into deterministic finite automata
(DFAs). The most interesting type is `Regex`, which is a virtual machine for executing a DFA.

# Example: creating and running a `Regex`

```rust
use regex_dfa::Regex;
let re = Regex::new(r"\d{4}-\d{2}-\d{2}").unwrap();
assert_eq!(re.shortest_match("My birthday is 1986-08-22!"), Some((15, 25)));
```

# Caveats

The most useful function in this crate is `Regex::shortest_match`, which looks for substrings of
the given string that match the language of the DFA. The first index of the return value is fairly
self-explanatory but the second index should be used with caution because it is only a bound on the
ending index you will get from running a standard regex engine. This is because a regex specifies
not only a language, but also a preferred execution order (for example, by specifying lazy or
greedy repetition operators). This information is lost when moving to a DFA, so we cannot
necessarily find the exact same match that a standard regex engine will.
*/

#![feature(range_inclusive, slice_splits, str_char, test)]

extern crate aho_corasick;
extern crate ascii_set;
extern crate bit_set;
extern crate memchr;
extern crate regex_syntax;
extern crate test;

mod backtracking;
mod builder;
mod char_map;
mod dfa;
mod engine;
mod error;
mod nfa;
mod prefix;
mod program;
mod regex;
mod searcher;
mod threaded;
mod transition;
mod unicode;

pub use error::Error;
pub use regex::Regex;

<|endoftext|>


<commit_before>//! The `gettext` crate provides functionality for
//! parsing and using Gettext catalogs stored in MO files.

// https://pascalhertleif.de/artikel/good-practices-for-writing-rust-libraries/
#![deny(missing_docs, missing_debug_implementations,
        trivial_casts, trivial_numeric_casts,
        unstable_features, unused_import_braces, unused_qualifications)]

mod parser;

use std::collections::HashMap;
use std::ops::Deref;

pub use parser::Error;

/// Returns the number of the appropriate plural form
/// for the given count `n` of objects for germanic languages.
fn plural_form(n: usize) -> usize {
    if n != 1 {
        1
    } else {
        0
    }
}

/// Catalog represents a set of translation strings
/// parsed out of one MO file.
#[derive(Debug)]
pub struct Catalog {
    strings: HashMap<String, Message>,
}

impl Catalog {
    fn new() -> Self {
        Catalog { strings: HashMap::new() }
    }

    fn insert(&mut self, msg: Message) {
        let key = match msg.context {
            Some(ref ctxt) => [ctxt.deref(), &*msg.id].join("\x04"),
            None => msg.id.clone(),
        };
        self.strings.insert(key, msg);
    }

    /// Returns the singular translation of `msg_id` from the given catalog
    /// or `msg_id` itself if a translation does not exist.
    pub fn gettext<'a>(&'a self, msg_id: &'a str) -> &'a str {
        self.strings.get(&msg_id.to_owned()).and_then(|msg| msg.get_translated(0)).unwrap_or(msg_id)
    }

    /// Returns the plural translation of `msg_id` from the given catalog
    /// with the correct plural form for the number `n` of objects.
    /// Returns msg_id if a translation does not exist and `n == 1`,
    /// msg_id_plural otherwise.
    ///
    /// Currently, the only supported plural formula is `n != 1`.
    pub fn ngettext<'a>(&'a self, msg_id: &'a str, msg_id_plural: &'a str, n: usize) -> &'a str {
        let form_no = plural_form(n);

        match self.strings.get(&msg_id.to_owned()) {
            Some(msg) => {
                msg.get_translated(form_no).unwrap_or_else(|| [msg_id, msg_id_plural][form_no])
            }
            None if form_no == 0 => msg_id,
            None if form_no == 1 => msg_id_plural,
            _ => unreachable!(),
        }
    }

    /// Returns the singular translation of `msg_id`
    /// in the context `msg_context`
    /// or `msg_id` itself if a translation does not exist.
    // TODO: DRY gettext/pgettext
    pub fn pgettext<'a>(&'a self, msg_context: &'a str, msg_id: &'a str) -> &'a str {
        let key = [msg_context, msg_id].join("\x04");
        self.strings.get(&key).and_then(|msg| msg.get_translated(0)).unwrap_or(msg_id)
    }

    /// Returns the plural translation of `msg_id`
    /// in the context `msg_context`
    /// with the correct plural form for the number `n` of objects.
    /// Returns msg_id if a translation does not exist and `n == 1`,
    /// msg_id_plural otherwise.
    ///
    /// Currently, the only supported plural formula is `n != 1`.
    // TODO: DRY ngettext/npgettext
    pub fn npgettext<'a>(&'a self,
                         msg_context: &'a str,
                         msg_id: &'a str,
                         msg_id_plural: &'a str,
                         n: usize)
                         -> &'a str {
        let key = [msg_context, msg_id].join("\x04");
        let form_no = plural_form(n);
        match self.strings.get(&key) {
            Some(msg) => {
                msg.get_translated(form_no).unwrap_or_else(|| [msg_id, msg_id_plural][form_no])
            }
            None if form_no == 0 => msg_id,
            None if form_no == 1 => msg_id_plural,
            _ => unreachable!(),
        }
    }
}

#[derive(Debug, Eq, PartialEq)]
struct Message {
    id: String,
    context: Option<String>,
    translated: Vec<String>,
}

impl Message {
    fn new<T: Into<String>>(id: T, context: Option<T>, translated: Vec<T>) -> Self {
        Message {
            id: id.into(),
            context: context.map(Into::into),
            translated: translated.into_iter().map(Into::into).collect(),
        }
    }

    fn get_translated(&self, form_no: usize) -> Option<&str> {
        self.translated.get(form_no).map(|s| s.deref())
    }
}

#[test]
fn catalog_insert() {
    let mut cat = Catalog::new();
    cat.insert(Message::new("thisisid", None, vec![]));
    cat.insert(Message::new("anotherid", Some("context"), vec![]));
    let mut keys = cat.strings.keys().collect::<Vec<_>>();
    keys.sort();
    assert_eq!(keys, &["context\x04anotherid", "thisisid"])
}

#[test]
fn catalog_gettext() {
    let mut cat = Catalog::new();
    cat.insert(Message::new("Text", None, vec!["Tekstas"]));
    cat.insert(Message::new("Image", Some("context"), vec!["Paveikslelis"]));
    assert_eq!(cat.gettext("Text"), "Tekstas");
    assert_eq!(cat.gettext("Image"), "Image");
}

#[test]
fn catalog_ngettext() {
    let mut cat = Catalog::new();
    {
        // n == 1, no translation
        assert_eq!(cat.ngettext("Text", "Texts", 1), "Text");
        // n != 1, no translation
        assert_eq!(cat.ngettext("Text", "Texts", 0), "Texts");
        assert_eq!(cat.ngettext("Text", "Texts", 2), "Texts");
    }
    {
        cat.insert(Message::new("Text", None, vec!["Tekstas", "Tekstai"]));
        // n == 1, translation available
        assert_eq!(cat.ngettext("Text", "Texts", 1), "Tekstas");
        // n != 1, translation available
        assert_eq!(cat.ngettext("Text", "Texts", 0), "Tekstai");
        assert_eq!(cat.ngettext("Text", "Texts", 2), "Tekstai");
    }
}

#[test]
fn catalog_pgettext() {
    let mut cat = Catalog::new();
    cat.insert(Message::new("Text", Some("unit test"), vec!["Tekstas"]));
    assert_eq!(cat.pgettext("unit test", "Text"), "Tekstas");
    assert_eq!(cat.pgettext("integration test", "Text"), "Text");
}

#[test]
fn catalog_npgettext() {
    let mut cat = Catalog::new();
    cat.insert(Message::new("Text", Some("unit test"), vec!["Tekstas", "Tekstai"]));

    assert_eq!(cat.npgettext("unit test", "Text", "Texts", 1), "Tekstas");
    assert_eq!(cat.npgettext("unit test", "Text", "Texts", 0), "Tekstai");
    assert_eq!(cat.npgettext("unit test", "Text", "Texts", 2), "Tekstai");

    assert_eq!(cat.npgettext("integration test", "Text", "Texts", 1),
               "Text");
    assert_eq!(cat.npgettext("integration test", "Text", "Texts", 0),
               "Texts");
    assert_eq!(cat.npgettext("integration test", "Text", "Texts", 2),
               "Texts");
}
<commit_msg>Nicer syntax<commit_after>//! The `gettext` crate provides functionality for
//! parsing and using Gettext catalogs stored in MO files.

// https://pascalhertleif.de/artikel/good-practices-for-writing-rust-libraries/
#![deny(missing_docs, missing_debug_implementations,
        trivial_casts, trivial_numeric_casts,
        unstable_features, unused_import_braces, unused_qualifications)]

mod parser;

use std::collections::HashMap;
use std::ops::Deref;

pub use parser::Error;

/// Returns the number of the appropriate plural form
/// for the given count `n` of objects for germanic languages.
fn plural_form(n: usize) -> usize {
    if n != 1 {
        1
    } else {
        0
    }
}

/// Catalog represents a set of translation strings
/// parsed out of one MO file.
#[derive(Debug)]
pub struct Catalog {
    strings: HashMap<String, Message>,
}

impl Catalog {
    fn new() -> Self {
        Catalog { strings: HashMap::new() }
    }

    fn insert(&mut self, msg: Message) {
        let key = match msg.context {
            Some(ref ctxt) => [&**ctxt, &*msg.id].join("\x04"),
            None => msg.id.clone(),
        };
        self.strings.insert(key, msg);
    }

    /// Returns the singular translation of `msg_id` from the given catalog
    /// or `msg_id` itself if a translation does not exist.
    pub fn gettext<'a>(&'a self, msg_id: &'a str) -> &'a str {
        self.strings.get(&msg_id.to_owned()).and_then(|msg| msg.get_translated(0)).unwrap_or(msg_id)
    }

    /// Returns the plural translation of `msg_id` from the given catalog
    /// with the correct plural form for the number `n` of objects.
    /// Returns msg_id if a translation does not exist and `n == 1`,
    /// msg_id_plural otherwise.
    ///
    /// Currently, the only supported plural formula is `n != 1`.
    pub fn ngettext<'a>(&'a self, msg_id: &'a str, msg_id_plural: &'a str, n: usize) -> &'a str {
        let form_no = plural_form(n);

        match self.strings.get(&msg_id.to_owned()) {
            Some(msg) => {
                msg.get_translated(form_no).unwrap_or_else(|| [msg_id, msg_id_plural][form_no])
            }
            None if form_no == 0 => msg_id,
            None if form_no == 1 => msg_id_plural,
            _ => unreachable!(),
        }
    }

    /// Returns the singular translation of `msg_id`
    /// in the context `msg_context`
    /// or `msg_id` itself if a translation does not exist.
    // TODO: DRY gettext/pgettext
    pub fn pgettext<'a>(&'a self, msg_context: &'a str, msg_id: &'a str) -> &'a str {
        let key = [msg_context, msg_id].join("\x04");
        self.strings.get(&key).and_then(|msg| msg.get_translated(0)).unwrap_or(msg_id)
    }

    /// Returns the plural translation of `msg_id`
    /// in the context `msg_context`
    /// with the correct plural form for the number `n` of objects.
    /// Returns msg_id if a translation does not exist and `n == 1`,
    /// msg_id_plural otherwise.
    ///
    /// Currently, the only supported plural formula is `n != 1`.
    // TODO: DRY ngettext/npgettext
    pub fn npgettext<'a>(&'a self,
                         msg_context: &'a str,
                         msg_id: &'a str,
                         msg_id_plural: &'a str,
                         n: usize)
                         -> &'a str {
        let key = [msg_context, msg_id].join("\x04");
        let form_no = plural_form(n);
        match self.strings.get(&key) {
            Some(msg) => {
                msg.get_translated(form_no).unwrap_or_else(|| [msg_id, msg_id_plural][form_no])
            }
            None if form_no == 0 => msg_id,
            None if form_no == 1 => msg_id_plural,
            _ => unreachable!(),
        }
    }
}

#[derive(Debug, Eq, PartialEq)]
struct Message {
    id: String,
    context: Option<String>,
    translated: Vec<String>,
}

impl Message {
    fn new<T: Into<String>>(id: T, context: Option<T>, translated: Vec<T>) -> Self {
        Message {
            id: id.into(),
            context: context.map(Into::into),
            translated: translated.into_iter().map(Into::into).collect(),
        }
    }

    fn get_translated(&self, form_no: usize) -> Option<&str> {
        self.translated.get(form_no).map(|s| s.deref())
    }
}

#[test]
fn catalog_insert() {
    let mut cat = Catalog::new();
    cat.insert(Message::new("thisisid", None, vec![]));
    cat.insert(Message::new("anotherid", Some("context"), vec![]));
    let mut keys = cat.strings.keys().collect::<Vec<_>>();
    keys.sort();
    assert_eq!(keys, &["context\x04anotherid", "thisisid"])
}

#[test]
fn catalog_gettext() {
    let mut cat = Catalog::new();
    cat.insert(Message::new("Text", None, vec!["Tekstas"]));
    cat.insert(Message::new("Image", Some("context"), vec!["Paveikslelis"]));
    assert_eq!(cat.gettext("Text"), "Tekstas");
    assert_eq!(cat.gettext("Image"), "Image");
}

#[test]
fn catalog_ngettext() {
    let mut cat = Catalog::new();
    {
        // n == 1, no translation
        assert_eq!(cat.ngettext("Text", "Texts", 1), "Text");
        // n != 1, no translation
        assert_eq!(cat.ngettext("Text", "Texts", 0), "Texts");
        assert_eq!(cat.ngettext("Text", "Texts", 2), "Texts");
    }
    {
        cat.insert(Message::new("Text", None, vec!["Tekstas", "Tekstai"]));
        // n == 1, translation available
        assert_eq!(cat.ngettext("Text", "Texts", 1), "Tekstas");
        // n != 1, translation available
        assert_eq!(cat.ngettext("Text", "Texts", 0), "Tekstai");
        assert_eq!(cat.ngettext("Text", "Texts", 2), "Tekstai");
    }
}

#[test]
fn catalog_pgettext() {
    let mut cat = Catalog::new();
    cat.insert(Message::new("Text", Some("unit test"), vec!["Tekstas"]));
    assert_eq!(cat.pgettext("unit test", "Text"), "Tekstas");
    assert_eq!(cat.pgettext("integration test", "Text"), "Text");
}

#[test]
fn catalog_npgettext() {
    let mut cat = Catalog::new();
    cat.insert(Message::new("Text", Some("unit test"), vec!["Tekstas", "Tekstai"]));

    assert_eq!(cat.npgettext("unit test", "Text", "Texts", 1), "Tekstas");
    assert_eq!(cat.npgettext("unit test", "Text", "Texts", 0), "Tekstai");
    assert_eq!(cat.npgettext("unit test", "Text", "Texts", 2), "Tekstai");

    assert_eq!(cat.npgettext("integration test", "Text", "Texts", 1),
               "Text");
    assert_eq!(cat.npgettext("integration test", "Text", "Texts", 0),
               "Texts");
    assert_eq!(cat.npgettext("integration test", "Text", "Texts", 2),
               "Texts");
}
<|endoftext|>