<commit_before>#![deny(missing_docs)]
#![warn(dead_code)]

//! A user friendly game engine written in Rust.

#[cfg(feature = "include_gfx")]
extern crate libc;
#[cfg(feature = "include_gfx")]
extern crate gfx;
#[cfg(feature = "include_gfx")]
extern crate gfx_device_gl;
#[cfg(feature = "include_gfx")]
extern crate gfx_graphics;
#[cfg(feature = "include_opengl")]
extern crate opengl_graphics;
#[cfg(feature = "include_sdl2")]
extern crate sdl2;
#[cfg(feature = "include_sdl2")]
extern crate sdl2_window;
#[cfg(feature = "include_glfw")]
extern crate glfw;
#[cfg(feature = "include_glfw")]
extern crate glfw_window;
#[cfg(feature = "include_glutin")]
extern crate glutin;
#[cfg(feature = "include_glutin")]
extern crate glutin_window;
extern crate graphics;
extern crate fps_counter;
extern crate current;
extern crate shader_version;

extern crate piston;

#[cfg(feature = "include_sdl2")]
pub use sdl2_window::Sdl2Window as WindowBackEnd;
#[cfg(feature = "include_glfw")]
pub use glfw_window::GlfwWindow as WindowBackEnd;
#[cfg(feature = "include_glutin")]
pub use glutin_window::GlutinWindow as WindowBackEnd;

#[cfg(feature = "include_gfx")]
use gfx_graphics::Gfx2d;
#[cfg(feature = "include_gfx")]
use gfx::traits::DeviceExt;
#[cfg(feature = "include_gfx")]
use gfx_device_gl::{ GlDevice, GlResources };
#[cfg(feature = "include_gfx")]
use gfx_device_gl::CommandBuffer;

#[cfg(feature = "include_opengl")]
use opengl_graphics::GlGraphics;
use fps_counter::FPSCounter;

use std::rc::Rc;
use std::cell::RefCell;

use piston::window::WindowSettings;
use piston::quack::{ Get, Set };
use current::{ Current, CurrentGuard };

fn start_window<F>(
    opengl: shader_version::OpenGL,
    window_settings: WindowSettings,
    mut f: F
)
    where
        F: FnMut()
{
    let mut window = Rc::new(RefCell::new(WindowBackEnd::new(
        opengl,
        window_settings,
    )));
    let mut fps_counter = Rc::new(RefCell::new(FPSCounter::new()));

    #[cfg(feature = "include_sdl2")]
    fn disable_vsync() { sdl2::video::gl_set_swap_interval(0); }

    #[cfg(not(feature = "include_sdl2"))]
    fn disable_vsync() {}

    disable_vsync();

    let window_guard = CurrentGuard::new(&mut window);
    let fps_counter_guard = CurrentGuard::new(&mut fps_counter);

    f();

    drop(window_guard);
    drop(fps_counter_guard);
}

#[cfg(feature = "include_opengl")]
fn start_opengl<F>(opengl: shader_version::OpenGL, mut f: F)
    where
        F: FnMut()
{
    let mut gl = Rc::new(RefCell::new(GlGraphics::new(opengl)));

    let gl_guard = CurrentGuard::new(&mut gl);

    f();

    drop(gl_guard);
}

#[cfg(not(feature = "include_opengl"))]
fn start_opengl<F>(_opengl: shader_version::OpenGL, mut f: F)
    where
        F: FnMut()
{
    f();
}

#[cfg(feature = "include_gfx")]
fn start_gfx<F>(mut f: F)
    where
        F: FnMut()
{
    let window = current_window();

    let mut device = Rc::new(RefCell::new(GlDevice::new(|s| {
        #[cfg(feature = "include_sdl2")]
        fn get_proc_address(_: &WindowBackEnd, s: &str) ->
            *const libc::types::common::c95::c_void {
            unsafe { std::mem::transmute(sdl2::video::gl_get_proc_address(s)) }
        }

        #[cfg(feature = "include_glfw")]
        fn get_proc_address(window: &mut WindowBackEnd, s: &str) ->
            *const libc::types::common::c95::c_void {
            window.window.get_proc_address(s)
        }

        #[cfg(feature = "include_glutin")]
        fn get_proc_address(window: &WindowBackEnd, s: &str) ->
            *const libc::types::common::c95::c_void {
            window.window.get_proc_address(s)
        }

        get_proc_address(&mut *window.borrow_mut(), s)
    })));
    let mut g2d = Rc::new(RefCell::new(Gfx2d::new(&mut *device.borrow_mut())));
    let mut renderer = Rc::new(RefCell::new(device.borrow_mut().create_renderer()));
    let piston::window::Size([w, h]) = window.get();
    let mut frame = Rc::new(RefCell::new(gfx::Frame::<GlResources>::new(w as u16, h as u16)));

    let device_guard = CurrentGuard::new(&mut device);
    let g2d_guard = CurrentGuard::new(&mut g2d);
    let renderer_guard = CurrentGuard::new(&mut renderer);
    let frame_guard = CurrentGuard::new(&mut frame);

    f();

    drop(g2d_guard);
    drop(renderer_guard);
    drop(frame_guard);
    drop(device_guard);
}

#[cfg(not(feature = "include_gfx"))]
fn start_gfx<F>(mut f: F)
    where
        F: FnMut()
{
    f();
}

/// Initializes window and sets up current objects.
pub fn start<F>(
    opengl: shader_version::OpenGL,
    window_settings: WindowSettings,
    mut f: F
)
    where
        F: FnMut()
{
    start_window(opengl, window_settings, || {
        start_opengl(opengl, || {
            if cfg!(feature = "include_gfx") {
                start_gfx(|| f());
            } else {
                f();
            }
        })
    });
}

/// The current window
pub fn current_window() -> Rc<RefCell<WindowBackEnd>> {
    unsafe {
        Current::<Rc<RefCell<WindowBackEnd>>>::new().clone()
    }
}
/// The current Gfx device
#[cfg(feature = "include_gfx")]
pub fn current_gfx_device() -> Rc<RefCell<GlDevice>> {
    unsafe {
        Current::<Rc<RefCell<GlDevice>>>::new().clone()
    }
}
/// The current opengl_graphics back-end
#[cfg(feature = "include_opengl")]
pub fn current_gl() -> Rc<RefCell<GlGraphics>> {
    unsafe {
        Current::<Rc<RefCell<GlGraphics>>>::new().clone()
    }
}
/// The current gfx_graphics back-end
#[cfg(feature = "include_gfx")]
pub fn current_g2d() -> Rc<RefCell<Gfx2d<GlResources>>> {
    unsafe {
        Current::<Rc<RefCell<Gfx2d<GlResources>>>>::new().clone()
    }
}
/// The current Gfx renderer
#[cfg(feature = "include_gfx")]
pub fn current_renderer() -> Rc<RefCell<gfx::Renderer<GlResources, CommandBuffer>>> {
    unsafe {
        Current::<Rc<RefCell<gfx::Renderer<GlResources, CommandBuffer>>>>::new().clone()
    }
}
/// The current Gfx frame
#[cfg(feature = "include_gfx")]
pub fn current_frame() -> Rc<RefCell<gfx::Frame<GlResources>>> {
    unsafe {
        Current::<Rc<RefCell<gfx::Frame<GlResources>>>>::new().clone()
    }
}
/// The current FPS counter
pub fn current_fps_counter() -> Rc<RefCell<FPSCounter>> {
    unsafe {
        Current::<Rc<RefCell<FPSCounter>>>::new().clone()
    }
}

/// Returns an event iterator for the event loop
pub fn events() -> piston::event::Events<
    Rc<RefCell<WindowBackEnd>>, piston::event::Event
> {
    piston::event::events(current_window())
}

/// Updates the FPS counter and gets the frames per second.
pub fn fps_tick() -> usize {
    let fps_counter = current_fps_counter();
    let mut fps_counter = fps_counter.borrow_mut();
    fps_counter.tick()
}

/// Sets title of the current window.
pub fn set_title(text: String) {
    current_window().set_mut(piston::window::Title(text));
}

/// Returns true if the current window should be closed.
pub fn should_close() -> bool {
    use piston::window::ShouldClose;
    let ShouldClose(val) = current_window().get();
    val
}

/// Renders 2D graphics using Gfx.
#[cfg(feature = "include_gfx")]
pub fn render_2d_gfx<F>(
    bg_color: Option<[f32; 4]>,
    mut f: F
)
    where
        F: FnMut(graphics::Context,
            &mut gfx_graphics::GfxGraphics<GlResources, CommandBuffer>)
{
    use gfx::Device;

    let renderer = current_renderer();
    let mut renderer = renderer.borrow_mut();
    let renderer = &mut *renderer;
    let gfx = current_g2d();
    let mut gfx = gfx.borrow_mut();
    let frame = current_frame();
    let frame = frame.borrow();
    gfx.draw(
        renderer,
        &*frame,
        |c, g| {
            if let Some(bg_color) = bg_color {
                graphics::clear(bg_color, g);
            }
            f(c, g);
        });
    let gfx_device = current_gfx_device();
    let mut gfx_device = gfx_device.borrow_mut();
    gfx_device.submit(renderer.as_buffer());
    renderer.reset();
}

/// Renders 2D graphics using OpenGL.
///
/// Panics if called nested within the closure
/// to prevent mutable aliases to the graphics back-end.
#[cfg(feature = "include_opengl")]
pub fn render_2d_opengl<F>(
    bg_color: Option<[f32; 4]>,
    mut f: F
)
    where
        F: FnMut(graphics::Context, &mut opengl_graphics::Gl)
{
    let window = current_window();
    let window = window.borrow();
    let piston::window::Size(size) = window.get();
    let gl = current_gl();
    let mut gl = gl.borrow_mut();
    gl.draw([0, 0, size[0] as i32, size[1] as i32], |c, g| {
        use graphics::*;
        if let Some(bg_color) = bg_color {
            graphics::clear(bg_color, g);
        }
        f(c, g);
    });
}

<commit_msg>Upgraded to latest Rust<commit_after>#![deny(missing_docs)]
#![warn(dead_code)]

//! A user friendly game engine written in Rust.

#[cfg(feature = "include_gfx")]
extern crate libc;
#[cfg(feature = "include_gfx")]
extern crate gfx;
#[cfg(feature = "include_gfx")]
extern crate gfx_device_gl;
#[cfg(feature = "include_gfx")]
extern crate gfx_graphics;
#[cfg(feature = "include_opengl")]
extern crate opengl_graphics;
#[cfg(feature = "include_sdl2")]
extern crate sdl2;
#[cfg(feature = "include_sdl2")]
extern crate sdl2_window;
#[cfg(feature = "include_glfw")]
extern crate glfw;
#[cfg(feature = "include_glfw")]
extern crate glfw_window;
#[cfg(feature = "include_glutin")]
extern crate glutin;
#[cfg(feature = "include_glutin")]
extern crate glutin_window;
extern crate graphics;
extern crate fps_counter;
extern crate current;
extern crate shader_version;

extern crate piston;

#[cfg(feature = "include_sdl2")]
pub use sdl2_window::Sdl2Window as WindowBackEnd;
#[cfg(feature = "include_glfw")]
pub use glfw_window::GlfwWindow as WindowBackEnd;
#[cfg(feature = "include_glutin")]
pub use glutin_window::GlutinWindow as WindowBackEnd;

#[cfg(feature = "include_gfx")]
use gfx_graphics::Gfx2d;
#[cfg(feature = "include_gfx")]
use gfx::traits::DeviceExt;
#[cfg(feature = "include_gfx")]
use gfx_device_gl::{ GlDevice, GlResources };
#[cfg(feature = "include_gfx")]
use gfx_device_gl::CommandBuffer;

#[cfg(feature = "include_opengl")]
use opengl_graphics::GlGraphics;
use fps_counter::FPSCounter;

use std::rc::Rc;
use std::cell::RefCell;

use piston::window::WindowSettings;
use piston::quack::{ Get, Set };
use current::{ Current, CurrentGuard };

fn start_window<F>(
    opengl: shader_version::OpenGL,
    window_settings: WindowSettings,
    mut f: F
)
    where
        F: FnMut()
{
    let mut window = Rc::new(RefCell::new(WindowBackEnd::new(
        opengl,
        window_settings,
    )));
    let mut fps_counter = Rc::new(RefCell::new(FPSCounter::new()));

    #[cfg(feature = "include_sdl2")]
    fn disable_vsync() { sdl2::video::gl_set_swap_interval(0); }

    #[cfg(not(feature = "include_sdl2"))]
    fn disable_vsync() {}

    disable_vsync();

    let window_guard = CurrentGuard::new(&mut window);
    let fps_counter_guard = CurrentGuard::new(&mut fps_counter);

    f();

    drop(window_guard);
    drop(fps_counter_guard);
}

#[cfg(feature = "include_opengl")]
fn start_opengl<F>(opengl: shader_version::OpenGL, mut f: F)
    where
        F: FnMut()
{
    let mut gl = Rc::new(RefCell::new(GlGraphics::new(opengl)));

    let gl_guard = CurrentGuard::new(&mut gl);

    f();

    drop(gl_guard);
}

#[cfg(not(feature = "include_opengl"))]
fn start_opengl<F>(_opengl: shader_version::OpenGL, mut f: F)
    where
        F: FnMut()
{
    f();
}

#[cfg(feature = "include_gfx")]
fn start_gfx<F>(mut f: F)
    where
        F: FnMut()
{
    let window = current_window();

    let mut device = Rc::new(RefCell::new(GlDevice::new(|s| {
        #[cfg(feature = "include_sdl2")]
        fn get_proc_address(_: &WindowBackEnd, s: &str) ->
            *const libc::types::common::c95::c_void {
            unsafe { std::mem::transmute(sdl2::video::gl_get_proc_address(s)) }
        }

        #[cfg(feature = "include_glfw")]
        fn get_proc_address(window: &mut WindowBackEnd, s: &str) ->
            *const libc::types::common::c95::c_void {
            window.window.get_proc_address(s)
        }

        #[cfg(feature = "include_glutin")]
        fn get_proc_address(window: &WindowBackEnd, s: &str) ->
            *const libc::types::common::c95::c_void {
            window.window.get_proc_address(s)
        }

        get_proc_address(&mut *window.borrow_mut(), s)
    })));
    let mut g2d = Rc::new(RefCell::new(Gfx2d::new(&mut *device.borrow_mut())));
    let mut renderer = Rc::new(RefCell::new(device.borrow_mut().create_renderer()));
    let piston::window::Size(size) = window.get();
    let mut frame = Rc::new(RefCell::new(gfx::Frame::<GlResources>::new(size[0] as u16, size[1] as u16)));

    let device_guard = CurrentGuard::new(&mut device);
    let g2d_guard = CurrentGuard::new(&mut g2d);
    let renderer_guard = CurrentGuard::new(&mut renderer);
    let frame_guard = CurrentGuard::new(&mut frame);

    f();

    drop(g2d_guard);
    drop(renderer_guard);
    drop(frame_guard);
    drop(device_guard);
}

#[cfg(not(feature = "include_gfx"))]
fn start_gfx<F>(mut f: F)
    where
        F: FnMut()
{
    f();
}

/// Initializes window and sets up current objects.
pub fn start<F>(
    opengl: shader_version::OpenGL,
    window_settings: WindowSettings,
    mut f: F
)
    where
        F: FnMut()
{
    start_window(opengl, window_settings, || {
        start_opengl(opengl, || {
            if cfg!(feature = "include_gfx") {
                start_gfx(|| f());
            } else {
                f();
            }
        })
    });
}

/// The current window
pub fn current_window() -> Rc<RefCell<WindowBackEnd>> {
    unsafe {
        Current::<Rc<RefCell<WindowBackEnd>>>::new().clone()
    }
}
/// The current Gfx device
#[cfg(feature = "include_gfx")]
pub fn current_gfx_device() -> Rc<RefCell<GlDevice>> {
    unsafe {
        Current::<Rc<RefCell<GlDevice>>>::new().clone()
    }
}
/// The current opengl_graphics back-end
#[cfg(feature = "include_opengl")]
pub fn current_gl() -> Rc<RefCell<GlGraphics>> {
    unsafe {
        Current::<Rc<RefCell<GlGraphics>>>::new().clone()
    }
}
/// The current gfx_graphics back-end
#[cfg(feature = "include_gfx")]
pub fn current_g2d() -> Rc<RefCell<Gfx2d<GlResources>>> {
    unsafe {
        Current::<Rc<RefCell<Gfx2d<GlResources>>>>::new().clone()
    }
}
/// The current Gfx renderer
#[cfg(feature = "include_gfx")]
pub fn current_renderer() -> Rc<RefCell<gfx::Renderer<GlResources, CommandBuffer>>> {
    unsafe {
        Current::<Rc<RefCell<gfx::Renderer<GlResources, CommandBuffer>>>>::new().clone()
    }
}
/// The current Gfx frame
#[cfg(feature = "include_gfx")]
pub fn current_frame() -> Rc<RefCell<gfx::Frame<GlResources>>> {
    unsafe {
        Current::<Rc<RefCell<gfx::Frame<GlResources>>>>::new().clone()
    }
}
/// The current FPS counter
pub fn current_fps_counter() -> Rc<RefCell<FPSCounter>> {
    unsafe {
        Current::<Rc<RefCell<FPSCounter>>>::new().clone()
    }
}

/// Returns an event iterator for the event loop
pub fn events() -> piston::event::Events<
    Rc<RefCell<WindowBackEnd>>, piston::event::Event
> {
    piston::event::events(current_window())
}

/// Updates the FPS counter and gets the frames per second.
pub fn fps_tick() -> usize {
    let fps_counter = current_fps_counter();
    let mut fps_counter = fps_counter.borrow_mut();
    fps_counter.tick()
}

/// Sets title of the current window.
pub fn set_title(text: String) {
    current_window().set_mut(piston::window::Title(text));
}

/// Returns true if the current window should be closed.
pub fn should_close() -> bool {
    use piston::window::ShouldClose;
    let ShouldClose(val) = current_window().get();
    val
}

/// Renders 2D graphics using Gfx.
#[cfg(feature = "include_gfx")]
pub fn render_2d_gfx<F>(
    bg_color: Option<[f32; 4]>,
    mut f: F
)
    where
        F: FnMut(graphics::Context,
            &mut gfx_graphics::GfxGraphics<GlResources, CommandBuffer>)
{
    use gfx::Device;

    let renderer = current_renderer();
    let mut renderer = renderer.borrow_mut();
    let renderer = &mut *renderer;
    let gfx = current_g2d();
    let mut gfx = gfx.borrow_mut();
    let frame = current_frame();
    let frame = frame.borrow();
    gfx.draw(
        renderer,
        &*frame,
        |c, g| {
            if let Some(bg_color) = bg_color {
                graphics::clear(bg_color, g);
            }
            f(c, g);
        });
    let gfx_device = current_gfx_device();
    let mut gfx_device = gfx_device.borrow_mut();
    gfx_device.submit(renderer.as_buffer());
    renderer.reset();
}

/// Renders 2D graphics using OpenGL.
///
/// Panics if called nested within the closure
/// to prevent mutable aliases to the graphics back-end.
#[cfg(feature = "include_opengl")]
pub fn render_2d_opengl<F>(
    bg_color: Option<[f32; 4]>,
    mut f: F
)
    where
        F: FnMut(graphics::Context, &mut opengl_graphics::Gl)
{
    let window = current_window();
    let window = window.borrow();
    let piston::window::Size(size) = window.get();
    let gl = current_gl();
    let mut gl = gl.borrow_mut();
    gl.draw([0, 0, size[0] as i32, size[1] as i32], |c, g| {
        use graphics::*;
        if let Some(bg_color) = bg_color {
            graphics::clear(bg_color, g);
        }
        f(c, g);
    });
}

<|endoftext|>


<commit_before>/*!
Provides a very bare-bones way of having custom `derive` support in stable Rust.
*/
#[macro_export]
macro_rules! custom_derive {
    (
        $(#[$($attrs:tt)*])*
        enum $($it:tt)*
    ) => {
        custom_derive! {
            @split_attrs
            ($(#[$($attrs)*],)*), (), (),
            (enum $($it)*)
        }
    };

    (
        $(#[$($attrs:tt)*])*
        pub $($it:tt)*
    ) => {
        custom_derive! {
            @split_attrs
            ($(#[$($attrs)*],)*), (), (),
            (pub $($it)*)
        }
    };

    (
        $(#[$($attrs:tt)*])*
        struct $($it:tt)*
    ) => {
        custom_derive! {
            @split_attrs
            ($(#[$($attrs)*],)*), (), (),
            (struct $($it)*)
        }
    };

    (@as_item $($i:item)*) => {$($i)*};

    (
        @split_attrs
        (),
        $non_derives:tt,
        $derives:tt,
        $it:tt
    ) => {
        custom_derive! {
            @split_derive_attrs
            { $non_derives, $it },
            $derives,
            (),
            ()
        }
    };

    (
        @split_attrs
        (#[derive($($new_drv:ident $(($($new_drv_args:tt)*))*),*)], $(#[$($attrs:tt)*],)*),
        $non_derives:tt,
        ($($derives:ident,)*),
        $it:tt
    ) => {
        custom_derive! {
            @split_attrs
            ($(#[$($attrs)*],)*),
            $non_derives,
            ($($derives,)* $($new_drv $(($($new_drv_args)*))*,)*),
            $it
        }
    };

    (
        @split_attrs
        (#[$new_attr:meta], $(#[$($attrs:tt)*],)*),
        ($($non_derives:tt)*),
        $derives:tt,
        $it:tt
    ) => {
        custom_derive! {
            @split_attrs
            ($(#[$($attrs)*],)*),
            ($($non_derives)* #[$new_attr],),
            $derives,
            $it
        }
    };

    /*
    Built-in derives:
        Clone, Hash, RustcEncodable, RustcDecodable, PartialEq, Eq, PartialOrd, Ord,
        Debug, Default, Send, Sync, Copy,
    */

    (@split_derive_attrs
        { ($(#[$($non_derives:tt)*],)*), ($($it:tt)*) },
        (), ($($bi_drvs:ident,)*), ($($user_drvs:tt)*)
    ) => {
        custom_derive! {
            @as_item
            #[derive($($bi_drvs,)*)]
            $(#[$($non_derives)*])*
            $($it)*
        }

        custom_derive! {
            @expand_user_drvs
            ($($user_drvs)*), ($($it)*)
        }
    };

    (@split_derive_attrs
        $fixed:tt,
        (Clone, $($tail:tt)*), ($($bi_drvs:ident,)*), $user_drvs:tt
    ) => {
        custom_derive! {
            @split_derive_attrs
            $fixed,
            ($($tail)*), ($($bi_drvs,)* Clone,), $user_drvs
        }
    };

    (@split_derive_attrs
        $fixed:tt,
        (RustcEncodable, $($tail:tt)*), ($($bi_drvs:ident,)*), $user_drvs:tt
    ) => {
        custom_derive! {
            @split_derive_attrs
            $fixed,
            ($($tail)*), ($($bi_drvs,)* RustcEncodable,), $user_drvs
        }
    };

    (@split_derive_attrs
        $fixed:tt,
        (RustcDecodable, $($tail:tt)*), ($($bi_drvs:ident,)*), $user_drvs:tt
    ) => {
        custom_derive! {
            @split_derive_attrs
            $fixed,
            ($($tail)*), ($($bi_drvs,)* RustcDecodable,), $user_drvs
        }
    };

    (@split_derive_attrs
        $fixed:tt,
        (PartialEq, $($tail:tt)*), ($($bi_drvs:ident,)*), $user_drvs:tt
    ) => {
        custom_derive! {
            @split_derive_attrs
            $fixed,
            ($($tail)*), ($($bi_drvs,)* PartialEq,), $user_drvs
        }
    };

    (@split_derive_attrs
        $fixed:tt,
        (Eq, $($tail:tt)*), ($($bi_drvs:ident,)*), $user_drvs:tt
    ) => {
        custom_derive! {
            @split_derive_attrs
            $fixed,
            ($($tail)*), ($($bi_drvs,)* Eq,), $user_drvs
        }
    };

    (@split_derive_attrs
        $fixed:tt,
        (PartialOrd, $($tail:tt)*), ($($bi_drvs:ident,)*), $user_drvs:tt
    ) => {
        custom_derive! {
            @split_derive_attrs
            $fixed,
            ($($tail)*), ($($bi_drvs,)* PartialOrd,), $user_drvs
        }
    };

    (@split_derive_attrs
        $fixed:tt,
        (Ord, $($tail:tt)*), ($($bi_drvs:ident,)*), $user_drvs:tt
    ) => {
        custom_derive! {
            @split_derive_attrs
            $fixed,
            ($($tail)*), ($($bi_drvs,)* Ord,), $user_drvs
        }
    };

    (@split_derive_attrs
        $fixed:tt,
        (Debug, $($tail:tt)*), ($($bi_drvs:ident,)*), $user_drvs:tt
    ) => {
        custom_derive! {
            @split_derive_attrs
            $fixed,
            ($($tail)*), ($($bi_drvs,)* Debug,), $user_drvs
        }
    };

    (@split_derive_attrs
        $fixed:tt,
        (Default, $($tail:tt)*), ($($bi_drvs:ident,)*), $user_drvs:tt
    ) => {
        custom_derive! {
            @split_derive_attrs
            $fixed,
            ($($tail)*), ($($bi_drvs,)* Default,), $user_drvs
        }
    };

    (@split_derive_attrs
        $fixed:tt,
        (Send ,$($tail:tt)*), ($($bi_drvs:ident,)*), $user_drvs:tt
    ) => {
        custom_derive! {
            @split_derive_attrs
            $fixed,
            ($($tail)*), ($($bi_drvs,)* Send,), $user_drvs
        }
    };

    (@split_derive_attrs
        $fixed:tt,
        (Sync, $($tail:tt)*), ($($bi_drvs:ident,)*), $user_drvs:tt
    ) => {
        custom_derive! {
            @split_derive_attrs
            $fixed,
            ($($tail)*), ($($bi_drvs,)* Sync,), $user_drvs
        }
    };

    (@split_derive_attrs
        $fixed:tt,
        (Copy, $($tail:tt)*), ($($bi_drvs:ident,)*), $user_drvs:tt
    ) => {
        custom_derive! {
            @split_derive_attrs
            $fixed,
            ($($tail)*), ($($bi_drvs,)* Copy,), $user_drvs
        }
    };

    (@split_derive_attrs
        $fixed:tt,
        ($new_user:ident, $($tail:tt)*), $bi_drvs:tt, ($($user_drvs:tt)*)
    ) => {
        custom_derive! {
            @split_derive_attrs
            $fixed, ($($tail)*), $bi_drvs, ($($user_drvs)* $new_user(),)
        }
    };

    (@split_derive_attrs
        $fixed:tt,
        ($new_user:ident ($($new_user_args:tt)*), $($tail:tt)*), $bi_drvs:tt, ($($user_drvs:tt)*)
    ) => {
        custom_derive! {
            @split_derive_attrs
            $fixed, ($($tail)*), $bi_drvs, ($($user_drvs)* $new_user($($new_user_args)*),)
        }
    };

    (@expand_user_drvs
        (), ($($it:tt)*)
    ) => {};

    (@expand_user_drvs
        ($user_drv:ident $arg:tt, $($tail:tt)*), ($($it:tt)*)
    ) => {
        $user_drv! { $arg $($it)* }
        custom_derive! {
            @expand_user_drvs
            ($($tail)*), ($($it)*)
        }
    };
}
<commit_msg>Added documentation.<commit_after>/*!
This crate provides a macro that enables the use of custom `derive` attributes.

To use it, make sure you link to the crate like so:

```rust
#[macro_use] extern crate custom_derive;
# macro_rules! Dummy { (() struct $name:ident;) => {}; }
# custom_derive! { #[derive(Clone, Dummy)] struct Foo; }
# fn main() { let _ = Foo; }
```

> **Note**: the `custom_derive!` macro itself is not documented, as the automatic documentation for it would be uselessly huge and incomprehensible.

# Usage

The macro should be used to wrap an entire *single* `enum` or `struct` declaration, including its attributes (both `derive` and others).  All derivation attributes which the macro does *not* recognise will be assumed to be custom, and treated accordingly.

`custom_derive!` assumes that custom derivations are implemented as macros (of the same name).  For example, here is a simple derivation macro:

```rust
#[macro_use] extern crate custom_derive;

trait TypeName {
    fn type_name() -> &'static str;
}

trait ReprType {
    type Repr;
}

macro_rules! TypeName {
    (() $(pub)* enum $name:ident $($tail:tt)*) => { TypeName! { @impl $name } };
    (() $(pub)* struct $name:ident $($tail:tt)*) => { TypeName! { @impl $name } };

    (@impl $name:ident) => {
        impl TypeName for $name {
            fn type_name() -> &'static str { stringify!($name) }
        }
    };
}

macro_rules! TryFrom {
    (($repr:ty) $(pub)* enum $name:ident $($tail:tt)*) => {
        impl ReprType for $name {
            type Repr = $repr;
        }
    };
}

custom_derive! {
    #[allow(dead_code)]
    #[repr(u8)]
    #[derive(Clone, Copy, Debug, TryFrom(u8), TypeName)]
    enum Foo { A, B }
}

fn main() {
    let foo = Foo::B;
    let v = foo as <Foo as ReprType>::Repr;
    let msg = format!("{}: {:?} ({:?})", Foo::type_name(), foo, v);
    assert_eq!(msg, "Foo: B (1)");
}
```

First, note that `custom_derive!` passes any arguments on the derivation attribute to the macro.  In the case of attributes *without* any arguments, `()` is passed instead.

Secondly, the macro is passed the entire item, *sans* attributes.  It is the derivation macro's job to parse the item correctly.

Third, each derivation macro is expected to result in zero or more items, not including the item itself.  As a result, it is *not* possible to mutate the item in any way, or attach additional attributes to it.

Finally, `@impl` is merely a trick to pack multiple, different functions into a single macro.  The sequence has no special meaning; it is simply *distinct* from the usual invocation syntax.
*/

#[doc(hidden)]
#[macro_export]
macro_rules! custom_derive {
    /*

    > **Convention**: a capture named `$fixed` is used for any part of a recursive rule that is needed in the terminal case, but is not actually being *used* for the recursive part.  This avoids having to constantly repeat the full capture pattern (and makes changing it easier).

    # Primary Invocation Forms

    These need to catch any valid form of struct or enum.

    */
    (
        $(#[$($attrs:tt)*])*
        enum $($it:tt)*
    ) => {
        custom_derive! {
            @split_attrs
            ($(#[$($attrs)*],)*), (), (),
            (enum $($it)*)
        }
    };

    (
        $(#[$($attrs:tt)*])*
        pub $($it:tt)*
    ) => {
        custom_derive! {
            @split_attrs
            ($(#[$($attrs)*],)*), (), (),
            (pub $($it)*)
        }
    };

    (
        $(#[$($attrs:tt)*])*
        struct $($it:tt)*
    ) => {
        custom_derive! {
            @split_attrs
            ($(#[$($attrs)*],)*), (), (),
            (struct $($it)*)
        }
    };

    /*

    # `@split_attrs`

    This is responsible for dividing all attributes on an item into two groups:

    - `#[derive(...)]`
    - Everything else.

    As part of this, it also explodes `#[derive(A, B(..), C, ...)]` into `A, B(..), C, ...`.  This is to simplify the next stage.

    */
    (
        @split_attrs
        (),
        $non_derives:tt,
        $derives:tt,
        $it:tt
    ) => {
        custom_derive! {
            @split_derive_attrs
            { $non_derives, $it },
            $derives,
            (),
            ()
        }
    };

    (
        @split_attrs
        (#[derive($($new_drv:ident $(($($new_drv_args:tt)*))*),*)], $(#[$($attrs:tt)*],)*),
        $non_derives:tt,
        ($($derives:ident,)*),
        $it:tt
    ) => {
        custom_derive! {
            @split_attrs
            ($(#[$($attrs)*],)*),
            $non_derives,
            ($($derives,)* $($new_drv $(($($new_drv_args)*))*,)*),
            $it
        }
    };

    (
        @split_attrs
        (#[$new_attr:meta], $(#[$($attrs:tt)*],)*),
        ($($non_derives:tt)*),
        $derives:tt,
        $it:tt
    ) => {
        custom_derive! {
            @split_attrs
            ($(#[$($attrs)*],)*),
            ($($non_derives)* #[$new_attr],),
            $derives,
            $it
        }
    };

    /*

    # `@split_derive_attrs`

    This is responsible for taking the list of derivation attributes and splitting them into "built-in" and "custom" groups.

    The list of built-in derives currently supported is: Clone, Hash, RustcEncodable, RustcDecodable, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Send, Sync, Copy.

    Anything not on that list is considered "custom".

    And yes, as far as I can see, we *have* to have a separate rule for each of those.  What I wouldn't give for an alternation pattern...
    */

    (@split_derive_attrs
        { ($(#[$($non_derives:tt)*],)*), ($($it:tt)*) },
        (), ($($bi_drvs:ident,)*), ($($user_drvs:tt)*)
    ) => {
        custom_derive! {
            @as_item
            #[derive($($bi_drvs,)*)]
            $(#[$($non_derives)*])*
            $($it)*
        }

        custom_derive! {
            @expand_user_drvs
            ($($user_drvs)*), ($($it)*)
        }
    };

    (@split_derive_attrs
        $fixed:tt,
        (Clone, $($tail:tt)*), ($($bi_drvs:ident,)*), $user_drvs:tt
    ) => {
        custom_derive! {
            @split_derive_attrs
            $fixed,
            ($($tail)*), ($($bi_drvs,)* Clone,), $user_drvs
        }
    };

    (@split_derive_attrs
        $fixed:tt,
        (RustcEncodable, $($tail:tt)*), ($($bi_drvs:ident,)*), $user_drvs:tt
    ) => {
        custom_derive! {
            @split_derive_attrs
            $fixed,
            ($($tail)*), ($($bi_drvs,)* RustcEncodable,), $user_drvs
        }
    };

    (@split_derive_attrs
        $fixed:tt,
        (RustcDecodable, $($tail:tt)*), ($($bi_drvs:ident,)*), $user_drvs:tt
    ) => {
        custom_derive! {
            @split_derive_attrs
            $fixed,
            ($($tail)*), ($($bi_drvs,)* RustcDecodable,), $user_drvs
        }
    };

    (@split_derive_attrs
        $fixed:tt,
        (PartialEq, $($tail:tt)*), ($($bi_drvs:ident,)*), $user_drvs:tt
    ) => {
        custom_derive! {
            @split_derive_attrs
            $fixed,
            ($($tail)*), ($($bi_drvs,)* PartialEq,), $user_drvs
        }
    };

    (@split_derive_attrs
        $fixed:tt,
        (Eq, $($tail:tt)*), ($($bi_drvs:ident,)*), $user_drvs:tt
    ) => {
        custom_derive! {
            @split_derive_attrs
            $fixed,
            ($($tail)*), ($($bi_drvs,)* Eq,), $user_drvs
        }
    };

    (@split_derive_attrs
        $fixed:tt,
        (PartialOrd, $($tail:tt)*), ($($bi_drvs:ident,)*), $user_drvs:tt
    ) => {
        custom_derive! {
            @split_derive_attrs
            $fixed,
            ($($tail)*), ($($bi_drvs,)* PartialOrd,), $user_drvs
        }
    };

    (@split_derive_attrs
        $fixed:tt,
        (Ord, $($tail:tt)*), ($($bi_drvs:ident,)*), $user_drvs:tt
    ) => {
        custom_derive! {
            @split_derive_attrs
            $fixed,
            ($($tail)*), ($($bi_drvs,)* Ord,), $user_drvs
        }
    };

    (@split_derive_attrs
        $fixed:tt,
        (Debug, $($tail:tt)*), ($($bi_drvs:ident,)*), $user_drvs:tt
    ) => {
        custom_derive! {
            @split_derive_attrs
            $fixed,
            ($($tail)*), ($($bi_drvs,)* Debug,), $user_drvs
        }
    };

    (@split_derive_attrs
        $fixed:tt,
        (Default, $($tail:tt)*), ($($bi_drvs:ident,)*), $user_drvs:tt
    ) => {
        custom_derive! {
            @split_derive_attrs
            $fixed,
            ($($tail)*), ($($bi_drvs,)* Default,), $user_drvs
        }
    };

    (@split_derive_attrs
        $fixed:tt,
        (Send ,$($tail:tt)*), ($($bi_drvs:ident,)*), $user_drvs:tt
    ) => {
        custom_derive! {
            @split_derive_attrs
            $fixed,
            ($($tail)*), ($($bi_drvs,)* Send,), $user_drvs
        }
    };

    (@split_derive_attrs
        $fixed:tt,
        (Sync, $($tail:tt)*), ($($bi_drvs:ident,)*), $user_drvs:tt
    ) => {
        custom_derive! {
            @split_derive_attrs
            $fixed,
            ($($tail)*), ($($bi_drvs,)* Sync,), $user_drvs
        }
    };

    (@split_derive_attrs
        $fixed:tt,
        (Copy, $($tail:tt)*), ($($bi_drvs:ident,)*), $user_drvs:tt
    ) => {
        custom_derive! {
            @split_derive_attrs
            $fixed,
            ($($tail)*), ($($bi_drvs,)* Copy,), $user_drvs
        }
    };

    /*

    ## Custom Derivations

    Now we can handle the custom derivations.  There are two forms we care about: those *with* an argument, and those *without*.

    The *reason* we care is that, in order to simplify the derivation macros, we want to detect the argument-less case and generate an empty pair of parens.

    */
    (@split_derive_attrs
        $fixed:tt,
        ($new_user:ident, $($tail:tt)*), $bi_drvs:tt, ($($user_drvs:tt)*)
    ) => {
        custom_derive! {
            @split_derive_attrs
            $fixed, ($($tail)*), $bi_drvs, ($($user_drvs)* $new_user(),)
        }
    };

    (@split_derive_attrs
        $fixed:tt,
        ($new_user:ident ($($new_user_args:tt)*), $($tail:tt)*), $bi_drvs:tt, ($($user_drvs:tt)*)
    ) => {
        custom_derive! {
            @split_derive_attrs
            $fixed, ($($tail)*), $bi_drvs, ($($user_drvs)* $new_user($($new_user_args)*),)
        }
    };

    /*

    # `@expand_user_drvs`

    Finally, we have a recursive rule for expanding user derivations.  This is basically just using the derivation name as a macro identifier.

    This *has* to be recursive because we need to expand two independent repetition sequences simultaneously, and this causes `macro_rules!` to throw a wobbly.  Don't want that.  So, recursive it is.

    */
    (@expand_user_drvs
        (), ($($it:tt)*)
    ) => {};

    (@expand_user_drvs
        ($user_drv:ident $arg:tt, $($tail:tt)*), ($($it:tt)*)
    ) => {
        $user_drv! { $arg $($it)* }
        custom_derive! {
            @expand_user_drvs
            ($($tail)*), ($($it)*)
        }
    };

    /*

    # Miscellaneous Rules

    */
    (@as_item $($i:item)*) => {$($i)*};
}
<|endoftext|>


<commit_before>#[deny(missing_docs)]

extern crate input;
extern crate piston_window;
extern crate rustc_serialize;
extern crate viewport;

mod builder;
mod rebind;

use input::{Input, Button, Motion};
use piston_window::Size;
use std::collections::HashMap;
use std::default::Default;
use std::hash::Hash;
use viewport::Viewport;

pub use rebind::InputRebind;
pub use builder::InputTranslatorBuilder;

/// Represents a logical action to be bound to a particular button press, e.g.
/// jump, attack, or move forward
pub trait Action: Copy + PartialEq + Eq + Hash { }

/// A translated action.
#[derive(Debug, Copy, Clone)]
pub enum Translated<A: Action> {
    /// A keypress event which was bound to an action
    Press(A),

    /// A key release event which was bound to an action
    Release(A),

    /// A translated mouse motion. The logical origin of a translated MouseCursor event
    /// is in the top left corner of the window, and the logical scroll is non-natural.
    /// Relative events are unchanged for now.
    Move(Motion)
}

/// An object which translates piston::input::Input events into input_map::Translated<A> events
#[derive(Clone)]
pub struct InputTranslator<A: Action> {
    keymap: KeyTranslator<A>,
    mouse_translator: MouseTranslator
}

impl<A: Action> InputTranslator<A> {

    /// Creates an empty InputTranslator.
    pub fn new(size: Size) -> Self {
        InputTranslator {
            keymap: KeyTranslator::new(),
            mouse_translator: MouseTranslator::new(size)
        }
    }

    /// Translate an Input into a Translated<A> event
    pub fn translate(&self, input: &Input) -> Option<Translated<A>> {
        macro_rules! translate_button(($but_state:ident, $but_var:ident) => (
            match self.keymap.translate($but_var) {
                Some(act) => Some(Translated::$but_state(act)),
                None => None
            });
        );

        match input {
            &Input::Press(button) => translate_button!(Press, button),
            &Input::Release(button) => translate_button!(Release, button),
            &Input::Move(motion) =>
                Some(Translated::Move(self.mouse_translator.translate(motion))),
            _ => None
        }
    }

    pub fn add_binding(&mut self, but: Button, act: A) {
        self.keymap.add_mapping(but, act);
    }

    /// Re-set the mouse bounds size used for calculating mouse events
    pub fn set_size(&mut self, size: Size) {
        self.mouse_translator.data.viewport_size = size
    }

    /// Re-set the mouse bounds size from a viewport
    pub fn set_size_from_viewport(&mut self, vp: Viewport) {
        self.set_size(Size::from(vp.draw_size));
    }
}

#[derive(Clone)]
struct MouseTranslationData {
    pub x_axis_motion_inverted: bool,
    pub y_axis_motion_inverted: bool,
    pub x_axis_scroll_inverted: bool,
    pub y_axis_scroll_inverted: bool,
    pub viewport_size: Size
}

impl MouseTranslationData {
    fn new(size: Size) -> Self {
        MouseTranslationData {
            x_axis_motion_inverted: false,
            y_axis_motion_inverted: false,
            x_axis_scroll_inverted: false,
            y_axis_scroll_inverted: false,
            viewport_size: size
        }
    }
}

#[derive(Clone)]
struct MouseTranslator {
    data: MouseTranslationData
}

impl MouseTranslator {
    fn new(size: Size) -> Self {
        MouseTranslator {
            data: MouseTranslationData::new(size)
        }
    }

    fn translate(&self, motion: Motion) -> Motion {
        match motion {
            Motion::MouseCursor(x, y) => {
                let (sw, sh) = {
                    let Size {width, height} = self.data.viewport_size;
                    (width as f64, height as f64)
                };

                let cx = if self.data.x_axis_motion_inverted { sw - x } else { x };
                let cy = if self.data.y_axis_motion_inverted { sh - y } else { y };

                Motion::MouseCursor(cx, cy)
            },
            Motion::MouseScroll(x, y) => {
                let mx = if self.data.x_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                let my = if self.data.y_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                Motion::MouseScroll(x * mx, y * my)
            },
            relative => relative
        }
    }
}

#[derive(Clone, Debug)]
struct KeyTranslator<A: Action> {
    btn_map: HashMap<ButtonTuple, A>
}

impl<A: Action> KeyTranslator<A> {
    fn new() -> Self {
        KeyTranslator {
            btn_map: HashMap::new()
        }
    }

    fn add_mapping(&mut self, button: Button, action: A) {
        let mut bt = self.get_bindings_for_action(action).unwrap_or(ButtonTuple::new());
        let bt = if bt.insert_inplace(button) {bt} else {ButtonTuple::new()};
        self.btn_map.insert(bt, action);
    }

    fn get_bindings_for_action(&self, action: A) -> Option<ButtonTuple> {
        self.btn_map.iter().find(|&(_, &a)| a == action).map(|(&bt, _)| bt)
    }

    fn translate(&self, button: Button) -> Option<A> {
        self.btn_map.iter().find(|&(&bt, _)| bt.contains(button)).map(|(_, &a)| a)
    }
}

/// A three-element tuple of Option<Button>. Used as the key of an InputTranslator
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ButtonTuple(pub Option<Button>, pub Option<Button>, pub Option<Button>);

impl ButtonTuple {
    fn new() -> Self { Default::default() }

    fn contains(&self, btn: Button) -> bool {
        let sbtn = Some(btn);
        self.0 == sbtn || self.1 == sbtn || self.2 == sbtn
    }

    #[allow(dead_code)]
    fn remove_inplace(&mut self, btn: Button) {
        let sbtn = Some(btn);
        if self.0 == sbtn {self.0 = None}
        if self.1 == sbtn {self.1 = None}
        if self.2 == sbtn {self.2 = None}
    }

    #[allow(dead_code)]
    fn replace_inplace(&mut self, btn_idx: u32, btn: Button) -> bool {
        match btn_idx {
            0 => {self.0 = Some(btn); true},
            1 => {self.1 = Some(btn); true},
            2 => {self.2 = Some(btn); true},
            _ => false
        }
    }

    fn insert_inplace(&mut self, btn: Button) -> bool {
        match self {
            &mut ButtonTuple(a, b, c) if a.is_none() => {*self = ButtonTuple(Some(btn), b, c); true},
            &mut ButtonTuple(a, b, c) if b.is_none() => {*self = ButtonTuple(a, Some(btn), c); true},
            &mut ButtonTuple(a, b, c) if c.is_none() => {*self = ButtonTuple(a, b, Some(btn)); true}
            _ => false
        }
    }
}

impl Default for ButtonTuple {
    fn default() -> Self { ButtonTuple(None, None, None) }
}
<commit_msg>Make ButtonTuple methods public<commit_after>#[deny(missing_docs)]

extern crate input;
extern crate piston_window;
extern crate rustc_serialize;
extern crate viewport;

mod builder;
mod rebind;

use input::{Input, Button, Motion};
use piston_window::Size;
use std::collections::HashMap;
use std::default::Default;
use std::hash::Hash;
use viewport::Viewport;

pub use rebind::InputRebind;
pub use builder::InputTranslatorBuilder;

/// Represents a logical action to be bound to a particular button press, e.g.
/// jump, attack, or move forward
pub trait Action: Copy + PartialEq + Eq + Hash { }

/// A translated action.
#[derive(Debug, Copy, Clone)]
pub enum Translated<A: Action> {
    /// A keypress event which was bound to an action
    Press(A),

    /// A key release event which was bound to an action
    Release(A),

    /// A translated mouse motion. The logical origin of a translated MouseCursor event
    /// is in the top left corner of the window, and the logical scroll is non-natural.
    /// Relative events are unchanged for now.
    Move(Motion)
}

/// An object which translates piston::input::Input events into input_map::Translated<A> events
#[derive(Clone)]
pub struct InputTranslator<A: Action> {
    keymap: KeyTranslator<A>,
    mouse_translator: MouseTranslator
}

impl<A: Action> InputTranslator<A> {

    /// Creates an empty InputTranslator.
    pub fn new(size: Size) -> Self {
        InputTranslator {
            keymap: KeyTranslator::new(),
            mouse_translator: MouseTranslator::new(size)
        }
    }

    /// Translate an Input into a Translated<A> event
    pub fn translate(&self, input: &Input) -> Option<Translated<A>> {
        macro_rules! translate_button(($but_state:ident, $but_var:ident) => (
            match self.keymap.translate($but_var) {
                Some(act) => Some(Translated::$but_state(act)),
                None => None
            });
        );

        match input {
            &Input::Press(button) => translate_button!(Press, button),
            &Input::Release(button) => translate_button!(Release, button),
            &Input::Move(motion) =>
                Some(Translated::Move(self.mouse_translator.translate(motion))),
            _ => None
        }
    }

    pub fn add_binding(&mut self, but: Button, act: A) {
        self.keymap.add_mapping(but, act);
    }

    /// Re-set the mouse bounds size used for calculating mouse events
    pub fn set_size(&mut self, size: Size) {
        self.mouse_translator.data.viewport_size = size
    }

    /// Re-set the mouse bounds size from a viewport
    pub fn set_size_from_viewport(&mut self, vp: Viewport) {
        self.set_size(Size::from(vp.draw_size));
    }
}

#[derive(Clone)]
struct MouseTranslationData {
    pub x_axis_motion_inverted: bool,
    pub y_axis_motion_inverted: bool,
    pub x_axis_scroll_inverted: bool,
    pub y_axis_scroll_inverted: bool,
    pub viewport_size: Size
}

impl MouseTranslationData {
    fn new(size: Size) -> Self {
        MouseTranslationData {
            x_axis_motion_inverted: false,
            y_axis_motion_inverted: false,
            x_axis_scroll_inverted: false,
            y_axis_scroll_inverted: false,
            viewport_size: size
        }
    }
}

#[derive(Clone)]
struct MouseTranslator {
    data: MouseTranslationData
}

impl MouseTranslator {
    fn new(size: Size) -> Self {
        MouseTranslator {
            data: MouseTranslationData::new(size)
        }
    }

    fn translate(&self, motion: Motion) -> Motion {
        match motion {
            Motion::MouseCursor(x, y) => {
                let (sw, sh) = {
                    let Size {width, height} = self.data.viewport_size;
                    (width as f64, height as f64)
                };

                let cx = if self.data.x_axis_motion_inverted { sw - x } else { x };
                let cy = if self.data.y_axis_motion_inverted { sh - y } else { y };

                Motion::MouseCursor(cx, cy)
            },
            Motion::MouseScroll(x, y) => {
                let mx = if self.data.x_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                let my = if self.data.y_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                Motion::MouseScroll(x * mx, y * my)
            },
            relative => relative
        }
    }
}

#[derive(Clone, Debug)]
struct KeyTranslator<A: Action> {
    btn_map: HashMap<ButtonTuple, A>
}

impl<A: Action> KeyTranslator<A> {
    fn new() -> Self {
        KeyTranslator {
            btn_map: HashMap::new()
        }
    }

    fn add_mapping(&mut self, button: Button, action: A) {
        let mut bt = self.get_bindings_for_action(action).unwrap_or(ButtonTuple::new());
        let bt = if bt.insert_inplace(button) {bt} else {ButtonTuple::new()};
        self.btn_map.insert(bt, action);
    }

    fn get_bindings_for_action(&self, action: A) -> Option<ButtonTuple> {
        self.btn_map.iter().find(|&(_, &a)| a == action).map(|(&bt, _)| bt)
    }

    fn translate(&self, button: Button) -> Option<A> {
        self.btn_map.iter().find(|&(&bt, _)| bt.contains(button)).map(|(_, &a)| a)
    }
}

/// A three-element tuple of Option<Button>. Used as the key of an InputTranslator
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ButtonTuple(pub Option<Button>, pub Option<Button>, pub Option<Button>);

impl ButtonTuple {
    pub fn new() -> Self { Default::default() }

    pub fn contains(&self, btn: Button) -> bool {
        let sbtn = Some(btn);
        self.0 == sbtn || self.1 == sbtn || self.2 == sbtn
    }

    pub fn remove_inplace(&mut self, btn: Button) {
        let sbtn = Some(btn);
        if self.0 == sbtn {self.0 = None}
        if self.1 == sbtn {self.1 = None}
        if self.2 == sbtn {self.2 = None}
    }

    pub fn replace_inplace(&mut self, btn_idx: u32, btn: Button) -> bool {
        match btn_idx {
            0 => {self.0 = Some(btn); true},
            1 => {self.1 = Some(btn); true},
            2 => {self.2 = Some(btn); true},
            _ => false
        }
    }

    pub fn insert_inplace(&mut self, btn: Button) -> bool {
        match self {
            &mut ButtonTuple(a, b, c) if a.is_none() => {*self = ButtonTuple(Some(btn), b, c); true},
            &mut ButtonTuple(a, b, c) if b.is_none() => {*self = ButtonTuple(a, Some(btn), c); true},
            &mut ButtonTuple(a, b, c) if c.is_none() => {*self = ButtonTuple(a, b, Some(btn)); true}
            _ => false
        }
    }
}

impl Default for ButtonTuple {
    fn default() -> Self { ButtonTuple(None, None, None) }
}
<|endoftext|>


<commit_before>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

//! Semantic version parsing and comparison.
//!
//! Semantic versioning (see http://semver.org/) is a set of rules for
//! assigning version numbers.
//!
//! ## SemVer overview
//!
//! Given a version number MAJOR.MINOR.PATCH, increment the:
//!
//! 1. MAJOR version when you make incompatible API changes,
//! 2. MINOR version when you add functionality in a backwards-compatible manner, and
//! 3. PATCH version when you make backwards-compatible bug fixes.
//!
//! Additional labels for pre-release and build metadata are available as extensions to the
//! MAJOR.MINOR.PATCH format.
//!
//! Any references to 'the spec' in this documentation refer to [version 2.0 of the SemVer
//! spec](http://semver.org/spec/v2.0.0.html).
//!
//! ## SemVer and the Rust ecosystem
//!
//! Rust itself follows the SemVer specification, as does its standard libraries. The two are
//! not tied together.
//!
//! [Cargo](http://crates.io), Rust's package manager, uses SemVer to determine which versions of
//! packages you need installed.
//!
//! ## Versions
//!
//! At its simplest, the `semver` crate allows you to construct `Version` objects using the `parse`
//! method:
//!
//! ```{rust}
//! use semver::Version;
//!
//! assert!(Version::parse("1.2.3") == Ok(Version {
//!    major: 1u,
//!    minor: 2u,
//!    patch: 3u,
//!    pre: vec!(),
//!    build: vec!(),
//! }));
//! ```
//!
//! If you have multiple `Version`s, you can use the usual comparison operators to compare them:
//!
//! ```{rust}
//! use semver::Version;
//!
//! assert!(Version::parse("1.2.3-alpha")  != Version::parse("1.2.3-beta"));
//! assert!(Version::parse("1.2.3-alpha2") >  Version::parse("1.2.0"));
//! ```
//!
//! ## Requirements
//!
//! The `semver` crate also provides the ability to compare requirements, which are more complex
//! comparisons.
//!
//! For example, creating a requirement that only matches versions greater than or
//! equal to 1.0.0:
//!
//! ```{rust}
//! use semver::Version;
//! use semver::VersionReq;
//!
//! let r = VersionReq::parse(">= 1.0.0").unwrap();
//! let v = Version::parse("1.0.0").unwrap();
//!
//! assert!(r.to_string() == ">= 1.0.0".to_string());
//! assert!(r.matches(&v))
//! ```
//!
//! It also allows parsing of `~x.y.z` and `^x.y.z` requirements as defined at
//! https://www.npmjs.org/doc/misc/semver.html
//!
//! **Tilde requirements** specify a minimal version with some updates:
//!
//! ```
//! ~1.2.3 := >=1.2.3 <1.3.0
//! ~1.2   := >=1.2.0 <1.3.0
//! ~1     := >=1.0.0 <2.0.0
//! ```
//!
//! **Caret requirements** allow SemVer compatible updates to a specified verion,
//! `0.x` and `0.x+1` are not considered compatible, but `1.x` and `1.x+1` are.
//!
//! `0.0.x` is not considered compatible with any other version.
//! Missing minor and patch versions are desugared to `0` but allow flexibility for that value.
//!
//! ```
//! ^1.2.3 := >=1.2.3 <2.0.0
//! ^0.2.3 := >=0.2.3 <0.3.0
//! ^0.0.3 := >=0.0.3 <0.0.4
//! ^0.0   := >=0.0.0 <0.1.0
//! ^0     := >=0.0.0 <1.0.0
//! ```

#![crate_name = "semver"]
#![experimental]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico")]
#![feature(default_type_params)]
#![feature(macro_rules)]

// We take the common approach of keeping our own module system private, and
// just re-exporting the interface that we want.

pub use version::{Version, Identifier, ParseError, Numeric, AlphaNumeric};
pub use version_req::{VersionReq, ReqParseError};

// SemVer-compliant versions.
mod version;

// advanced version comparisons
mod version_req;

<commit_msg>Mark docs as notrust<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

//! Semantic version parsing and comparison.
//!
//! Semantic versioning (see http://semver.org/) is a set of rules for
//! assigning version numbers.
//!
//! ## SemVer overview
//!
//! Given a version number MAJOR.MINOR.PATCH, increment the:
//!
//! 1. MAJOR version when you make incompatible API changes,
//! 2. MINOR version when you add functionality in a backwards-compatible manner, and
//! 3. PATCH version when you make backwards-compatible bug fixes.
//!
//! Additional labels for pre-release and build metadata are available as extensions to the
//! MAJOR.MINOR.PATCH format.
//!
//! Any references to 'the spec' in this documentation refer to [version 2.0 of the SemVer
//! spec](http://semver.org/spec/v2.0.0.html).
//!
//! ## SemVer and the Rust ecosystem
//!
//! Rust itself follows the SemVer specification, as does its standard libraries. The two are
//! not tied together.
//!
//! [Cargo](http://crates.io), Rust's package manager, uses SemVer to determine which versions of
//! packages you need installed.
//!
//! ## Versions
//!
//! At its simplest, the `semver` crate allows you to construct `Version` objects using the `parse`
//! method:
//!
//! ```{rust}
//! use semver::Version;
//!
//! assert!(Version::parse("1.2.3") == Ok(Version {
//!    major: 1u,
//!    minor: 2u,
//!    patch: 3u,
//!    pre: vec!(),
//!    build: vec!(),
//! }));
//! ```
//!
//! If you have multiple `Version`s, you can use the usual comparison operators to compare them:
//!
//! ```{rust}
//! use semver::Version;
//!
//! assert!(Version::parse("1.2.3-alpha")  != Version::parse("1.2.3-beta"));
//! assert!(Version::parse("1.2.3-alpha2") >  Version::parse("1.2.0"));
//! ```
//!
//! ## Requirements
//!
//! The `semver` crate also provides the ability to compare requirements, which are more complex
//! comparisons.
//!
//! For example, creating a requirement that only matches versions greater than or
//! equal to 1.0.0:
//!
//! ```{rust}
//! use semver::Version;
//! use semver::VersionReq;
//!
//! let r = VersionReq::parse(">= 1.0.0").unwrap();
//! let v = Version::parse("1.0.0").unwrap();
//!
//! assert!(r.to_string() == ">= 1.0.0".to_string());
//! assert!(r.matches(&v))
//! ```
//!
//! It also allows parsing of `~x.y.z` and `^x.y.z` requirements as defined at
//! https://www.npmjs.org/doc/misc/semver.html
//!
//! **Tilde requirements** specify a minimal version with some updates:
//!
//! ```notrust
//! ~1.2.3 := >=1.2.3 <1.3.0
//! ~1.2   := >=1.2.0 <1.3.0
//! ~1     := >=1.0.0 <2.0.0
//! ```
//!
//! **Caret requirements** allow SemVer compatible updates to a specified verion,
//! `0.x` and `0.x+1` are not considered compatible, but `1.x` and `1.x+1` are.
//!
//! `0.0.x` is not considered compatible with any other version.
//! Missing minor and patch versions are desugared to `0` but allow flexibility for that value.
//!
//! ```notrust
//! ^1.2.3 := >=1.2.3 <2.0.0
//! ^0.2.3 := >=0.2.3 <0.3.0
//! ^0.0.3 := >=0.0.3 <0.0.4
//! ^0.0   := >=0.0.0 <0.1.0
//! ^0     := >=0.0.0 <1.0.0
//! ```

#![crate_name = "semver"]
#![experimental]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico")]
#![feature(default_type_params)]
#![feature(macro_rules)]

// We take the common approach of keeping our own module system private, and
// just re-exporting the interface that we want.

pub use version::{Version, Identifier, ParseError, Numeric, AlphaNumeric};
pub use version_req::{VersionReq, ReqParseError};

// SemVer-compliant versions.
mod version;

// advanced version comparisons
mod version_req;

<|endoftext|>


<commit_before>//! This library provide a way to evaluate [`Reverse Polish Notated`] expressions for
//! numbers and basic evaluators.
//!
//! [`Floats`] and [`signed integers`] has already been implemented with basic evaluators
//! (cf. `+`, `-`, `*`, `/`, `neg`, `pow`...).
//!
//! Of course you can build your own Evaluators by implementing the [`Evaluate`] Trait,
//! the only constraint is the compatibility with the [`Operand`] type,
//! that can be everything you want (cf. `letters`, `Enums`, `chinese symbols`...).
//!
//! # Example
//!
//! ```
//! use ripin::evaluate::{FloatExpression, IntExpression};
//!
//! let str_expr = "3 4 + 2 *"; // (3 + 4) * 2
//! let tokens = str_expr.split_whitespace();
//! let expr = FloatExpression::<f32>::from_iter(tokens).unwrap();
//!
//! assert_eq!(expr.evaluate(), Ok(14.0)); // yup that's a Float evaluation
//!
//! // let's try an Integer evaluation:
//! let tokens = str_expr.split_whitespace();
//! let expr = IntExpression::<i32>::from_iter(tokens).unwrap();
//! assert_eq!(expr.evaluate(), Ok(14));
//! ```
//!
//! [`Reverse Polish Notated`]: https://en.wikipedia.org/wiki/Reverse_Polish_notation
//! [`str`]: https://doc.rust-lang.org/std/str/index.html
//! [`Floats`]: evaluate/enum.FloatEvaluator.html
//! [`signed integers`]: evaluate/enum.IntEvaluator.html
//! [`Evaluate`]: evaluate/trait.Evaluate.html
//! [`Operand`]: expression/enum.Arithm.html

extern crate num;

mod stack;

/// Custom conversion module
pub mod convert_ref;

/// Operation on expressions and `Expression` construction methods.
pub mod expression;

/// `Evaluate Trait` and default `Evaluators`.
pub mod evaluate;

pub use stack::Stack;

/// Removes the last two elements from a stack and return them,
/// or `None` if there is not enough element.
pub fn pop_two_operands<T>(stack: &mut Stack<T>) -> Option<(T, T)> {
    match (stack.pop(), stack.pop()) {
        (Some(a), Some(b)) => Some((b, a)),
        _ => None,
    }
}
<commit_msg>stack: Fix pop_two_operands, don't pop one and lost it<commit_after>//! This library provide a way to evaluate [`Reverse Polish Notated`] expressions for
//! numbers and basic evaluators.
//!
//! [`Floats`] and [`signed integers`] has already been implemented with basic evaluators
//! (cf. `+`, `-`, `*`, `/`, `neg`, `pow`...).
//!
//! Of course you can build your own Evaluators by implementing the [`Evaluate`] Trait,
//! the only constraint is the compatibility with the [`Operand`] type,
//! that can be everything you want (cf. `letters`, `Enums`, `chinese symbols`...).
//!
//! # Example
//!
//! ```
//! use ripin::evaluate::{FloatExpression, IntExpression};
//!
//! let str_expr = "3 4 + 2 *"; // (3 + 4) * 2
//! let tokens = str_expr.split_whitespace();
//! let expr = FloatExpression::<f32>::from_iter(tokens).unwrap();
//!
//! assert_eq!(expr.evaluate(), Ok(14.0)); // yup that's a Float evaluation
//!
//! // let's try an Integer evaluation:
//! let tokens = str_expr.split_whitespace();
//! let expr = IntExpression::<i32>::from_iter(tokens).unwrap();
//! assert_eq!(expr.evaluate(), Ok(14));
//! ```
//!
//! [`Reverse Polish Notated`]: https://en.wikipedia.org/wiki/Reverse_Polish_notation
//! [`str`]: https://doc.rust-lang.org/std/str/index.html
//! [`Floats`]: evaluate/enum.FloatEvaluator.html
//! [`signed integers`]: evaluate/enum.IntEvaluator.html
//! [`Evaluate`]: evaluate/trait.Evaluate.html
//! [`Operand`]: expression/enum.Arithm.html

extern crate num;

mod stack;

/// Custom conversion module
pub mod convert_ref;

/// Operation on expressions and `Expression` construction methods.
pub mod expression;

/// `Evaluate Trait` and default `Evaluators`.
pub mod evaluate;

pub use stack::Stack;

/// Removes the last two elements from a stack and return them,
/// or `None` if there is not enough element.
pub fn pop_two_operands<T>(stack: &mut Stack<T>) -> Option<(T, T)> {
    if stack.len() >= 2 {
        let (a, b) = (stack.pop().unwrap(), stack.pop().unwrap());
        Some((b, a))
    } else {
        None
    }
}
<|endoftext|>


<commit_before>#![crate_id = "staticfile"]
#![deny(missing_doc)]
#![feature(phase)]

//! Static file-serving middleware.

extern crate url;
#[phase(plugin)]
extern crate regex_macros;
extern crate regex;

#[phase(plugin, link)]
extern crate log;
extern crate http;
extern crate iron;
extern crate mount;

use iron::{Request, Response, Middleware, Alloy};
use iron::mixin::{GetUrl, Serve};
use iron::middleware::{Status, Continue, Unwind};
use mount::OriginalUrl;

/// The static file-serving `Middleware`.
#[deriving(Clone)]
pub struct Static {
    root_path: Path
}

#[deriving(Clone)]
#[doc(hidden)]
struct Favicon {
    favicon_path: Path
}

impl Static {
    /// Create a new instance of `Static` with a given root path.
    ///
    /// This will attempt to serve static files from the given root path.
    /// The path may be relative or absolute. If `Path::new("")` is given,
    /// files will be served from the current directory.
    ///
    /// If a static file exists and can be read from, `enter` will serve it to
    /// the `Response` and `Unwind` the middleware stack with a status of `200`.
    ///
    /// In the case of any error, it will `Continue` through the stack.
    /// If a file should have been read but cannot, due to permissions or
    /// read errors, a different `Middleware` should handle it.
    ///
    /// If the path is '/', it will attempt to serve `index.html`.
    pub fn new(root_path: Path) -> Static {
        Static {
            root_path: root_path
        }
    }

    /// Create a favicon server from the given filepath.
    ///
    /// This will serve your favicon, as specified by `favicon_path`,
    /// to every request ending in "/favicon.ico" that it sees,
    /// and then unwind the middleware stack for those requests.
    ///
    /// It should be linked first in order to avoid additional processing
    /// for simple favicon requests.
    ///
    /// Unlike normally served static files, favicons are given a max-age
    /// of one day.
    #[allow(visible_private_types)]
    pub fn favicon(favicon_path: Path) -> Favicon {
        Favicon {
            favicon_path: favicon_path
        }
    }
}

impl Middleware for Static {
    fn enter(&mut self, req: &mut Request, res: &mut Response, alloy: &mut Alloy) -> Status {
        match req.url() {
            Some(path) => {
                // Check for requested file
                match res.serve_file(&self.root_path.join(
                    Path::new(
                        // Coerce to relative path.
                        // We include the slash to ensure that you never have a path like ".index.html"
                        // when you meant "./index.html", see http://is.gd/yz9p0B for an example.
                        "./".to_string().append(path.as_slice())))) {
                    Ok(()) => {
                        debug!("Serving static file at {}.",
                            &self.root_path.join("./".to_string().append(path.as_slice())).display());
                        return Unwind
                    },
                    Err(_) => ()
                }

                // Check for index.html
                let index_path = self.root_path.join(
                    Path::new("./".to_string().append(path.as_slice()))
                        .join("./index.html".to_string()));
                if index_path.is_file() {
                    // Avoid serving as a directory
                    if path.len() > 0 {
                        match path.as_slice().char_at_reverse(path.len()) {
                            '/' => {
                                match res.serve_file(&index_path) {
                                    Ok(()) => {
                                        debug!("Serving static file at {}.",
                                            &index_path.display());
                                        return Unwind
                                    },
                                    Err(err) => {
                                        debug!("Failed while trying to serve index.html: {}", err)
                                        return Continue
                                    }
                                }
                            },
                    // 303:
                            _ => ()
                        }
                    }
                    let redirect_path = match alloy.find::<OriginalUrl>() {
                        Some(&OriginalUrl(ref original_url)) => original_url.clone(),
                        None => path.clone()
                    }.append("/");
                    res.headers.extensions.insert("Location".to_string(), redirect_path.clone());
                    let _ = res.serve(::http::status::SeeOther,
                        format!("Redirecting to {}/", redirect_path).as_slice());
                    return Unwind
                }
            },
            None => ()
        }
        Continue
    }
}

impl Middleware for Favicon {
    fn enter(&mut self, req: &mut Request, res: &mut Response, _alloy: &mut Alloy) -> Status {
        match req.request_uri {
            AbsolutePath(ref path) => {
                if regex!("/favicon$").is_match(path.as_slice()) {
                    match res.serve_file(&self.favicon_path) {
                        Ok(()) => {
                            res.headers.cache_control = Some("max-age=86400".to_str());
                            return Unwind },
                        Err(_) => { return Continue }
                    }
                }
                Continue
            },
            _ => {
                Continue
            }
        }
    }
}
<commit_msg>(feat) Added dynamic max-age to favicon.<commit_after>#![crate_id = "staticfile"]
#![deny(missing_doc)]
#![feature(phase)]

//! Static file-serving middleware.

extern crate url;
#[phase(plugin)]
extern crate regex_macros;
extern crate regex;

extern crate http;
extern crate iron;
#[phase(plugin, link)]
extern crate log;
extern crate mount;

use http::headers::content_type::MediaType;

use iron::{Request, Response, Middleware, Alloy};
use iron::mixin::{GetUrl, Serve};
use iron::middleware::{Status, Continue, Unwind};
use mount::OriginalUrl;

/// The static file-serving `Middleware`.
#[deriving(Clone)]
pub struct Static {
    root_path: Path
}

#[deriving(Clone)]
#[doc(hidden)]
struct Favicon {
    max_age: u8,
    favicon_path: Path
}

impl Static {
    /// Create a new instance of `Static` with a given root path.
    ///
    /// This will attempt to serve static files from the given root path.
    /// The path may be relative or absolute. If `Path::new("")` is given,
    /// files will be served from the current directory.
    ///
    /// If a static file exists and can be read from, `enter` will serve it to
    /// the `Response` and `Unwind` the middleware stack with a status of `200`.
    ///
    /// In the case of any error, it will `Continue` through the stack.
    /// If a file should have been read but cannot, due to permissions or
    /// read errors, a different `Middleware` should handle it.
    ///
    /// If the path is '/', it will attempt to serve `index.html`.
    pub fn new(root_path: Path) -> Static {
        Static {
            root_path: root_path
        }
    }

    /// Create a favicon server from the given filepath.
    ///
    /// This will serve your favicon, as specified by `favicon_path`,
    /// to every request ending in "/favicon.ico" that it sees,
    /// and then unwind the middleware stack for those requests.
    ///
    /// It should be linked first in order to avoid additional processing
    /// for simple favicon requests.
    ///
    /// Unlike normally served static files, favicons are given a max-age,
    /// specified in seconds.
    #[allow(visible_private_types)]
    pub fn favicon(favicon_path: Path, max_age: u8) -> Favicon {
        Favicon {
            max_age: max_age,
            favicon_path: favicon_path
        }
    }
}

impl Middleware for Static {
    fn enter(&mut self, req: &mut Request, res: &mut Response, alloy: &mut Alloy) -> Status {
        match req.url() {
            Some(path) => {
                // Check for requested file
                match res.serve_file(&self.root_path.join(
                    Path::new(
                        // Coerce to relative path.
                        // We include the slash to ensure that you never have a path like ".index.html"
                        // when you meant "./index.html", see http://is.gd/yz9p0B for an example.
                        "./".to_string().append(path.as_slice())))) {
                    Ok(()) => {
                        debug!("Serving static file at {}.",
                            &self.root_path.join("./".to_string().append(path.as_slice())).display());
                        return Unwind
                    },
                    Err(_) => ()
                }

                // Check for index.html
                let index_path = self.root_path.join(
                    Path::new("./".to_string().append(path.as_slice()))
                        .join("./index.html".to_string()));
                if index_path.is_file() {
                    // Avoid serving as a directory
                    if path.len() > 0 {
                        match path.as_slice().char_at_reverse(path.len()) {
                            '/' => {
                                match res.serve_file(&index_path) {
                                    Ok(()) => {
                                        debug!("Serving static file at {}.",
                                            &index_path.display());
                                        return Unwind
                                    },
                                    Err(err) => {
                                        debug!("Failed while trying to serve index.html: {}", err)
                                        return Continue
                                    }
                                }
                            },
                    // 303:
                            _ => ()
                        }
                    }
                    let redirect_path = match alloy.find::<OriginalUrl>() {
                        Some(&OriginalUrl(ref original_url)) => original_url.clone(),
                        None => path.clone()
                    }.append("/");
                    res.headers.extensions.insert("Location".to_string(), redirect_path.clone());
                    let _ = res.serve(::http::status::SeeOther,
                        format!("Redirecting to {}/", redirect_path).as_slice());
                    return Unwind
                }
            },
            None => ()
        }
        Continue
    }
}

impl Middleware for Favicon {
    fn enter(&mut self, req: &mut Request, res: &mut Response, _alloy: &mut Alloy) -> Status {
        match req.url() {
            Some(path) => {
                if regex!("/favicon.ico$").is_match(path.as_slice()) {
                    res.headers.content_type = Some(MediaType {
                        type_: "image".to_string(),
                        subtype: "x-icon".to_string(),
                        parameters: vec![]
                    });
                    res.headers.cache_control = Some(format!("public, max-age={}", self.max_age));
                    let _ = res.try_write_headers();
                    match res.serve_file(&self.favicon_path) {
                        Ok(()) => (),
                        Err(_) => {
                            let _ = res.serve(::http::status::InternalServerError,
                                "Failed to serve favicon.ico.");
                        }
                    }
                    return Unwind;
                }
            },
            None => ()
        }
        Continue
    }
}
<|endoftext|>


<commit_before>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

//! Semantic version parsing and comparison.
//!
//! Semantic versioning (see http://semver.org/) is a set of rules for
//! assigning version numbers.
//!
//! ## SemVer overview
//!
//! Given a version number MAJOR.MINOR.PATCH, increment the:
//!
//! 1. MAJOR version when you make incompatible API changes,
//! 2. MINOR version when you add functionality in a backwards-compatible
//!    manner, and
//! 3. PATCH version when you make backwards-compatible bug fixes.
//!
//! Additional labels for pre-release and build metadata are available as
//! extensions to the MAJOR.MINOR.PATCH format.
//!
//! Any references to 'the spec' in this documentation refer to [version 2.0 of
//! the SemVer spec](http://semver.org/spec/v2.0.0.html).
//!
//! ## SemVer and the Rust ecosystem
//!
//! Rust itself follows the SemVer specification, as does its standard
//! libraries. The two are not tied together.
//!
//! [Cargo](http://crates.io), Rust's package manager, uses SemVer to determine
//! which versions of packages you need installed.
//!
//! ## Versions
//!
//! At its simplest, the `semver` crate allows you to construct `Version`
//! objects using the `parse` method:
//!
//! ```{rust}
//! use semver::Version;
//!
//! assert!(Version::parse("1.2.3") == Ok(Version {
//!    major: 1,
//!    minor: 2,
//!    patch: 3,
//!    pre: vec!(),
//!    build: vec!(),
//! }));
//! ```
//!
//! If you have multiple `Version`s, you can use the usual comparison operators
//! to compare them:
//!
//! ```{rust}
//! use semver::Version;
//!
//! assert!(Version::parse("1.2.3-alpha") != Version::parse("1.2.3-beta"));
//! assert!(Version::parse("1.2.3-alpha2") >  Version::parse("1.2.0"));
//! ```
//!
//! If you explicitly need to modify a Version, SemVer also allows you to
//! increment the major, minor, and patch numbers in accordance with the spec.
//!
//! Please note that in order to do this, you must use a mutable Version:
//!
//! ```{rust}
//! use semver::Version;
//!
//! let mut bugfix_release = Version::parse("1.0.0").unwrap();
//! bugfix_release.increment_patch();
//!
//! assert_eq!(Ok(bugfix_release), Version::parse("1.0.1"));
//! ```
//!
//! When incrementing the minor version number, the patch number resets to zero
//! (in accordance with section 7 of the spec)
//!
//! ```{rust}
//! use semver::Version;
//!
//! let mut feature_release = Version::parse("1.4.6").unwrap();
//! feature_release.increment_minor();
//!
//! assert_eq!(Ok(feature_release), Version::parse("1.5.0"));
//! ```
//!
//! Similarly, when incrementing the major version number, the patch and minor
//! numbers reset to zero (in accordance with section 8 of the spec)
//!
//! ```{rust}
//! use semver::Version;
//!
//! let mut chrome_release = Version::parse("41.5.5377").unwrap();
//! chrome_release.increment_major();
//!
//! assert_eq!(Ok(chrome_release), Version::parse("42.0.0"));
//! ```
//!
//! ## Requirements
//!
//! The `semver` crate also provides the ability to compare requirements, which
//! are more complex comparisons.
//!
//! For example, creating a requirement that only matches versions greater than
//! or equal to 1.0.0:
//!
//! ```{rust}
//! # #![allow(unstable)]
//! use semver::Version;
//! use semver::VersionReq;
//!
//! let r = VersionReq::parse(">= 1.0.0").unwrap();
//! let v = Version::parse("1.0.0").unwrap();
//!
//! assert!(r.to_string() == ">= 1.0.0".to_string());
//! assert!(r.matches(&v))
//! ```
//!
//! It also allows parsing of `~x.y.z` and `^x.y.z` requirements as defined at
//! https://www.npmjs.org/doc/misc/semver.html
//!
//! **Tilde requirements** specify a minimal version with some updates:
//!
//! ```notrust
//! ~1.2.3 := >=1.2.3 <1.3.0
//! ~1.2   := >=1.2.0 <1.3.0
//! ~1     := >=1.0.0 <2.0.0
//! ```
//!
//! **Caret requirements** allow SemVer compatible updates to a specified
//! verion, `0.x` and `0.x+1` are not considered compatible, but `1.x` and
//! `1.x+1` are.
//!
//! `0.0.x` is not considered compatible with any other version.
//! Missing minor and patch versions are desugared to `0` but allow flexibility
//! for that value.
//!
//! ```notrust
//! ^1.2.3 := >=1.2.3 <2.0.0
//! ^0.2.3 := >=0.2.3 <0.3.0
//! ^0.0.3 := >=0.0.3 <0.0.4
//! ^0.0   := >=0.0.0 <0.1.0
//! ^0     := >=0.0.0 <1.0.0
//! ```
//!
//! **Wildcard requirements** allows parsing of version requirements of the
//! formats `*`, `x.*` and `x.y.*`.
//!
//! ```notrust
//! *     := >=0.0.0
//! 1.*   := >=1.0.0 <2.0.0
//! 1.2.* := >=1.2.0 <1.3.0
//! ```

#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://www.rust-lang.org/favicon.ico")]
#![deny(missing_docs)]
#![cfg_attr(test, deny(warnings))]

extern crate semver_parser;

// Serialization and deserialization support for version numbers
#[cfg(feature = "serde")]
extern crate serde;

// We take the common approach of keeping our own module system private, and
// just re-exporting the interface that we want.

pub use version::{Version, Identifier, SemVerError};
pub use version::Identifier::{Numeric, AlphaNumeric};
pub use version_req::{VersionReq, ReqParseError};

// SemVer-compliant versions.
mod version;

// advanced version comparisons
mod version_req;
<commit_msg>add html root url attribute to crate root<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

//! Semantic version parsing and comparison.
//!
//! Semantic versioning (see http://semver.org/) is a set of rules for
//! assigning version numbers.
//!
//! ## SemVer overview
//!
//! Given a version number MAJOR.MINOR.PATCH, increment the:
//!
//! 1. MAJOR version when you make incompatible API changes,
//! 2. MINOR version when you add functionality in a backwards-compatible
//!    manner, and
//! 3. PATCH version when you make backwards-compatible bug fixes.
//!
//! Additional labels for pre-release and build metadata are available as
//! extensions to the MAJOR.MINOR.PATCH format.
//!
//! Any references to 'the spec' in this documentation refer to [version 2.0 of
//! the SemVer spec](http://semver.org/spec/v2.0.0.html).
//!
//! ## SemVer and the Rust ecosystem
//!
//! Rust itself follows the SemVer specification, as does its standard
//! libraries. The two are not tied together.
//!
//! [Cargo](http://crates.io), Rust's package manager, uses SemVer to determine
//! which versions of packages you need installed.
//!
//! ## Versions
//!
//! At its simplest, the `semver` crate allows you to construct `Version`
//! objects using the `parse` method:
//!
//! ```{rust}
//! use semver::Version;
//!
//! assert!(Version::parse("1.2.3") == Ok(Version {
//!    major: 1,
//!    minor: 2,
//!    patch: 3,
//!    pre: vec!(),
//!    build: vec!(),
//! }));
//! ```
//!
//! If you have multiple `Version`s, you can use the usual comparison operators
//! to compare them:
//!
//! ```{rust}
//! use semver::Version;
//!
//! assert!(Version::parse("1.2.3-alpha") != Version::parse("1.2.3-beta"));
//! assert!(Version::parse("1.2.3-alpha2") >  Version::parse("1.2.0"));
//! ```
//!
//! If you explicitly need to modify a Version, SemVer also allows you to
//! increment the major, minor, and patch numbers in accordance with the spec.
//!
//! Please note that in order to do this, you must use a mutable Version:
//!
//! ```{rust}
//! use semver::Version;
//!
//! let mut bugfix_release = Version::parse("1.0.0").unwrap();
//! bugfix_release.increment_patch();
//!
//! assert_eq!(Ok(bugfix_release), Version::parse("1.0.1"));
//! ```
//!
//! When incrementing the minor version number, the patch number resets to zero
//! (in accordance with section 7 of the spec)
//!
//! ```{rust}
//! use semver::Version;
//!
//! let mut feature_release = Version::parse("1.4.6").unwrap();
//! feature_release.increment_minor();
//!
//! assert_eq!(Ok(feature_release), Version::parse("1.5.0"));
//! ```
//!
//! Similarly, when incrementing the major version number, the patch and minor
//! numbers reset to zero (in accordance with section 8 of the spec)
//!
//! ```{rust}
//! use semver::Version;
//!
//! let mut chrome_release = Version::parse("41.5.5377").unwrap();
//! chrome_release.increment_major();
//!
//! assert_eq!(Ok(chrome_release), Version::parse("42.0.0"));
//! ```
//!
//! ## Requirements
//!
//! The `semver` crate also provides the ability to compare requirements, which
//! are more complex comparisons.
//!
//! For example, creating a requirement that only matches versions greater than
//! or equal to 1.0.0:
//!
//! ```{rust}
//! # #![allow(unstable)]
//! use semver::Version;
//! use semver::VersionReq;
//!
//! let r = VersionReq::parse(">= 1.0.0").unwrap();
//! let v = Version::parse("1.0.0").unwrap();
//!
//! assert!(r.to_string() == ">= 1.0.0".to_string());
//! assert!(r.matches(&v))
//! ```
//!
//! It also allows parsing of `~x.y.z` and `^x.y.z` requirements as defined at
//! https://www.npmjs.org/doc/misc/semver.html
//!
//! **Tilde requirements** specify a minimal version with some updates:
//!
//! ```notrust
//! ~1.2.3 := >=1.2.3 <1.3.0
//! ~1.2   := >=1.2.0 <1.3.0
//! ~1     := >=1.0.0 <2.0.0
//! ```
//!
//! **Caret requirements** allow SemVer compatible updates to a specified
//! verion, `0.x` and `0.x+1` are not considered compatible, but `1.x` and
//! `1.x+1` are.
//!
//! `0.0.x` is not considered compatible with any other version.
//! Missing minor and patch versions are desugared to `0` but allow flexibility
//! for that value.
//!
//! ```notrust
//! ^1.2.3 := >=1.2.3 <2.0.0
//! ^0.2.3 := >=0.2.3 <0.3.0
//! ^0.0.3 := >=0.0.3 <0.0.4
//! ^0.0   := >=0.0.0 <0.1.0
//! ^0     := >=0.0.0 <1.0.0
//! ```
//!
//! **Wildcard requirements** allows parsing of version requirements of the
//! formats `*`, `x.*` and `x.y.*`.
//!
//! ```notrust
//! *     := >=0.0.0
//! 1.*   := >=1.0.0 <2.0.0
//! 1.2.* := >=1.2.0 <1.3.0
//! ```

#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://www.rust-lang.org/favicon.ico",
       html_root_url = "https://docs.rs/semver")]
#![deny(missing_docs)]
#![cfg_attr(test, deny(warnings))]

extern crate semver_parser;

// Serialization and deserialization support for version numbers
#[cfg(feature = "serde")]
extern crate serde;

// We take the common approach of keeping our own module system private, and
// just re-exporting the interface that we want.

pub use version::{Version, Identifier, SemVerError};
pub use version::Identifier::{Numeric, AlphaNumeric};
pub use version_req::{VersionReq, ReqParseError};

// SemVer-compliant versions.
mod version;

// advanced version comparisons
mod version_req;
<|endoftext|>


<commit_before>extern crate arc_swap;
extern crate libc;

use std::collections::hash_map::Entry;
use std::collections::{BTreeMap, HashMap};
use std::io::Error;
use std::mem;
use std::panic::{self, AssertUnwindSafe};
use std::process;
use std::ptr;
use std::sync::{Arc, Mutex, MutexGuard, Once, ONCE_INIT};
use std::thread;

use arc_swap::ArcSwap;
use libc::{c_int, c_void, sigaction, siginfo_t, sigset_t, SIG_BLOCK, SIG_SETMASK};

#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
struct ActionId(u64);

#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct SigId {
    signal: c_int,
    action: ActionId,
}

#[derive(Clone)]
struct Slot {
    prev: sigaction,
    actions: BTreeMap<ActionId, Arc<Fn()>>,
}

impl Slot {
    fn new(signal: libc::c_int) -> Result<Self, Error> {
        // C data structure, expected to be zeroed out.
        let mut new: libc::sigaction = unsafe { mem::zeroed() };
        new.sa_sigaction = handler as usize;
        #[cfg(target_os = "android")]
        fn flags() -> libc::c_ulong {
            (libc::SA_RESTART as libc::c_ulong)
                | libc::SA_SIGINFO
                | (libc::SA_NOCLDSTOP as libc::c_ulong)
        }
        #[cfg(not(target_os = "android"))]
        fn flags() -> libc::c_int {
            libc::SA_RESTART | libc::SA_SIGINFO | libc::SA_NOCLDSTOP
        }
        new.sa_flags = flags();
        // C data structure, expected to be zeroed out.
        let mut old: libc::sigaction = unsafe { mem::zeroed() };
        // FFI ‒ pointers are valid, it doesn't take ownership.
        if unsafe { libc::sigaction(signal, &new, &mut old) } != 0 {
            return Err(Error::last_os_error());
        }
        Ok(Slot {
            prev: old,
            actions: BTreeMap::new(),
        })
    }
}

type AllSignals = HashMap<c_int, Slot>;

struct GlobalData {
    all_signals: ArcSwap<AllSignals>,
    rcu_lock: Mutex<u64>,
}

static mut GLOBAL_DATA: Option<GlobalData> = None;
static GLOBAL_INIT: Once = ONCE_INIT;

impl GlobalData {
    fn get() -> &'static Self {
        unsafe { GLOBAL_DATA.as_ref().unwrap() }
    }
    fn ensure() -> &'static Self {
        GLOBAL_INIT.call_once(|| unsafe {
            GLOBAL_DATA = Some(GlobalData {
                all_signals: ArcSwap::from(Arc::new(HashMap::new())),
                rcu_lock: Mutex::new(0),
            });
        });
        Self::get()
    }
    fn load(&self) -> (AllSignals, MutexGuard<u64>) {
        let lock = self.rcu_lock.lock().unwrap();
        let signals = AllSignals::clone(&self.all_signals.load());
        (signals, lock)
    }
    fn store(&self, signals: AllSignals, _lock: MutexGuard<u64>) {
        let mut previous = self.all_signals.swap(Arc::new(signals));
        while let Err(failed_unwrap) = Arc::try_unwrap(previous) {
            previous = failed_unwrap;
            thread::yield_now();
        }
    }
}

extern "C" fn handler(sig: c_int, info: *mut siginfo_t, data: *mut c_void) {
    let result = panic::catch_unwind(AssertUnwindSafe(|| {
        let signals = GlobalData::get().all_signals.load();

        if let Some(ref slot) = signals.get(&sig) {
            let fptr = slot.prev.sa_sigaction;
            if fptr != 0 && fptr != libc::SIG_DFL && fptr != libc::SIG_IGN {
                // FFI ‒ calling the original signal handler.
                unsafe {
                    if slot.prev.sa_flags & libc::SA_SIGINFO == 0 {
                        let action = mem::transmute::<usize, extern "C" fn(c_int)>(fptr);
                        action(sig);
                    } else {
                        type SigAction = extern "C" fn(c_int, *mut siginfo_t, *mut c_void);
                        let action = mem::transmute::<usize, SigAction>(fptr);
                        action(sig, info, data);
                    }
                }
            }

            for action in slot.actions.values() {
                action();
            }
        }
    }));
    if result.is_err() {
        eprintln!("Panic inside a signal handler for {}", sig);
        process::abort();
    }
}

fn block_signal(signal: c_int) -> Result<sigset_t, Error> {
    unsafe {
        let mut newsigs: sigset_t = mem::uninitialized();
        libc::sigemptyset(&mut newsigs);
        libc::sigaddset(&mut newsigs, signal);
        let mut oldsigs: sigset_t = mem::uninitialized();
        libc::sigemptyset(&mut oldsigs);
        if libc::sigprocmask(SIG_BLOCK, &newsigs, &mut oldsigs) == 0 {
            Ok(oldsigs)
        } else {
            Err(Error::last_os_error())
        }
    }
}

fn restore_signals(signals: libc::sigset_t) -> Result<(), Error> {
    if unsafe { libc::sigprocmask(SIG_SETMASK, &signals, ptr::null_mut()) } == 0 {
        Ok(())
    } else {
        Err(Error::last_os_error())
    }
}

fn without_signal<F: FnOnce() -> Result<(), Error>>(signal: c_int, f: F) -> Result<(), Error> {
    let old_signals = block_signal(signal)?;
    let result = f();
    let restored = restore_signals(old_signals);
    // In case of errors in both, prefer the one in result.
    result.and(restored)
}

pub unsafe fn register_action(signal: c_int, action: Box<Fn()>) -> Result<SigId, Error> {
    let globals = GlobalData::ensure();
    let (mut signals, mut lock) = globals.load();
    let id = ActionId(*lock);
    *lock += 1;
    let action = Arc::from(action);
    without_signal(signal, || {
        match signals.entry(signal) {
            Entry::Occupied(mut occupied) => {
                assert!(occupied.get_mut().actions.insert(id, action).is_none());
            }
            Entry::Vacant(place) => {
                let mut slot = Slot::new(signal)?;
                slot.actions.insert(id, action);
                place.insert(slot);
            }
        }

        globals.store(signals, lock);

        Ok(())
    })?;

    Ok(SigId { signal, action: id })
}

pub fn unregister(id: SigId) -> bool {
    let globals = GlobalData::ensure();
    let (mut signals, lock) = globals.load();
    let mut replace = false;
    if let Some(slot) = signals.get_mut(&id.signal) {
        replace = slot.actions.remove(&id.action).is_some();
    }
    if replace {
        globals.store(signals, lock);
    }
    replace
}
<commit_msg>Get rid of tiny clippy warning<commit_after>extern crate arc_swap;
extern crate libc;

use std::collections::hash_map::Entry;
use std::collections::{BTreeMap, HashMap};
use std::io::Error;
use std::mem;
use std::panic::{self, AssertUnwindSafe};
use std::process;
use std::ptr;
use std::sync::{Arc, Mutex, MutexGuard, Once, ONCE_INIT};
use std::thread;

use arc_swap::ArcSwap;
use libc::{c_int, c_void, sigaction, siginfo_t, sigset_t, SIG_BLOCK, SIG_SETMASK};

#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
struct ActionId(u64);

#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct SigId {
    signal: c_int,
    action: ActionId,
}

#[derive(Clone)]
struct Slot {
    prev: sigaction,
    actions: BTreeMap<ActionId, Arc<Fn()>>,
}

impl Slot {
    fn new(signal: libc::c_int) -> Result<Self, Error> {
        // C data structure, expected to be zeroed out.
        let mut new: libc::sigaction = unsafe { mem::zeroed() };
        new.sa_sigaction = handler as usize;
        #[cfg(target_os = "android")]
        fn flags() -> libc::c_ulong {
            (libc::SA_RESTART as libc::c_ulong)
                | libc::SA_SIGINFO
                | (libc::SA_NOCLDSTOP as libc::c_ulong)
        }
        #[cfg(not(target_os = "android"))]
        fn flags() -> libc::c_int {
            libc::SA_RESTART | libc::SA_SIGINFO | libc::SA_NOCLDSTOP
        }
        new.sa_flags = flags();
        // C data structure, expected to be zeroed out.
        let mut old: libc::sigaction = unsafe { mem::zeroed() };
        // FFI ‒ pointers are valid, it doesn't take ownership.
        if unsafe { libc::sigaction(signal, &new, &mut old) } != 0 {
            return Err(Error::last_os_error());
        }
        Ok(Slot {
            prev: old,
            actions: BTreeMap::new(),
        })
    }
}

type AllSignals = HashMap<c_int, Slot>;

struct GlobalData {
    all_signals: ArcSwap<AllSignals>,
    rcu_lock: Mutex<u64>,
}

static mut GLOBAL_DATA: Option<GlobalData> = None;
static GLOBAL_INIT: Once = ONCE_INIT;

impl GlobalData {
    fn get() -> &'static Self {
        unsafe { GLOBAL_DATA.as_ref().unwrap() }
    }
    fn ensure() -> &'static Self {
        GLOBAL_INIT.call_once(|| unsafe {
            GLOBAL_DATA = Some(GlobalData {
                all_signals: ArcSwap::from(Arc::new(HashMap::new())),
                rcu_lock: Mutex::new(0),
            });
        });
        Self::get()
    }
    fn load(&self) -> (AllSignals, MutexGuard<u64>) {
        let lock = self.rcu_lock.lock().unwrap();
        let signals = AllSignals::clone(&self.all_signals.load());
        (signals, lock)
    }
    fn store(&self, signals: AllSignals, lock: MutexGuard<u64>) {
        let mut previous = self.all_signals.swap(Arc::new(signals));
        while let Err(failed_unwrap) = Arc::try_unwrap(previous) {
            previous = failed_unwrap;
            thread::yield_now();
        }
        drop(lock);
    }
}

extern "C" fn handler(sig: c_int, info: *mut siginfo_t, data: *mut c_void) {
    let result = panic::catch_unwind(AssertUnwindSafe(|| {
        let signals = GlobalData::get().all_signals.load();

        if let Some(ref slot) = signals.get(&sig) {
            let fptr = slot.prev.sa_sigaction;
            if fptr != 0 && fptr != libc::SIG_DFL && fptr != libc::SIG_IGN {
                // FFI ‒ calling the original signal handler.
                unsafe {
                    if slot.prev.sa_flags & libc::SA_SIGINFO == 0 {
                        let action = mem::transmute::<usize, extern "C" fn(c_int)>(fptr);
                        action(sig);
                    } else {
                        type SigAction = extern "C" fn(c_int, *mut siginfo_t, *mut c_void);
                        let action = mem::transmute::<usize, SigAction>(fptr);
                        action(sig, info, data);
                    }
                }
            }

            for action in slot.actions.values() {
                action();
            }
        }
    }));
    if result.is_err() {
        eprintln!("Panic inside a signal handler for {}", sig);
        process::abort();
    }
}

fn block_signal(signal: c_int) -> Result<sigset_t, Error> {
    unsafe {
        let mut newsigs: sigset_t = mem::uninitialized();
        libc::sigemptyset(&mut newsigs);
        libc::sigaddset(&mut newsigs, signal);
        let mut oldsigs: sigset_t = mem::uninitialized();
        libc::sigemptyset(&mut oldsigs);
        if libc::sigprocmask(SIG_BLOCK, &newsigs, &mut oldsigs) == 0 {
            Ok(oldsigs)
        } else {
            Err(Error::last_os_error())
        }
    }
}

fn restore_signals(signals: libc::sigset_t) -> Result<(), Error> {
    if unsafe { libc::sigprocmask(SIG_SETMASK, &signals, ptr::null_mut()) } == 0 {
        Ok(())
    } else {
        Err(Error::last_os_error())
    }
}

fn without_signal<F: FnOnce() -> Result<(), Error>>(signal: c_int, f: F) -> Result<(), Error> {
    let old_signals = block_signal(signal)?;
    let result = f();
    let restored = restore_signals(old_signals);
    // In case of errors in both, prefer the one in result.
    result.and(restored)
}

pub unsafe fn register_action(signal: c_int, action: Box<Fn()>) -> Result<SigId, Error> {
    let globals = GlobalData::ensure();
    let (mut signals, mut lock) = globals.load();
    let id = ActionId(*lock);
    *lock += 1;
    let action = Arc::from(action);
    without_signal(signal, || {
        match signals.entry(signal) {
            Entry::Occupied(mut occupied) => {
                assert!(occupied.get_mut().actions.insert(id, action).is_none());
            }
            Entry::Vacant(place) => {
                let mut slot = Slot::new(signal)?;
                slot.actions.insert(id, action);
                place.insert(slot);
            }
        }

        globals.store(signals, lock);

        Ok(())
    })?;

    Ok(SigId { signal, action: id })
}

pub fn unregister(id: SigId) -> bool {
    let globals = GlobalData::ensure();
    let (mut signals, lock) = globals.load();
    let mut replace = false;
    if let Some(slot) = signals.get_mut(&id.signal) {
        replace = slot.actions.remove(&id.action).is_some();
    }
    if replace {
        globals.store(signals, lock);
    }
    replace
}
<|endoftext|>