<commit_before>use crate::get_error;
use crate::surface::SurfaceRef;
use crate::video;
use crate::EventPump;
use std::mem::transmute;

use crate::sys;
use crate::sys::SDL_SystemCursor;

mod relative;
pub use self::relative::RelativeMouseState;

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[repr(u32)]
pub enum SystemCursor {
    Arrow = SDL_SystemCursor::SDL_SYSTEM_CURSOR_ARROW as u32,
    IBeam = SDL_SystemCursor::SDL_SYSTEM_CURSOR_IBEAM as u32,
    Wait = SDL_SystemCursor::SDL_SYSTEM_CURSOR_WAIT as u32,
    Crosshair = SDL_SystemCursor::SDL_SYSTEM_CURSOR_CROSSHAIR as u32,
    WaitArrow = SDL_SystemCursor::SDL_SYSTEM_CURSOR_WAITARROW as u32,
    SizeNWSE = SDL_SystemCursor::SDL_SYSTEM_CURSOR_SIZENWSE as u32,
    SizeNESW = SDL_SystemCursor::SDL_SYSTEM_CURSOR_SIZENESW as u32,
    SizeWE = SDL_SystemCursor::SDL_SYSTEM_CURSOR_SIZEWE as u32,
    SizeNS = SDL_SystemCursor::SDL_SYSTEM_CURSOR_SIZENS as u32,
    SizeAll = SDL_SystemCursor::SDL_SYSTEM_CURSOR_SIZEALL as u32,
    No = SDL_SystemCursor::SDL_SYSTEM_CURSOR_NO as u32,
    Hand = SDL_SystemCursor::SDL_SYSTEM_CURSOR_HAND as u32,
}

pub struct Cursor {
    raw: *mut sys::SDL_Cursor,
}

impl Drop for Cursor {
    #[inline]
    #[doc(alias = "SDL_FreeCursor")]
    fn drop(&mut self) {
        unsafe { sys::SDL_FreeCursor(self.raw) };
    }
}

impl Cursor {
    #[doc(alias = "SDL_CreateCursor")]
    pub fn new(
        data: &[u8],
        mask: &[u8],
        width: i32,
        height: i32,
        hot_x: i32,
        hot_y: i32,
    ) -> Result<Cursor, String> {
        unsafe {
            let raw = sys::SDL_CreateCursor(
                data.as_ptr(),
                mask.as_ptr(),
                width as i32,
                height as i32,
                hot_x as i32,
                hot_y as i32,
            );

            if raw.is_null() {
                Err(get_error())
            } else {
                Ok(Cursor { raw })
            }
        }
    }

    // TODO: figure out how to pass Surface in here correctly
    #[doc(alias = "SDL_CreateColorCursor")]
    pub fn from_surface<S: AsRef<SurfaceRef>>(
        surface: S,
        hot_x: i32,
        hot_y: i32,
    ) -> Result<Cursor, String> {
        unsafe {
            let raw = sys::SDL_CreateColorCursor(surface.as_ref().raw(), hot_x, hot_y);

            if raw.is_null() {
                Err(get_error())
            } else {
                Ok(Cursor { raw })
            }
        }
    }

    #[doc(alias = "SDL_CreateSystemCursor")]
    pub fn from_system(cursor: SystemCursor) -> Result<Cursor, String> {
        unsafe {
            let raw = sys::SDL_CreateSystemCursor(transmute(cursor as u32));

            if raw.is_null() {
                Err(get_error())
            } else {
                Ok(Cursor { raw })
            }
        }
    }

    #[doc(alias = "SDL_SetCursor")]
    pub fn set(&self) {
        unsafe {
            sys::SDL_SetCursor(self.raw);
        }
    }
}

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum MouseWheelDirection {
    Normal,
    Flipped,
    Unknown(u32),
}

// 0 and 1 are not fixed values in the SDL source code.  This value is defined as an enum which is then cast to a Uint32.
// The enum in C is defined as such:

/**
 * \brief Scroll direction types for the Scroll event
 */
//typedef enum
//{
//    SDL_MOUSEWHEEL_NORMAL,    /**< The scroll direction is normal */
//    SDL_MOUSEWHEEL_FLIPPED    /**< The scroll direction is flipped / natural */
//} SDL_MouseWheelDirection;

// Since no value is given in the enum definition these values are auto assigned by the C compiler starting at 0.
// Normally I would prefer to use the enum rather than hard code what it is implied to represent however
// the mouse wheel direction value could be described equally as well by a bool, so I don't think changes
// to this enum in the C source code are going to be a problem.

impl MouseWheelDirection {
    #[inline]
    pub fn from_ll(direction: u32) -> MouseWheelDirection {
        match direction {
            0 => MouseWheelDirection::Normal,
            1 => MouseWheelDirection::Flipped,
            _ => MouseWheelDirection::Unknown(direction),
        }
    }
    #[inline]
    pub fn to_ll(self) -> u32 {
        match self {
            MouseWheelDirection::Normal => 0,
            MouseWheelDirection::Flipped => 1,
            MouseWheelDirection::Unknown(direction) => direction,
        }
    }
}

#[repr(u8)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum MouseButton {
    Unknown = 0,
    Left = sys::SDL_BUTTON_LEFT as u8,
    Middle = sys::SDL_BUTTON_MIDDLE as u8,
    Right = sys::SDL_BUTTON_RIGHT as u8,
    X1 = sys::SDL_BUTTON_X1 as u8,
    X2 = sys::SDL_BUTTON_X2 as u8,
}

impl MouseButton {
    #[inline]
    pub fn from_ll(button: u8) -> MouseButton {
        match button as u32 {
            sys::SDL_BUTTON_LEFT => MouseButton::Left,
            sys::SDL_BUTTON_MIDDLE => MouseButton::Middle,
            sys::SDL_BUTTON_RIGHT => MouseButton::Right,
            sys::SDL_BUTTON_X1 => MouseButton::X1,
            sys::SDL_BUTTON_X2 => MouseButton::X2,
            _ => MouseButton::Unknown,
        }
    }
}

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct MouseState {
    mouse_state: u32,
    x: i32,
    y: i32,
}

impl MouseState {
    #[doc(alias = "SDL_GetMouseState")]
    pub fn new(_e: &EventPump) -> MouseState {
        let mut x = 0;
        let mut y = 0;
        let mouse_state: u32 = unsafe { sys::SDL_GetMouseState(&mut x, &mut y) };

        MouseState {
            mouse_state,
            x: x as i32,
            y: y as i32,
        }
    }

    pub fn from_sdl_state(state: u32) -> MouseState {
        MouseState {
            mouse_state: state,
            x: 0,
            y: 0,
        }
    }
    pub fn to_sdl_state(&self) -> u32 {
        self.mouse_state
    }

    fn button_mask(&self, button: u32) -> u32 {
        1 << (button - 1)
    }

    /// Returns true if the left mouse button is pressed.
    ///
    /// # Example
    /// ```no_run
    /// use sdl2::mouse::MouseButton;
    ///
    /// fn is_a_pressed(e: &sdl2::EventPump) -> bool {
    ///     e.mouse_state().left()
    /// }
    /// ```
    pub fn left(&self) -> bool {
        (self.mouse_state & self.button_mask(sys::SDL_BUTTON_LEFT)) != 0
    }

    /// Tests if the middle mouse button was pressed.
    pub fn middle(&self) -> bool {
        (self.mouse_state & self.button_mask(sys::SDL_BUTTON_MIDDLE)) != 0
    }

    /// Tests if the right mouse button was pressed.
    pub fn right(&self) -> bool {
        (self.mouse_state & self.button_mask(sys::SDL_BUTTON_RIGHT)) != 0
    }

    /// Tests if the X1 mouse button was pressed.
    pub fn x1(&self) -> bool {
        (self.mouse_state & self.button_mask(sys::SDL_BUTTON_X1)) != 0
    }

    /// Tests if the X2 mouse button was pressed.
    pub fn x2(&self) -> bool {
        (self.mouse_state & self.button_mask(sys::SDL_BUTTON_X2)) != 0
    }

    /// Returns the x coordinate of the state
    pub fn x(&self) -> i32 {
        self.x
    }

    /// Returns the y coordinate of the state
    pub fn y(&self) -> i32 {
        self.y
    }

    /// Returns true if the mouse button is pressed.
    ///
    /// # Example
    /// ```no_run
    /// use sdl2::mouse::MouseButton;
    ///
    /// fn is_left_pressed(e: &sdl2::EventPump) -> bool {
    ///     e.mouse_state().is_mouse_button_pressed(MouseButton::Left)
    /// }
    /// ```
    pub fn is_mouse_button_pressed(&self, mouse_button: MouseButton) -> bool {
        let mask = 1 << ((mouse_button as u32) - 1);
        self.mouse_state & mask != 0
    }

    /// Returns an iterator all mouse buttons with a boolean indicating if the scancode is pressed.
    ///
    /// # Example
    /// ```no_run
    /// use sdl2::mouse::MouseButton;
    /// use std::collections::HashMap;
    ///
    /// fn mouse_button_set(e: &sdl2::EventPump) -> HashMap<MouseButton, bool> {
    ///     e.mouse_state().mouse_buttons().collect()
    /// }
    ///
    /// fn find_first_pressed(e: &sdl2::EventPump) -> bool {
    ///     for (key,value) in mouse_button_set(e) {
    ///         return value != false
    ///     }
    ///     false
    /// }
    ///
    /// ```
    pub fn mouse_buttons(&self) -> MouseButtonIterator {
        MouseButtonIterator {
            cur_button: 1,
            mouse_state: &self.mouse_state,
        }
    }

    /// Returns an iterator of pressed mouse buttons.
    ///
    /// # Example
    /// ```no_run
    /// use sdl2::mouse::MouseButton;
    /// use std::collections::HashSet;
    ///
    /// fn pressed_mouse_button_set(e: &sdl2::EventPump) -> HashSet<MouseButton> {
    ///     e.mouse_state().pressed_mouse_buttons().collect()
    /// }
    ///
    /// fn newly_pressed(old: &HashSet<MouseButton>, new: &HashSet<MouseButton>) -> HashSet<MouseButton> {
    ///     new - old
    ///     // sugar for: new.difference(old).collect()
    /// }
    /// ```
    pub fn pressed_mouse_buttons(&self) -> PressedMouseButtonIterator {
        PressedMouseButtonIterator {
            iter: self.mouse_buttons(),
        }
    }
}

pub struct MouseButtonIterator<'a> {
    cur_button: u8,
    mouse_state: &'a u32,
}

impl<'a> Iterator for MouseButtonIterator<'a> {
    type Item = (MouseButton, bool);

    fn next(&mut self) -> Option<(MouseButton, bool)> {
        if self.cur_button < MouseButton::X2 as u8 + 1 {
            let mouse_button = self.cur_button;
            let mask = 1 << ((self.cur_button as u32) - 1);
            let pressed = self.mouse_state & mask != 0;
            self.cur_button += 1;
            Some((MouseButton::from_ll(mouse_button), pressed))
        } else {
            None
        }
    }
}

pub struct PressedMouseButtonIterator<'a> {
    iter: MouseButtonIterator<'a>,
}

impl<'a> Iterator for PressedMouseButtonIterator<'a> {
    type Item = MouseButton;

    fn next(&mut self) -> Option<MouseButton> {
        while let Some((mouse_button, pressed)) = self.iter.next() {
            if pressed {
                return Some(mouse_button);
            }
        }
        None
    }
}

impl crate::Sdl {
    #[inline]
    pub fn mouse(&self) -> MouseUtil {
        MouseUtil {
            _sdldrop: self.sdldrop(),
        }
    }
}

/// Mouse utility functions. Access with `Sdl::mouse()`.
///
/// ```no_run
/// let sdl_context = sdl2::init().unwrap();
///
/// // Hide the cursor
/// sdl_context.mouse().show_cursor(false);
/// ```
pub struct MouseUtil {
    _sdldrop: crate::SdlDrop,
}

impl MouseUtil {
    /// Gets the id of the window which currently has mouse focus.
    #[doc(alias = "SDL_GetMouseFocus")]
    pub fn focused_window_id(&self) -> Option<u32> {
        let raw = unsafe { sys::SDL_GetMouseFocus() };
        if raw.is_null() {
            None
        } else {
            let id = unsafe { sys::SDL_GetWindowID(raw) };
            Some(id)
        }
    }

    #[doc(alias = "SDL_WarpMouseInWindow")]
    pub fn warp_mouse_in_window(&self, window: &video::Window, x: i32, y: i32) {
        unsafe {
            sys::SDL_WarpMouseInWindow(window.raw(), x, y);
        }
    }

    #[doc(alias = "SDL_SetRelativeMouseMode")]
    pub fn set_relative_mouse_mode(&self, on: bool) {
        let on = if on {
            sys::SDL_bool::SDL_TRUE
        } else {
            sys::SDL_bool::SDL_FALSE
        };
        unsafe {
            sys::SDL_SetRelativeMouseMode(on);
        }
    }

    #[doc(alias = "SDL_GetRelativeMouseMode")]
    pub fn relative_mouse_mode(&self) -> bool {
        unsafe { sys::SDL_GetRelativeMouseMode() == sys::SDL_bool::SDL_TRUE }
    }

    #[doc(alias = "SDL_ShowCursor")]
    pub fn is_cursor_showing(&self) -> bool {
        unsafe { sys::SDL_ShowCursor(crate::sys::SDL_QUERY) == 1 }
    }

    #[doc(alias = "SDL_ShowCursor")]
    pub fn show_cursor(&self, show: bool) {
        unsafe {
            sys::SDL_ShowCursor(show as i32);
        }
    }

    #[doc(alias = "SDL_CaptureMouse")]
    pub fn capture(&self, enable: bool) {
        let enable = if enable {
            sys::SDL_bool::SDL_TRUE
        } else {
            sys::SDL_bool::SDL_FALSE
        };
        unsafe {
            sys::SDL_CaptureMouse(enable);
        }
    }
}
<commit_msg>Update mod.rs<commit_after>use crate::get_error;
use crate::surface::SurfaceRef;
use crate::video;
use crate::EventPump;
use std::mem::transmute;

use crate::sys;
use crate::sys::SDL_SystemCursor;

mod relative;
pub use self::relative::RelativeMouseState;

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[repr(u32)]
pub enum SystemCursor {
    Arrow = SDL_SystemCursor::SDL_SYSTEM_CURSOR_ARROW as u32,
    IBeam = SDL_SystemCursor::SDL_SYSTEM_CURSOR_IBEAM as u32,
    Wait = SDL_SystemCursor::SDL_SYSTEM_CURSOR_WAIT as u32,
    Crosshair = SDL_SystemCursor::SDL_SYSTEM_CURSOR_CROSSHAIR as u32,
    WaitArrow = SDL_SystemCursor::SDL_SYSTEM_CURSOR_WAITARROW as u32,
    SizeNWSE = SDL_SystemCursor::SDL_SYSTEM_CURSOR_SIZENWSE as u32,
    SizeNESW = SDL_SystemCursor::SDL_SYSTEM_CURSOR_SIZENESW as u32,
    SizeWE = SDL_SystemCursor::SDL_SYSTEM_CURSOR_SIZEWE as u32,
    SizeNS = SDL_SystemCursor::SDL_SYSTEM_CURSOR_SIZENS as u32,
    SizeAll = SDL_SystemCursor::SDL_SYSTEM_CURSOR_SIZEALL as u32,
    No = SDL_SystemCursor::SDL_SYSTEM_CURSOR_NO as u32,
    Hand = SDL_SystemCursor::SDL_SYSTEM_CURSOR_HAND as u32,
}

pub struct Cursor {
    raw: *mut sys::SDL_Cursor,
}

impl Drop for Cursor {
    #[inline]
    #[doc(alias = "SDL_FreeCursor")]
    fn drop(&mut self) {
        unsafe { sys::SDL_FreeCursor(self.raw) };
    }
}

impl Cursor {
    #[doc(alias = "SDL_CreateCursor")]
    pub fn new(
        data: &[u8],
        mask: &[u8],
        width: i32,
        height: i32,
        hot_x: i32,
        hot_y: i32,
    ) -> Result<Cursor, String> {
        unsafe {
            let raw = sys::SDL_CreateCursor(
                data.as_ptr(),
                mask.as_ptr(),
                width as i32,
                height as i32,
                hot_x as i32,
                hot_y as i32,
            );

            if raw.is_null() {
                Err(get_error())
            } else {
                Ok(Cursor { raw })
            }
        }
    }

    // TODO: figure out how to pass Surface in here correctly
    #[doc(alias = "SDL_CreateColorCursor")]
    pub fn from_surface<S: AsRef<SurfaceRef>>(
        surface: S,
        hot_x: i32,
        hot_y: i32,
    ) -> Result<Cursor, String> {
        unsafe {
            let raw = sys::SDL_CreateColorCursor(surface.as_ref().raw(), hot_x, hot_y);

            if raw.is_null() {
                Err(get_error())
            } else {
                Ok(Cursor { raw })
            }
        }
    }

    #[doc(alias = "SDL_CreateSystemCursor")]
    pub fn from_system(cursor: SystemCursor) -> Result<Cursor, String> {
        unsafe {
            let raw = sys::SDL_CreateSystemCursor(transmute(cursor as u32));

            if raw.is_null() {
                Err(get_error())
            } else {
                Ok(Cursor { raw })
            }
        }
    }

    #[doc(alias = "SDL_SetCursor")]
    pub fn set(&self) {
        unsafe {
            sys::SDL_SetCursor(self.raw);
        }
    }
}

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum MouseWheelDirection {
    Normal,
    Flipped,
    Unknown(u32),
}

// 0 and 1 are not fixed values in the SDL source code.  This value is defined as an enum which is then cast to a Uint32.
// The enum in C is defined as such:

/**
 * \brief Scroll direction types for the Scroll event
 */
//typedef enum
//{
//    SDL_MOUSEWHEEL_NORMAL,    /**< The scroll direction is normal */
//    SDL_MOUSEWHEEL_FLIPPED    /**< The scroll direction is flipped / natural */
//} SDL_MouseWheelDirection;

// Since no value is given in the enum definition these values are auto assigned by the C compiler starting at 0.
// Normally I would prefer to use the enum rather than hard code what it is implied to represent however
// the mouse wheel direction value could be described equally as well by a bool, so I don't think changes
// to this enum in the C source code are going to be a problem.

impl MouseWheelDirection {
    #[inline]
    pub fn from_ll(direction: u32) -> MouseWheelDirection {
        match direction {
            0 => MouseWheelDirection::Normal,
            1 => MouseWheelDirection::Flipped,
            _ => MouseWheelDirection::Unknown(direction),
        }
    }
    #[inline]
    pub fn to_ll(self) -> u32 {
        match self {
            MouseWheelDirection::Normal => 0,
            MouseWheelDirection::Flipped => 1,
            MouseWheelDirection::Unknown(direction) => direction,
        }
    }
}

#[repr(u8)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum MouseButton {
    Unknown = 0,
    Left = sys::SDL_BUTTON_LEFT as u8,
    Middle = sys::SDL_BUTTON_MIDDLE as u8,
    Right = sys::SDL_BUTTON_RIGHT as u8,
    X1 = sys::SDL_BUTTON_X1 as u8,
    X2 = sys::SDL_BUTTON_X2 as u8,
}

impl MouseButton {
    #[inline]
    pub fn from_ll(button: u8) -> MouseButton {
        match button as u32 {
            sys::SDL_BUTTON_LEFT => MouseButton::Left,
            sys::SDL_BUTTON_MIDDLE => MouseButton::Middle,
            sys::SDL_BUTTON_RIGHT => MouseButton::Right,
            sys::SDL_BUTTON_X1 => MouseButton::X1,
            sys::SDL_BUTTON_X2 => MouseButton::X2,
            _ => MouseButton::Unknown,
        }
    }
}

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct MouseState {
    mouse_state: u32,
    x: i32,
    y: i32,
}

impl MouseState {
    #[doc(alias = "SDL_GetMouseState")]
    pub fn new(_e: &EventPump) -> MouseState {
        let mut x = 0;
        let mut y = 0;
        let mouse_state: u32 = unsafe { sys::SDL_GetMouseState(&mut x, &mut y) };

        MouseState {
            mouse_state,
            x: x as i32,
            y: y as i32,
        }
    }

    pub fn from_sdl_state(state: u32) -> MouseState {
        MouseState {
            mouse_state: state,
            x: 0,
            y: 0,
        }
    }
    pub fn to_sdl_state(&self) -> u32 {
        self.mouse_state
    }

    fn button_mask(&self, button: u32) -> u32 {
        1 << (button - 1)
    }

    /// Returns true if the left mouse button is pressed.
    ///
    /// # Example
    /// ```no_run
    /// use sdl2::mouse::MouseButton;
    ///
    /// fn is_left_pressed(e: &sdl2::EventPump) -> bool {
    ///     e.mouse_state().left()
    /// }
    /// ```
    pub fn left(&self) -> bool {
        (self.mouse_state & self.button_mask(sys::SDL_BUTTON_LEFT)) != 0
    }

    /// Tests if the middle mouse button was pressed.
    pub fn middle(&self) -> bool {
        (self.mouse_state & self.button_mask(sys::SDL_BUTTON_MIDDLE)) != 0
    }

    /// Tests if the right mouse button was pressed.
    pub fn right(&self) -> bool {
        (self.mouse_state & self.button_mask(sys::SDL_BUTTON_RIGHT)) != 0
    }

    /// Tests if the X1 mouse button was pressed.
    pub fn x1(&self) -> bool {
        (self.mouse_state & self.button_mask(sys::SDL_BUTTON_X1)) != 0
    }

    /// Tests if the X2 mouse button was pressed.
    pub fn x2(&self) -> bool {
        (self.mouse_state & self.button_mask(sys::SDL_BUTTON_X2)) != 0
    }

    /// Returns the x coordinate of the state
    pub fn x(&self) -> i32 {
        self.x
    }

    /// Returns the y coordinate of the state
    pub fn y(&self) -> i32 {
        self.y
    }

    /// Returns true if the mouse button is pressed.
    ///
    /// # Example
    /// ```no_run
    /// use sdl2::mouse::MouseButton;
    ///
    /// fn is_left_pressed(e: &sdl2::EventPump) -> bool {
    ///     e.mouse_state().is_mouse_button_pressed(MouseButton::Left)
    /// }
    /// ```
    pub fn is_mouse_button_pressed(&self, mouse_button: MouseButton) -> bool {
        let mask = 1 << ((mouse_button as u32) - 1);
        self.mouse_state & mask != 0
    }

    /// Returns an iterator all mouse buttons with a boolean indicating if the scancode is pressed.
    ///
    /// # Example
    /// ```no_run
    /// use sdl2::mouse::MouseButton;
    /// use std::collections::HashMap;
    ///
    /// fn mouse_button_set(e: &sdl2::EventPump) -> HashMap<MouseButton, bool> {
    ///     e.mouse_state().mouse_buttons().collect()
    /// }
    ///
    /// fn find_first_pressed(e: &sdl2::EventPump) -> bool {
    ///     for (key,value) in mouse_button_set(e) {
    ///         return value != false
    ///     }
    ///     false
    /// }
    ///
    /// ```
    pub fn mouse_buttons(&self) -> MouseButtonIterator {
        MouseButtonIterator {
            cur_button: 1,
            mouse_state: &self.mouse_state,
        }
    }

    /// Returns an iterator of pressed mouse buttons.
    ///
    /// # Example
    /// ```no_run
    /// use sdl2::mouse::MouseButton;
    /// use std::collections::HashSet;
    ///
    /// fn pressed_mouse_button_set(e: &sdl2::EventPump) -> HashSet<MouseButton> {
    ///     e.mouse_state().pressed_mouse_buttons().collect()
    /// }
    ///
    /// fn newly_pressed(old: &HashSet<MouseButton>, new: &HashSet<MouseButton>) -> HashSet<MouseButton> {
    ///     new - old
    ///     // sugar for: new.difference(old).collect()
    /// }
    /// ```
    pub fn pressed_mouse_buttons(&self) -> PressedMouseButtonIterator {
        PressedMouseButtonIterator {
            iter: self.mouse_buttons(),
        }
    }
}

pub struct MouseButtonIterator<'a> {
    cur_button: u8,
    mouse_state: &'a u32,
}

impl<'a> Iterator for MouseButtonIterator<'a> {
    type Item = (MouseButton, bool);

    fn next(&mut self) -> Option<(MouseButton, bool)> {
        if self.cur_button < MouseButton::X2 as u8 + 1 {
            let mouse_button = self.cur_button;
            let mask = 1 << ((self.cur_button as u32) - 1);
            let pressed = self.mouse_state & mask != 0;
            self.cur_button += 1;
            Some((MouseButton::from_ll(mouse_button), pressed))
        } else {
            None
        }
    }
}

pub struct PressedMouseButtonIterator<'a> {
    iter: MouseButtonIterator<'a>,
}

impl<'a> Iterator for PressedMouseButtonIterator<'a> {
    type Item = MouseButton;

    fn next(&mut self) -> Option<MouseButton> {
        while let Some((mouse_button, pressed)) = self.iter.next() {
            if pressed {
                return Some(mouse_button);
            }
        }
        None
    }
}

impl crate::Sdl {
    #[inline]
    pub fn mouse(&self) -> MouseUtil {
        MouseUtil {
            _sdldrop: self.sdldrop(),
        }
    }
}

/// Mouse utility functions. Access with `Sdl::mouse()`.
///
/// ```no_run
/// let sdl_context = sdl2::init().unwrap();
///
/// // Hide the cursor
/// sdl_context.mouse().show_cursor(false);
/// ```
pub struct MouseUtil {
    _sdldrop: crate::SdlDrop,
}

impl MouseUtil {
    /// Gets the id of the window which currently has mouse focus.
    #[doc(alias = "SDL_GetMouseFocus")]
    pub fn focused_window_id(&self) -> Option<u32> {
        let raw = unsafe { sys::SDL_GetMouseFocus() };
        if raw.is_null() {
            None
        } else {
            let id = unsafe { sys::SDL_GetWindowID(raw) };
            Some(id)
        }
    }

    #[doc(alias = "SDL_WarpMouseInWindow")]
    pub fn warp_mouse_in_window(&self, window: &video::Window, x: i32, y: i32) {
        unsafe {
            sys::SDL_WarpMouseInWindow(window.raw(), x, y);
        }
    }

    #[doc(alias = "SDL_SetRelativeMouseMode")]
    pub fn set_relative_mouse_mode(&self, on: bool) {
        let on = if on {
            sys::SDL_bool::SDL_TRUE
        } else {
            sys::SDL_bool::SDL_FALSE
        };
        unsafe {
            sys::SDL_SetRelativeMouseMode(on);
        }
    }

    #[doc(alias = "SDL_GetRelativeMouseMode")]
    pub fn relative_mouse_mode(&self) -> bool {
        unsafe { sys::SDL_GetRelativeMouseMode() == sys::SDL_bool::SDL_TRUE }
    }

    #[doc(alias = "SDL_ShowCursor")]
    pub fn is_cursor_showing(&self) -> bool {
        unsafe { sys::SDL_ShowCursor(crate::sys::SDL_QUERY) == 1 }
    }

    #[doc(alias = "SDL_ShowCursor")]
    pub fn show_cursor(&self, show: bool) {
        unsafe {
            sys::SDL_ShowCursor(show as i32);
        }
    }

    #[doc(alias = "SDL_CaptureMouse")]
    pub fn capture(&self, enable: bool) {
        let enable = if enable {
            sys::SDL_bool::SDL_TRUE
        } else {
            sys::SDL_bool::SDL_FALSE
        };
        unsafe {
            sys::SDL_CaptureMouse(enable);
        }
    }
}
<|endoftext|>


<commit_before>use crate::types;

use super::auto::{HasInner, Abstract, Spawnable};
use super::container::AContainer;
use super::item_clickable::{ItemClickable, ItemClickableInner};
use super::adapted::{AAdapted, Adapted, AdaptedInner};
use super::control::{AControl, Control, ControlInner};
use super::member::{AMember, Member};
use super::adapter::Node;

define! {
    Tree: Control + Adapted + ItemClickable {
	    /*base: {
            pub on_item_click: Option<OnItemClick>,
        }*/
	    inner: {}
	    outer: {}
	    constructor: {
    	    fn with_adapter(adapter: Box<dyn types::Adapter>) -> Box<dyn Tree>;
	    }
	    extends: { ItemClickable }
    }
}

/*impl<T: TreeInner + 'static> ATree<T> {
    #[inline]
    pub fn with_inner(inner: T) -> Self {
        Self { base: TreeBase { on_item_click: None }, inner }
    }
}*/
impl<II: TreeInner, T: HasInner<I = II> + Abstract + 'static> TreeInner for T {
    #[inline]
    fn with_adapter(adapter: Box<dyn types::Adapter>) -> Box<dyn Tree> {
        <<Self as HasInner>::I as TreeInner>::with_adapter(adapter)
    }
}
impl<T: TreeInner> NewTree for AMember<AControl<AContainer<AAdapted<ATree<T>>>>> {
    #[inline]
    fn with_adapter(adapter: Box<dyn types::Adapter>) -> Box<dyn Tree> {
        T::with_adapter(adapter)
    }
}
// hello E0119
/*impl<T: TreeInner> ItemClickable for AMember<AControl<AContainer<AAdapted<ATree<T>>>>> {
    #[inline]
    fn on_item_click(&mut self, cb: Option<OnItemClick>) {
        self.inner.inner.inner.inner.base.on_item_click = cb;
    }
    #[inline]
    fn item_click(&mut self, arg: usize, item_view: &mut dyn Control, skip_callbacks: bool) {
        if !skip_callbacks{
            let self2 = self as *mut Self;
            if let Some(ref mut callback) = self.inner.inner.inner.inner.base.on_item_click {
                (callback.as_mut())(unsafe { &mut *self2 }, arg, item_view)
            }
        }
    }
    #[inline]
    fn as_item_clickable(&self) -> &dyn ItemClickable {
        self
    }
    #[inline]
    fn as_item_clickable_mut(&mut self) -> &mut dyn ItemClickable {
        self
    }
    #[inline]
    fn into_item_clickable(self: Box<Self>) -> Box<dyn ItemClickable> {
        self
    }
}*/

impl<T: TreeInner> Tree for AMember<AControl<AContainer<AAdapted<ATree<T>>>>> {
    #[inline]
    fn as_tree(&self) -> &dyn Tree {
        self
    }
    #[inline]
    fn as_tree_mut(&mut self) -> &mut dyn Tree {
        self
    }
    #[inline]
    fn into_tree(self: Box<Self>) -> Box<dyn Tree> {
        self
    }
}

impl<T: TreeInner> Spawnable for AMember<AControl<AContainer<AAdapted<ATree<T>>>>> {
    fn spawn() -> Box<dyn Control> {
        <T as Spawnable>::spawn()
    }
}

pub struct TreeNode<T: Sized> {
    pub expanded: bool,
    pub root: Box<dyn Control>,
    pub native: T,
    pub branches: Vec<Self>,
}

impl<T: Sized> TreeNode<T> {
	pub fn node(&self) -> Node {
		if self.branches.len() == 0 {
			Node::Leaf
		} else {
			Node::Branch(self.expanded)
		}
	}
}

impl<T: Sized, I: AsRef<[usize]>> std::ops::Index<I> for TreeNode<T> {
	type Output = Self;
	fn index(&self, index: I) -> &Self::Output {
		let mut i = 0;
		let index = index.as_ref();
		let mut ret = self;
		while i < index.len() {
			ret = &ret.branches[index[i]];
			i += 1;
		}
		ret
	}
}

impl<T: Sized, I: AsRef<[usize]>> std::ops::IndexMut<I> for TreeNode<T> {
	fn index_mut(&mut self, index: I) -> &mut Self::Output {
		let mut i = 0;
		let index = index.as_ref();
		let mut ret = self;
		while i < index.len() {
			ret = &mut ret.branches[index[i]];
			i += 1;
		}
		ret
	}
}

pub struct TreeNodeList<T: Sized> (pub Vec<TreeNode<T>>);

impl<T: Sized, I: AsRef<[usize]>> std::ops::Index<I> for TreeNodeList<T> {
	type Output = TreeNode<T>;
	fn index(&self, index: I) -> &Self::Output {
		let index = index.as_ref();
		if index.len() < 1 {
			panic!("Empty index!");
		}
		&self.0.as_slice()[index[0]][index[1..].as_ref()]
	}
}

impl<T: Sized, I: AsRef<[usize]>> std::ops::IndexMut<I> for TreeNodeList<T> {
	fn index_mut(&mut self, index: I) -> &mut Self::Output {
		let index = index.as_ref();
		if index.len() < 1 {
			panic!("Empty index!");
		}
		&mut self.0.as_mut_slice()[index[0]][index[1..].as_ref()]
	}
}

impl<T: Sized> std::ops::Deref for TreeNodeList<T> {
	type Target = [TreeNode<T>];
	fn deref(&self) -> &Self::Target {
		self.0.as_slice()
	}
}
impl<T: Sized> std::ops::DerefMut for TreeNodeList<T> {
	fn deref_mut(&mut self) -> &mut Self::Target {
		self.0.as_mut_slice()
	}
}
<commit_msg>Tree::default()<commit_after>use crate::types;

use super::auto::{HasInner, Abstract, Spawnable};
use super::container::AContainer;
use super::item_clickable::{ItemClickable, ItemClickableInner};
use super::adapted::{AAdapted, Adapted, AdaptedInner};
use super::control::{AControl, Control, ControlInner};
use super::member::{AMember, Member};
use super::adapter::Node;

define! {
    Tree: Control + Adapted + ItemClickable {
	    /*base: {
            pub on_item_click: Option<OnItemClick>,
        }*/
	    inner: {}
	    outer: {}
	    constructor: {
    	    fn with_adapter(adapter: Box<dyn types::Adapter>) -> Box<dyn Tree>;
	    }
	    extends: { ItemClickable }
    }
}

/*impl<T: TreeInner + 'static> ATree<T> {
    #[inline]
    pub fn with_inner(inner: T) -> Self {
        Self { base: TreeBase { on_item_click: None }, inner }
    }
}*/
impl<II: TreeInner, T: HasInner<I = II> + Abstract + 'static> TreeInner for T {
    #[inline]
    fn with_adapter(adapter: Box<dyn types::Adapter>) -> Box<dyn Tree> {
        <<Self as HasInner>::I as TreeInner>::with_adapter(adapter)
    }
}
impl<T: TreeInner> NewTree for AMember<AControl<AContainer<AAdapted<ATree<T>>>>> {
    #[inline]
    fn with_adapter(adapter: Box<dyn types::Adapter>) -> Box<dyn Tree> {
        T::with_adapter(adapter)
    }
}
// hello E0119
/*impl<T: TreeInner> ItemClickable for AMember<AControl<AContainer<AAdapted<ATree<T>>>>> {
    #[inline]
    fn on_item_click(&mut self, cb: Option<OnItemClick>) {
        self.inner.inner.inner.inner.base.on_item_click = cb;
    }
    #[inline]
    fn item_click(&mut self, arg: usize, item_view: &mut dyn Control, skip_callbacks: bool) {
        if !skip_callbacks{
            let self2 = self as *mut Self;
            if let Some(ref mut callback) = self.inner.inner.inner.inner.base.on_item_click {
                (callback.as_mut())(unsafe { &mut *self2 }, arg, item_view)
            }
        }
    }
    #[inline]
    fn as_item_clickable(&self) -> &dyn ItemClickable {
        self
    }
    #[inline]
    fn as_item_clickable_mut(&mut self) -> &mut dyn ItemClickable {
        self
    }
    #[inline]
    fn into_item_clickable(self: Box<Self>) -> Box<dyn ItemClickable> {
        self
    }
}*/

impl<T: TreeInner> Tree for AMember<AControl<AContainer<AAdapted<ATree<T>>>>> {
    #[inline]
    fn as_tree(&self) -> &dyn Tree {
        self
    }
    #[inline]
    fn as_tree_mut(&mut self) -> &mut dyn Tree {
        self
    }
    #[inline]
    fn into_tree(self: Box<Self>) -> Box<dyn Tree> {
        self
    }
}

impl<T: TreeInner> Spawnable for AMember<AControl<AContainer<AAdapted<ATree<T>>>>> {
    fn spawn() -> Box<dyn Control> {
        <T as Spawnable>::spawn()
    }
}

pub struct TreeNode<T: Sized> {
    pub expanded: bool,
    pub root: Box<dyn Control>,
    pub native: T,
    pub branches: Vec<Self>,
}

impl<T: Sized> TreeNode<T> {
	pub fn node(&self) -> Node {
		if self.branches.len() == 0 {
			Node::Leaf
		} else {
			Node::Branch(self.expanded)
		}
	}
}

impl<T: Sized, I: AsRef<[usize]>> std::ops::Index<I> for TreeNode<T> {
	type Output = Self;
	fn index(&self, index: I) -> &Self::Output {
		let mut i = 0;
		let index = index.as_ref();
		let mut ret = self;
		while i < index.len() {
			ret = &ret.branches[index[i]];
			i += 1;
		}
		ret
	}
}

impl<T: Sized, I: AsRef<[usize]>> std::ops::IndexMut<I> for TreeNode<T> {
	fn index_mut(&mut self, index: I) -> &mut Self::Output {
		let mut i = 0;
		let index = index.as_ref();
		let mut ret = self;
		while i < index.len() {
			ret = &mut ret.branches[index[i]];
			i += 1;
		}
		ret
	}
}

pub struct TreeNodeList<T: Sized> (pub Vec<TreeNode<T>>);

impl<T: Sized> std::default::Default for TreeNodeList<T> {
	fn default() -> Self {
		Self(Vec::new())
	}
}

impl<T: Sized, I: AsRef<[usize]>> std::ops::Index<I> for TreeNodeList<T> {
	type Output = TreeNode<T>;
	fn index(&self, index: I) -> &Self::Output {
		let index = index.as_ref();
		if index.len() < 1 {
			panic!("Empty index!");
		}
		&self.0.as_slice()[index[0]][index[1..].as_ref()]
	}
}

impl<T: Sized, I: AsRef<[usize]>> std::ops::IndexMut<I> for TreeNodeList<T> {
	fn index_mut(&mut self, index: I) -> &mut Self::Output {
		let index = index.as_ref();
		if index.len() < 1 {
			panic!("Empty index!");
		}
		&mut self.0.as_mut_slice()[index[0]][index[1..].as_ref()]
	}
}

impl<T: Sized> std::ops::Deref for TreeNodeList<T> {
	type Target = [TreeNode<T>];
	fn deref(&self) -> &Self::Target {
		self.0.as_slice()
	}
}
impl<T: Sized> std::ops::DerefMut for TreeNodeList<T> {
	fn deref_mut(&mut self) -> &mut Self::Target {
		self.0.as_mut_slice()
	}
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::path::{PathBuf};

use tera::{GlobalFn, Value, from_value, to_value, Result};

use content::{Page, Section};
use config::Config;
use utils::site::resolve_internal_link;

pub fn make_get_page(all_pages: &HashMap<PathBuf, Page>) -> GlobalFn {
    let mut pages = HashMap::new();
    for page in all_pages.values() {
        pages.insert(page.file.relative.clone(), page.clone());
    }

    Box::new(move |args| -> Result<Value> {
        match args.get("path") {
            Some(val) => match from_value::<String>(val.clone()) {
                Ok(v) => {
                    match pages.get(&v) {
                        Some(p) => Ok(to_value(p).unwrap()),
                        None => Err(format!("Page `{}` not found.", v).into())
                    }
                },
                Err(_) => Err(format!("`get_page` received path={:?} but it requires a string", val).into()),
            },
            None => Err("`get_page` requires a `path` argument.".into()),
        }
    })
}

pub fn make_get_section(all_sections: &HashMap<PathBuf, Section>) -> GlobalFn {
    let mut sections = HashMap::new();
    for section in all_sections.values() {
        sections.insert(section.file.relative.clone(), section.clone());
    }

    Box::new(move |args| -> Result<Value> {
        match args.get("path") {
            Some(val) => match from_value::<String>(val.clone()) {
                Ok(v) => {
                    match sections.get(&v) {
                        Some(p) => Ok(to_value(p).unwrap()),
                        None => Err(format!("Section `{}` not found.", v).into())
                    }
                },
                Err(_) => Err(format!("`get_section` received path={:?} but it requires a string", val).into()),
            },
            None => Err("`get_section` requires a `path` argument.".into()),
        }
    })
}

pub fn make_get_url(permalinks: HashMap<String, String>, config: Config) -> GlobalFn {
    Box::new(move |args| -> Result<Value> {
        let cachebust = args
            .get("cachebust")
            .map_or(false, |c| {
                from_value::<bool>(c.clone()).unwrap_or(false)
            });

        if args.contains_key("link") {
            println!("> DEPRECATION -- `link` is deprecated for `get_url`: use `path` instead");
        }

        match args.get("link").or_else(|| args.get("path")) {
            Some(val) => match from_value::<String>(val.clone()) {
                Ok(v) => {
                    // Internal link
                    if v.starts_with("./") {
                        match resolve_internal_link(&v, &permalinks) {
                            Ok(url) => Ok(to_value(url).unwrap()),
                            Err(_) => Err(format!("Could not resolve URL for link `{}` not found.", v).into())
                        }
                    } else {
                        // anything else
                        let mut permalink = config.make_permalink(&v);
                        if cachebust {
                            permalink = format!("{}?t={}", permalink, config.build_timestamp.unwrap());
                        }
                        Ok(to_value(permalink).unwrap())
                    }
                },
                Err(_) => Err(format!("`get_url` received path={:?} but it requires a string", val).into()),
            },
            None => Err("`get_url` requires a `path` argument.".into()),
        }
    })
}

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

    use std::collections::HashMap;

    use tera::to_value;

    use config::Config;

    #[test]
    fn can_add_cachebust_to_url() {
        let config = Config::default();
        let static_fn = make_get_url(HashMap::new(), config);
        let mut args = HashMap::new();
        args.insert("path".to_string(), to_value("app.css").unwrap());
        args.insert("cachebust".to_string(), to_value(true).unwrap());
        assert_eq!(static_fn(args).unwrap(), "http://a-website.com/app.css/?t=1");
    }

    #[test]
    fn can_link_to_some_static_file() {
        let config = Config::default();
        let static_fn = make_get_url(HashMap::new(), config);
        let mut args = HashMap::new();
        args.insert("path".to_string(), to_value("app.css").unwrap());
        assert_eq!(static_fn(args).unwrap(), "http://a-website.com/app.css/");
    }
}
<commit_msg>Remove deprecated link param of get_url<commit_after>use std::collections::HashMap;
use std::path::{PathBuf};

use tera::{GlobalFn, Value, from_value, to_value, Result};

use content::{Page, Section};
use config::Config;
use utils::site::resolve_internal_link;

pub fn make_get_page(all_pages: &HashMap<PathBuf, Page>) -> GlobalFn {
    let mut pages = HashMap::new();
    for page in all_pages.values() {
        pages.insert(page.file.relative.clone(), page.clone());
    }

    Box::new(move |args| -> Result<Value> {
        match args.get("path") {
            Some(val) => match from_value::<String>(val.clone()) {
                Ok(v) => {
                    match pages.get(&v) {
                        Some(p) => Ok(to_value(p).unwrap()),
                        None => Err(format!("Page `{}` not found.", v).into())
                    }
                },
                Err(_) => Err(format!("`get_page` received path={:?} but it requires a string", val).into()),
            },
            None => Err("`get_page` requires a `path` argument.".into()),
        }
    })
}

pub fn make_get_section(all_sections: &HashMap<PathBuf, Section>) -> GlobalFn {
    let mut sections = HashMap::new();
    for section in all_sections.values() {
        sections.insert(section.file.relative.clone(), section.clone());
    }

    Box::new(move |args| -> Result<Value> {
        match args.get("path") {
            Some(val) => match from_value::<String>(val.clone()) {
                Ok(v) => {
                    match sections.get(&v) {
                        Some(p) => Ok(to_value(p).unwrap()),
                        None => Err(format!("Section `{}` not found.", v).into())
                    }
                },
                Err(_) => Err(format!("`get_section` received path={:?} but it requires a string", val).into()),
            },
            None => Err("`get_section` requires a `path` argument.".into()),
        }
    })
}

pub fn make_get_url(permalinks: HashMap<String, String>, config: Config) -> GlobalFn {
    Box::new(move |args| -> Result<Value> {
        let cachebust = args
            .get("cachebust")
            .map_or(false, |c| {
                from_value::<bool>(c.clone()).unwrap_or(false)
            });

        match args.get("path") {
            Some(val) => match from_value::<String>(val.clone()) {
                Ok(v) => {
                    // Internal link
                    if v.starts_with("./") {
                        match resolve_internal_link(&v, &permalinks) {
                            Ok(url) => Ok(to_value(url).unwrap()),
                            Err(_) => Err(format!("Could not resolve URL for link `{}` not found.", v).into())
                        }
                    } else {
                        // anything else
                        let mut permalink = config.make_permalink(&v);
                        if cachebust {
                            permalink = format!("{}?t={}", permalink, config.build_timestamp.unwrap());
                        }
                        Ok(to_value(permalink).unwrap())
                    }
                },
                Err(_) => Err(format!("`get_url` received path={:?} but it requires a string", val).into()),
            },
            None => Err("`get_url` requires a `path` argument.".into()),
        }
    })
}

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

    use std::collections::HashMap;

    use tera::to_value;

    use config::Config;

    #[test]
    fn can_add_cachebust_to_url() {
        let config = Config::default();
        let static_fn = make_get_url(HashMap::new(), config);
        let mut args = HashMap::new();
        args.insert("path".to_string(), to_value("app.css").unwrap());
        args.insert("cachebust".to_string(), to_value(true).unwrap());
        assert_eq!(static_fn(args).unwrap(), "http://a-website.com/app.css/?t=1");
    }

    #[test]
    fn can_link_to_some_static_file() {
        let config = Config::default();
        let static_fn = make_get_url(HashMap::new(), config);
        let mut args = HashMap::new();
        args.insert("path".to_string(), to_value("app.css").unwrap());
        assert_eq!(static_fn(args).unwrap(), "http://a-website.com/app.css/");
    }
}
<|endoftext|>


<commit_before>//! Server Requests
//!
//! These are requests that a `hyper::Server` receives, and include its method,
//! target URI, headers, and message body.
use std::io::{self, Read};
use std::net::SocketAddr;

use buffer::BufReader;
use net::NetworkStream;
use version::{HttpVersion};
use method::Method::{self, Get, Head};
use header::{Headers, ContentLength, TransferEncoding};
use http::h1::{self, Incoming, HttpReader};
use http::h1::HttpReader::{SizedReader, ChunkedReader, EmptyReader};
use uri::RequestUri;

/// A request bundles several parts of an incoming `NetworkStream`, given to a `Handler`.
pub struct Request<'a, 'b: 'a> {
    /// The IP address of the remote connection.
    pub remote_addr: SocketAddr,
    /// The `Method`, such as `Get`, `Post`, etc.
    pub method: Method,
    /// The headers of the incoming request.
    pub headers: Headers,
    /// The target request-uri for this request.
    pub uri: RequestUri,
    /// The version of HTTP for this request.
    pub version: HttpVersion,
    body: HttpReader<&'a mut BufReader<&'b mut NetworkStream>>
}

impl<'a, 'b: 'a> Request<'a, 'b> {
    /// Create a new Request, reading the StartLine and Headers so they are
    /// immediately useful.
    pub fn new(mut stream: &'a mut BufReader<&'b mut NetworkStream>, addr: SocketAddr)
        -> ::Result<Request<'a, 'b>> {

        let Incoming { version, subject: (method, uri), headers } = try!(h1::parse_request(stream));
        debug!("Request Line: {:?} {:?} {:?}", method, uri, version);
        debug!("{:?}", headers);

        let body = if method == Get || method == Head {
            EmptyReader(stream)
        } else if headers.has::<ContentLength>() {
            match headers.get::<ContentLength>() {
                Some(&ContentLength(len)) => SizedReader(stream, len),
                None => unreachable!()
            }
        } else if headers.has::<TransferEncoding>() {
            todo!("check for Transfer-Encoding: chunked");
            ChunkedReader(stream, None)
        } else {
            EmptyReader(stream)
        };

        Ok(Request {
            remote_addr: addr,
            method: method,
            uri: uri,
            headers: headers,
            version: version,
            body: body
        })
    }

    /// Deconstruct a Request into its constituent parts.
    #[inline]
    pub fn deconstruct(self) -> (SocketAddr, Method, Headers,
                                 RequestUri, HttpVersion,
                                 HttpReader<&'a mut BufReader<&'b mut NetworkStream>>) {
        (self.remote_addr, self.method, self.headers,
         self.uri, self.version, self.body)
    }
}

impl<'a, 'b> Read for Request<'a, 'b> {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.body.read(buf)
    }
}

#[cfg(test)]
mod tests {
    use buffer::BufReader;
    use header::{Host, TransferEncoding, Encoding};
    use net::NetworkStream;
    use mock::MockStream;
    use super::Request;

    use std::io::{self, Read};
    use std::net::SocketAddr;

    fn sock(s: &str) -> SocketAddr {
        s.parse().unwrap()
    }

    fn read_to_string(mut req: Request) -> io::Result<String> {
        let mut s = String::new();
        try!(req.read_to_string(&mut s));
        Ok(s)
    }

    #[test]
    fn test_get_empty_body() {
        let mut mock = MockStream::with_input(b"\
            GET / HTTP/1.1\r\n\
            Host: example.domain\r\n\
            \r\n\
            I'm a bad request.\r\n\
        ");

        // FIXME: Use Type ascription
        let mock: &mut NetworkStream = &mut mock;
        let mut stream = BufReader::new(mock);

        let req = Request::new(&mut stream, sock("127.0.0.1:80")).unwrap();
        assert_eq!(read_to_string(req).unwrap(), "".to_owned());
    }

    #[test]
    fn test_head_empty_body() {
        let mut mock = MockStream::with_input(b"\
            HEAD / HTTP/1.1\r\n\
            Host: example.domain\r\n\
            \r\n\
            I'm a bad request.\r\n\
        ");

        // FIXME: Use Type ascription
        let mock: &mut NetworkStream = &mut mock;
        let mut stream = BufReader::new(mock);

        let req = Request::new(&mut stream, sock("127.0.0.1:80")).unwrap();
        assert_eq!(read_to_string(req).unwrap(), "".to_owned());
    }

    #[test]
    fn test_post_empty_body() {
        let mut mock = MockStream::with_input(b"\
            POST / HTTP/1.1\r\n\
            Host: example.domain\r\n\
            \r\n\
            I'm a bad request.\r\n\
        ");

        // FIXME: Use Type ascription
        let mock: &mut NetworkStream = &mut mock;
        let mut stream = BufReader::new(mock);

        let req = Request::new(&mut stream, sock("127.0.0.1:80")).unwrap();
        assert_eq!(read_to_string(req).unwrap(), "".to_owned());
    }

    #[test]
    fn test_parse_chunked_request() {
        let mut mock = MockStream::with_input(b"\
            POST / HTTP/1.1\r\n\
            Host: example.domain\r\n\
            Transfer-Encoding: chunked\r\n\
            \r\n\
            1\r\n\
            q\r\n\
            2\r\n\
            we\r\n\
            2\r\n\
            rt\r\n\
            0\r\n\
            \r\n"
        );

        // FIXME: Use Type ascription
        let mock: &mut NetworkStream = &mut mock;
        let mut stream = BufReader::new(mock);

        let req = Request::new(&mut stream, sock("127.0.0.1:80")).unwrap();

        // The headers are correct?
        match req.headers.get::<Host>() {
            Some(host) => {
                assert_eq!("example.domain", host.hostname);
            },
            None => panic!("Host header expected!"),
        };
        match req.headers.get::<TransferEncoding>() {
            Some(encodings) => {
                assert_eq!(1, encodings.len());
                assert_eq!(Encoding::Chunked, encodings[0]);
            }
            None => panic!("Transfer-Encoding: chunked expected!"),
        };
        // The content is correctly read?
        assert_eq!(read_to_string(req).unwrap(), "qwert".to_owned());
    }

    /// Tests that when a chunk size is not a valid radix-16 number, an error
    /// is returned.
    #[test]
    fn test_invalid_chunk_size_not_hex_digit() {
        let mut mock = MockStream::with_input(b"\
            POST / HTTP/1.1\r\n\
            Host: example.domain\r\n\
            Transfer-Encoding: chunked\r\n\
            \r\n\
            X\r\n\
            1\r\n\
            0\r\n\
            \r\n"
        );

        // FIXME: Use Type ascription
        let mock: &mut NetworkStream = &mut mock;
        let mut stream = BufReader::new(mock);

        let req = Request::new(&mut stream, sock("127.0.0.1:80")).unwrap();

        assert!(read_to_string(req).is_err());
    }

    /// Tests that when a chunk size contains an invalid extension, an error is
    /// returned.
    #[test]
    fn test_invalid_chunk_size_extension() {
        let mut mock = MockStream::with_input(b"\
            POST / HTTP/1.1\r\n\
            Host: example.domain\r\n\
            Transfer-Encoding: chunked\r\n\
            \r\n\
            1 this is an invalid extension\r\n\
            1\r\n\
            0\r\n\
            \r\n"
        );

        // FIXME: Use Type ascription
        let mock: &mut NetworkStream = &mut mock;
        let mut stream = BufReader::new(mock);

        let req = Request::new(&mut stream, sock("127.0.0.1:80")).unwrap();

        assert!(read_to_string(req).is_err());
    }

    /// Tests that when a valid extension that contains a digit is appended to
    /// the chunk size, the chunk is correctly read.
    #[test]
    fn test_chunk_size_with_extension() {
        let mut mock = MockStream::with_input(b"\
            POST / HTTP/1.1\r\n\
            Host: example.domain\r\n\
            Transfer-Encoding: chunked\r\n\
            \r\n\
            1;this is an extension with a digit 1\r\n\
            1\r\n\
            0\r\n\
            \r\n"
        );

        // FIXME: Use Type ascription
        let mock: &mut NetworkStream = &mut mock;
        let mut stream = BufReader::new(mock);

        let req = Request::new(&mut stream, sock("127.0.0.1:80")).unwrap();

        assert_eq!(read_to_string(req).unwrap(), "1".to_owned());
    }

}
<commit_msg>feat(server): add Request.ssl() to get underlying ssl stream<commit_after>//! Server Requests
//!
//! These are requests that a `hyper::Server` receives, and include its method,
//! target URI, headers, and message body.
use std::io::{self, Read};
use std::net::SocketAddr;

use buffer::BufReader;
use net::NetworkStream;
use version::{HttpVersion};
use method::Method::{self, Get, Head};
use header::{Headers, ContentLength, TransferEncoding};
use http::h1::{self, Incoming, HttpReader};
use http::h1::HttpReader::{SizedReader, ChunkedReader, EmptyReader};
use uri::RequestUri;

/// A request bundles several parts of an incoming `NetworkStream`, given to a `Handler`.
pub struct Request<'a, 'b: 'a> {
    /// The IP address of the remote connection.
    pub remote_addr: SocketAddr,
    /// The `Method`, such as `Get`, `Post`, etc.
    pub method: Method,
    /// The headers of the incoming request.
    pub headers: Headers,
    /// The target request-uri for this request.
    pub uri: RequestUri,
    /// The version of HTTP for this request.
    pub version: HttpVersion,
    body: HttpReader<&'a mut BufReader<&'b mut NetworkStream>>
}

impl<'a, 'b: 'a> Request<'a, 'b> {
    /// Create a new Request, reading the StartLine and Headers so they are
    /// immediately useful.
    pub fn new(mut stream: &'a mut BufReader<&'b mut NetworkStream>, addr: SocketAddr)
        -> ::Result<Request<'a, 'b>> {

        let Incoming { version, subject: (method, uri), headers } = try!(h1::parse_request(stream));
        debug!("Request Line: {:?} {:?} {:?}", method, uri, version);
        debug!("{:?}", headers);

        let body = if method == Get || method == Head {
            EmptyReader(stream)
        } else if headers.has::<ContentLength>() {
            match headers.get::<ContentLength>() {
                Some(&ContentLength(len)) => SizedReader(stream, len),
                None => unreachable!()
            }
        } else if headers.has::<TransferEncoding>() {
            todo!("check for Transfer-Encoding: chunked");
            ChunkedReader(stream, None)
        } else {
            EmptyReader(stream)
        };

        Ok(Request {
            remote_addr: addr,
            method: method,
            uri: uri,
            headers: headers,
            version: version,
            body: body
        })
    }

    /// Get a reference to the underlying `NetworkStream`.
    #[inline]
    pub fn downcast_ref<T: NetworkStream>(&self) -> Option<&T> {
        self.body.get_ref().get_ref().downcast_ref()
    }

    /// Get a reference to the underlying Ssl stream, if connected
    /// over HTTPS.
    ///
    /// # Example
    ///
    /// ```rust
    /// # extern crate hyper;
    /// # #[cfg(feature = "openssl")]
    /// extern crate openssl;
    /// # #[cfg(feature = "openssl")]
    /// use openssl::ssl::SslStream;
    /// # fn main() {}
    /// # #[cfg(feature = "openssl")]
    /// # fn doc_ssl(req: hyper::server::Request) {
    /// let maybe_ssl = req.ssl::<SslStream>();
    /// # }
    /// ```
    #[inline]
    pub fn ssl<T: NetworkStream>(&self) -> Option<&T> {
        use ::net::HttpsStream;
        match self.downcast_ref() {
            Some(&HttpsStream::Https(ref s)) => Some(s),
            _ => None
        }
    }

    /// Deconstruct a Request into its constituent parts.
    #[inline]
    pub fn deconstruct(self) -> (SocketAddr, Method, Headers,
                                 RequestUri, HttpVersion,
                                 HttpReader<&'a mut BufReader<&'b mut NetworkStream>>) {
        (self.remote_addr, self.method, self.headers,
         self.uri, self.version, self.body)
    }
}

impl<'a, 'b> Read for Request<'a, 'b> {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.body.read(buf)
    }
}

#[cfg(test)]
mod tests {
    use buffer::BufReader;
    use header::{Host, TransferEncoding, Encoding};
    use net::NetworkStream;
    use mock::MockStream;
    use super::Request;

    use std::io::{self, Read};
    use std::net::SocketAddr;

    fn sock(s: &str) -> SocketAddr {
        s.parse().unwrap()
    }

    fn read_to_string(mut req: Request) -> io::Result<String> {
        let mut s = String::new();
        try!(req.read_to_string(&mut s));
        Ok(s)
    }

    #[test]
    fn test_get_empty_body() {
        let mut mock = MockStream::with_input(b"\
            GET / HTTP/1.1\r\n\
            Host: example.domain\r\n\
            \r\n\
            I'm a bad request.\r\n\
        ");

        // FIXME: Use Type ascription
        let mock: &mut NetworkStream = &mut mock;
        let mut stream = BufReader::new(mock);

        let req = Request::new(&mut stream, sock("127.0.0.1:80")).unwrap();
        assert_eq!(read_to_string(req).unwrap(), "".to_owned());
    }

    #[test]
    fn test_head_empty_body() {
        let mut mock = MockStream::with_input(b"\
            HEAD / HTTP/1.1\r\n\
            Host: example.domain\r\n\
            \r\n\
            I'm a bad request.\r\n\
        ");

        // FIXME: Use Type ascription
        let mock: &mut NetworkStream = &mut mock;
        let mut stream = BufReader::new(mock);

        let req = Request::new(&mut stream, sock("127.0.0.1:80")).unwrap();
        assert_eq!(read_to_string(req).unwrap(), "".to_owned());
    }

    #[test]
    fn test_post_empty_body() {
        let mut mock = MockStream::with_input(b"\
            POST / HTTP/1.1\r\n\
            Host: example.domain\r\n\
            \r\n\
            I'm a bad request.\r\n\
        ");

        // FIXME: Use Type ascription
        let mock: &mut NetworkStream = &mut mock;
        let mut stream = BufReader::new(mock);

        let req = Request::new(&mut stream, sock("127.0.0.1:80")).unwrap();
        assert_eq!(read_to_string(req).unwrap(), "".to_owned());
    }

    #[test]
    fn test_parse_chunked_request() {
        let mut mock = MockStream::with_input(b"\
            POST / HTTP/1.1\r\n\
            Host: example.domain\r\n\
            Transfer-Encoding: chunked\r\n\
            \r\n\
            1\r\n\
            q\r\n\
            2\r\n\
            we\r\n\
            2\r\n\
            rt\r\n\
            0\r\n\
            \r\n"
        );

        // FIXME: Use Type ascription
        let mock: &mut NetworkStream = &mut mock;
        let mut stream = BufReader::new(mock);

        let req = Request::new(&mut stream, sock("127.0.0.1:80")).unwrap();

        // The headers are correct?
        match req.headers.get::<Host>() {
            Some(host) => {
                assert_eq!("example.domain", host.hostname);
            },
            None => panic!("Host header expected!"),
        };
        match req.headers.get::<TransferEncoding>() {
            Some(encodings) => {
                assert_eq!(1, encodings.len());
                assert_eq!(Encoding::Chunked, encodings[0]);
            }
            None => panic!("Transfer-Encoding: chunked expected!"),
        };
        // The content is correctly read?
        assert_eq!(read_to_string(req).unwrap(), "qwert".to_owned());
    }

    /// Tests that when a chunk size is not a valid radix-16 number, an error
    /// is returned.
    #[test]
    fn test_invalid_chunk_size_not_hex_digit() {
        let mut mock = MockStream::with_input(b"\
            POST / HTTP/1.1\r\n\
            Host: example.domain\r\n\
            Transfer-Encoding: chunked\r\n\
            \r\n\
            X\r\n\
            1\r\n\
            0\r\n\
            \r\n"
        );

        // FIXME: Use Type ascription
        let mock: &mut NetworkStream = &mut mock;
        let mut stream = BufReader::new(mock);

        let req = Request::new(&mut stream, sock("127.0.0.1:80")).unwrap();

        assert!(read_to_string(req).is_err());
    }

    /// Tests that when a chunk size contains an invalid extension, an error is
    /// returned.
    #[test]
    fn test_invalid_chunk_size_extension() {
        let mut mock = MockStream::with_input(b"\
            POST / HTTP/1.1\r\n\
            Host: example.domain\r\n\
            Transfer-Encoding: chunked\r\n\
            \r\n\
            1 this is an invalid extension\r\n\
            1\r\n\
            0\r\n\
            \r\n"
        );

        // FIXME: Use Type ascription
        let mock: &mut NetworkStream = &mut mock;
        let mut stream = BufReader::new(mock);

        let req = Request::new(&mut stream, sock("127.0.0.1:80")).unwrap();

        assert!(read_to_string(req).is_err());
    }

    /// Tests that when a valid extension that contains a digit is appended to
    /// the chunk size, the chunk is correctly read.
    #[test]
    fn test_chunk_size_with_extension() {
        let mut mock = MockStream::with_input(b"\
            POST / HTTP/1.1\r\n\
            Host: example.domain\r\n\
            Transfer-Encoding: chunked\r\n\
            \r\n\
            1;this is an extension with a digit 1\r\n\
            1\r\n\
            0\r\n\
            \r\n"
        );

        // FIXME: Use Type ascription
        let mock: &mut NetworkStream = &mut mock;
        let mut stream = BufReader::new(mock);

        let req = Request::new(&mut stream, sock("127.0.0.1:80")).unwrap();

        assert_eq!(read_to_string(req).unwrap(), "1".to_owned());
    }

}
<|endoftext|>


<commit_before>use std::path::{PathBuf, Path};
use std::fs;
use std::error::Error;
use std::fmt;

#[cfg(feature = "cache")]
use time::{self, Timespec};
#[cfg(feature = "cache")]
use std::time::Duration;

use iron::prelude::*;
use iron::{Handler, status};
#[cfg(feature = "cache")]
use iron::modifier::Modifier;
use iron::modifiers::Redirect;
use mount::OriginalUrl;
use requested_path::RequestedPath;

/// The static file-serving `Handler`.
///
/// This handler serves files from a single filesystem path, which may be absolute or relative.
/// Incoming requests are mapped onto the filesystem by appending their URL path to the handler's
/// root path. If the filesystem path corresponds to a regular file, the handler will attempt to
/// serve it. Otherwise, if the path corresponds to a directory containing an `index.html`,
/// the handler will attempt to serve that instead.
///
/// ## Errors
///
/// If the path doesn't match any real object in the filesystem, the handler will return
/// a Response with `status::NotFound`. If an IO error occurs whilst attempting to serve
/// a file, `FileError(IoError)` will be returned.
#[derive(Clone)]
pub struct Static {
    /// The path this handler is serving files from.
    pub root: PathBuf,
    #[cfg(feature = "cache")]
    cache: Option<Cache>,
}

impl Static {
    /// Create a new instance of `Static` with a given root path.
    ///
    /// If `Path::new("")` is given, files will be served from the current directory.
    #[cfg(feature = "cache")]
    pub fn new<P: AsRef<Path>>(root: P) -> Static {
        Static {
            root: root.as_ref().to_path_buf(),
            cache: None
        }
    }

    /// Create a new instance of `Static` with a given root path.
    ///
    /// If `Path::new("")` is given, files will be served from the current directory.
    #[cfg(not(feature = "cache"))]
    pub fn new<P: AsRef<Path>>(root: P) -> Static {
        Static {
            root: root.as_ref().to_path_buf(),
        }
    }

    /// Specify the response's `cache-control` header with a given duration. Internally, this is
    /// a helper function to set a `Cache` on an instance of `Static`.
    ///
    /// ## Example
    ///
    /// ```ignore
    /// let cached_static_handler = Static::new(path).cache(Duration::from_secs(30*24*60*60));
    /// ```
    #[cfg(feature = "cache")]
    pub fn cache(self, duration: Duration) -> Static {
        self.set(Cache::new(duration))
    }

    #[cfg(feature = "cache")]
    fn try_cache<P: AsRef<Path>>(&self, req: &mut Request, path: P) -> IronResult<Response> {
        match self.cache {
            None => Ok(Response::with((status::Ok, path.as_ref()))),
            Some(ref cache) => cache.handle(req, path.as_ref()),
        }
    }
}

impl Handler for Static {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        use std::io;

        let requested_path = RequestedPath::new(&self.root, req);

        let metadata = match fs::metadata(&requested_path.path) {
            Ok(meta) => meta,
            Err(e) => {
                let status = match e.kind() {
                    io::ErrorKind::NotFound => status::NotFound,
                    io::ErrorKind::PermissionDenied => status::Forbidden,
                    _ => status::InternalServerError,
                };

                return Err(IronError::new(e, status))
            },
        };

        // If the URL ends in a slash, serve the file directly.
        // Otherwise, redirect to the directory equivalent of the URL.
        if requested_path.should_redirect(&metadata, req) {
            // Perform an HTTP 301 Redirect.
            let mut redirect_path = match req.extensions.get::<OriginalUrl>() {
                None => &req.url,
                Some(original_url) => original_url,
            }.clone();

            // Append the trailing slash
            //
            // rust-url automatically turns an empty string in the last
            // slot in the path into a trailing slash.
            redirect_path.path.push("".to_string());

            return Ok(Response::with((status::MovedPermanently,
                                      format!("Redirecting to {}", redirect_path),
                                      Redirect(redirect_path))));
        }

        match requested_path.get_file(&metadata) {
            // If no file is found, return a 404 response.
            None => Err(IronError::new(NoFile, status::NotFound)),
            // Won't panic because we know the file exists from get_file.
            #[cfg(feature = "cache")]
            Some(path) => self.try_cache(req, path),
            #[cfg(not(feature = "cache"))]
            Some(path) => {
                let path: &Path = &path;
                Ok(Response::with((status::Ok, path)))
            },
        }
    }
}

impl Set for Static {}

/// A modifier for `Static` to specify a response's `cache-control`.
#[cfg(feature = "cache")]
#[derive(Clone)]
pub struct Cache {
    /// The length of time the file should be cached for.
    pub duration: Duration,
}

#[cfg(feature = "cache")]
impl Cache {
    /// Create a new instance of `Cache` with a given duration.
    pub fn new(duration: Duration) -> Cache {
        Cache { duration: duration }
    }

    fn handle<P: AsRef<Path>>(&self, req: &mut Request, path: P) -> IronResult<Response> {
        use iron::headers::{IfModifiedSince, HttpDate};

        let path = path.as_ref();

        let last_modified_time = match fs::metadata(path) {
            Err(error) => return Err(IronError::new(error, status::InternalServerError)),
            Ok(metadata) => {
                use filetime::FileTime;

                let time = FileTime::from_last_modification_time(&metadata);
                Timespec::new(time.seconds() as i64, time.nanoseconds() as i32)
            },
        };

        let if_modified_since = match req.headers.get::<IfModifiedSince>().cloned() {
            None => return Ok(self.response_with_cache(path, last_modified_time)),
            Some(IfModifiedSince(HttpDate(time))) => time.to_timespec(),
        };

        if last_modified_time <= if_modified_since {
            Ok(Response::with(status::NotModified))
        } else {
            Ok(self.response_with_cache(path, last_modified_time))
        }
    }

    fn response_with_cache<P: AsRef<Path>>(&self, path: P, modified: Timespec) -> Response {
        use iron::headers::{CacheControl, LastModified, CacheDirective, HttpDate};

        let mut response = Response::with((status::Ok, path.as_ref()));
        let seconds = self.duration.as_secs() as u32;
        let cache = vec![CacheDirective::Public, CacheDirective::MaxAge(seconds)];
        response.headers.set(CacheControl(cache));
        response.headers.set(LastModified(HttpDate(time::at(modified))));
        response
    }
}

#[cfg(feature = "cache")]
impl Modifier<Static> for Cache {
    fn modify(self, static_handler: &mut Static) {
        static_handler.cache = Some(self);
    }
}

/// Thrown if no file is found. It is always accompanied by a NotFound response.
#[derive(Debug)]
pub struct NoFile;

impl Error for NoFile {
    fn description(&self) -> &str { "File not found" }
}

impl fmt::Display for NoFile {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(self.description())
    }
}
<commit_msg>(fix) Return earlier if no cache header detected<commit_after>use std::path::{PathBuf, Path};
use std::fs;
use std::error::Error;
use std::fmt;

#[cfg(feature = "cache")]
use time::{self, Timespec};
#[cfg(feature = "cache")]
use std::time::Duration;

use iron::prelude::*;
use iron::{Handler, status};
#[cfg(feature = "cache")]
use iron::modifier::Modifier;
use iron::modifiers::Redirect;
use mount::OriginalUrl;
use requested_path::RequestedPath;

/// The static file-serving `Handler`.
///
/// This handler serves files from a single filesystem path, which may be absolute or relative.
/// Incoming requests are mapped onto the filesystem by appending their URL path to the handler's
/// root path. If the filesystem path corresponds to a regular file, the handler will attempt to
/// serve it. Otherwise, if the path corresponds to a directory containing an `index.html`,
/// the handler will attempt to serve that instead.
///
/// ## Errors
///
/// If the path doesn't match any real object in the filesystem, the handler will return
/// a Response with `status::NotFound`. If an IO error occurs whilst attempting to serve
/// a file, `FileError(IoError)` will be returned.
#[derive(Clone)]
pub struct Static {
    /// The path this handler is serving files from.
    pub root: PathBuf,
    #[cfg(feature = "cache")]
    cache: Option<Cache>,
}

impl Static {
    /// Create a new instance of `Static` with a given root path.
    ///
    /// If `Path::new("")` is given, files will be served from the current directory.
    #[cfg(feature = "cache")]
    pub fn new<P: AsRef<Path>>(root: P) -> Static {
        Static {
            root: root.as_ref().to_path_buf(),
            cache: None
        }
    }

    /// Create a new instance of `Static` with a given root path.
    ///
    /// If `Path::new("")` is given, files will be served from the current directory.
    #[cfg(not(feature = "cache"))]
    pub fn new<P: AsRef<Path>>(root: P) -> Static {
        Static {
            root: root.as_ref().to_path_buf(),
        }
    }

    /// Specify the response's `cache-control` header with a given duration. Internally, this is
    /// a helper function to set a `Cache` on an instance of `Static`.
    ///
    /// ## Example
    ///
    /// ```ignore
    /// let cached_static_handler = Static::new(path).cache(Duration::from_secs(30*24*60*60));
    /// ```
    #[cfg(feature = "cache")]
    pub fn cache(self, duration: Duration) -> Static {
        self.set(Cache::new(duration))
    }

    #[cfg(feature = "cache")]
    fn try_cache<P: AsRef<Path>>(&self, req: &mut Request, path: P) -> IronResult<Response> {
        match self.cache {
            None => Ok(Response::with((status::Ok, path.as_ref()))),
            Some(ref cache) => cache.handle(req, path.as_ref()),
        }
    }
}

impl Handler for Static {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        use std::io;

        let requested_path = RequestedPath::new(&self.root, req);

        let metadata = match fs::metadata(&requested_path.path) {
            Ok(meta) => meta,
            Err(e) => {
                let status = match e.kind() {
                    io::ErrorKind::NotFound => status::NotFound,
                    io::ErrorKind::PermissionDenied => status::Forbidden,
                    _ => status::InternalServerError,
                };

                return Err(IronError::new(e, status))
            },
        };

        // If the URL ends in a slash, serve the file directly.
        // Otherwise, redirect to the directory equivalent of the URL.
        if requested_path.should_redirect(&metadata, req) {
            // Perform an HTTP 301 Redirect.
            let mut redirect_path = match req.extensions.get::<OriginalUrl>() {
                None => &req.url,
                Some(original_url) => original_url,
            }.clone();

            // Append the trailing slash
            //
            // rust-url automatically turns an empty string in the last
            // slot in the path into a trailing slash.
            redirect_path.path.push("".to_string());

            return Ok(Response::with((status::MovedPermanently,
                                      format!("Redirecting to {}", redirect_path),
                                      Redirect(redirect_path))));
        }

        match requested_path.get_file(&metadata) {
            // If no file is found, return a 404 response.
            None => Err(IronError::new(NoFile, status::NotFound)),
            // Won't panic because we know the file exists from get_file.
            #[cfg(feature = "cache")]
            Some(path) => self.try_cache(req, path),
            #[cfg(not(feature = "cache"))]
            Some(path) => {
                let path: &Path = &path;
                Ok(Response::with((status::Ok, path)))
            },
        }
    }
}

impl Set for Static {}

/// A modifier for `Static` to specify a response's `cache-control`.
#[cfg(feature = "cache")]
#[derive(Clone)]
pub struct Cache {
    /// The length of time the file should be cached for.
    pub duration: Duration,
}

#[cfg(feature = "cache")]
impl Cache {
    /// Create a new instance of `Cache` with a given duration.
    pub fn new(duration: Duration) -> Cache {
        Cache { duration: duration }
    }

    fn handle<P: AsRef<Path>>(&self, req: &mut Request, path: P) -> IronResult<Response> {
        use iron::headers::{IfModifiedSince, HttpDate};

        let path = path.as_ref();

        let if_modified_since = match req.headers.get::<IfModifiedSince>().cloned() {
            None => return Ok(self.response_with_cache(path, last_modified_time)),
            Some(IfModifiedSince(HttpDate(time))) => time.to_timespec(),
        };

        let last_modified_time = match fs::metadata(path) {
            Err(error) => return Err(IronError::new(error, status::InternalServerError)),
            Ok(metadata) => {
                use filetime::FileTime;

                let time = FileTime::from_last_modification_time(&metadata);
                Timespec::new(time.seconds() as i64, time.nanoseconds() as i32)
            },
        };

        if last_modified_time <= if_modified_since {
            Ok(Response::with(status::NotModified))
        } else {
            Ok(self.response_with_cache(path, last_modified_time))
        }
    }

    fn response_with_cache<P: AsRef<Path>>(&self, path: P, modified: Timespec) -> Response {
        use iron::headers::{CacheControl, LastModified, CacheDirective, HttpDate};

        let mut response = Response::with((status::Ok, path.as_ref()));
        let seconds = self.duration.as_secs() as u32;
        let cache = vec![CacheDirective::Public, CacheDirective::MaxAge(seconds)];
        response.headers.set(CacheControl(cache));
        response.headers.set(LastModified(HttpDate(time::at(modified))));
        response
    }
}

#[cfg(feature = "cache")]
impl Modifier<Static> for Cache {
    fn modify(self, static_handler: &mut Static) {
        static_handler.cache = Some(self);
    }
}

/// Thrown if no file is found. It is always accompanied by a NotFound response.
#[derive(Debug)]
pub struct NoFile;

impl Error for NoFile {
    fn description(&self) -> &str { "File not found" }
}

impl fmt::Display for NoFile {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(self.description())
    }
}
<|endoftext|>


<commit_before>/// Maximum order of the fixed predictors permitted by the format.
pub const MAX_FIXED_ORDER: usize = 4;

/// Maximum LPC order permitted by the format.
pub const MAX_LPC_ORDER: usize   = 32;

/// A single channel of audio data.
pub struct Subframe {
  /// Data containing one of the four different types of subframes.
  pub data: Data,
  /// Number of wasted bits within each sample.
  pub wasted_bits: u32,
}

/// General enum that holds all the different subframe data types.
#[derive(Debug, PartialEq, Eq)]
pub enum Data {
  /// A single value that represents a constant subframe.
  Constant(i64),
  /// An uncompressed subframe.
  Verbatim(Vec<i64>),
  /// Fixed linear prediction subframe.
  Fixed(Fixed),
  /// FIR linear prediction subframe.
  LPC(LPC),
}

/// Fixed linear prediction subframe.
#[derive(Debug, PartialEq, Eq)]
pub struct Fixed {
  /// Residual coding method.
  pub entropy_coding_method: EntropyCodingMethod,
  /// Polynomial order.
  pub order: u8,
  /// Samples used to warm up, or prime, the predictor.
  pub warmup: [i64; MAX_FIXED_ORDER],
  /// Remaining samples after the warm up samples.
  pub residual: Vec<i64>,
}

/// Finite Impulse Response (FIR) linear prediction subframe.
#[derive(Debug, PartialEq, Eq)]
pub struct LPC {
  /// Residual coding method.
  pub entropy_coding_method: EntropyCodingMethod,
  /// FIR order.
  pub order: u8,
  /// Quantized FIR filter coefficient precision in bits.
  pub qlp_coeff_precision: u8,
  /// Quantized linear predictor coefficient shift needed in bits.
  pub quantization_level: i8,
  /// FIR filter coefficients.
  pub qlp_coefficients: [i64; MAX_LPC_ORDER],
  /// Samples used to warm up, or prime, the predictor.
  pub warmup: [i64; MAX_LPC_ORDER],
  /// Remaining samples after the warm up samples.
  pub residual: Vec<i64>,
}

/// Header for the entropy coding method.
#[derive(Debug, PartialEq, Eq)]
pub struct EntropyCodingMethod {
  /// The type of coding method being used.
  pub method_type: CodingMethod,
  /// Data for each entropy coding method partition.
  pub data: PartitionedRice,
}

/// The available entropy coding methods.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum CodingMethod {
  /// Coding partition with a 4-bit Rice parameter.
  PartitionedRice,
  /// Coding partition with a 5-bit Rice parameter.
  PartitionedRice2,
}

/// Header for a Rice partitioned residual.
#[derive(Debug, PartialEq, Eq)]
pub struct PartitionedRice {
  /// Partition order.
  pub order: u32,
  /// Rice parameters and/or raw bits.
  pub contents: PartitionedRiceContents,
}

/// Contents of a Rice partitioned residual.
#[derive(Debug, PartialEq, Eq)]
pub struct PartitionedRiceContents {
  /// Size of `parameters` and `raw_bits` within the data buffer.
  pub capacity: usize,
  /// Data buffer containing both `parameters` and `raw_bits`.
  pub data: Vec<u32>,
}

impl PartitionedRiceContents {
  pub fn new(capacity: usize) -> PartitionedRiceContents {
    let full_capacity = capacity * 2;
    let mut data      = Vec::with_capacity(full_capacity);

    unsafe { data.set_len(full_capacity) }

    PartitionedRiceContents {
      capacity: capacity,
      data: data,
    }
  }

  /// Rice parameters for each context.
  #[inline]
  pub fn parameters(&mut self) -> &mut [u32] {
    &mut self.data[0..self.capacity]
  }

  /// Widths for escaped-coded partitions.
  #[inline]
  pub fn raw_bits(&mut self) -> &mut [u32] {
    &mut self.data[self.capacity..]
  }
}
<commit_msg>Change a few types back to i32<commit_after>/// Maximum order of the fixed predictors permitted by the format.
pub const MAX_FIXED_ORDER: usize = 4;

/// Maximum LPC order permitted by the format.
pub const MAX_LPC_ORDER: usize   = 32;

/// A single channel of audio data.
pub struct Subframe {
  /// Data containing one of the four different types of subframes.
  pub data: Data,
  /// Number of wasted bits within each sample.
  pub wasted_bits: u32,
}

/// General enum that holds all the different subframe data types.
#[derive(Debug, PartialEq, Eq)]
pub enum Data {
  /// A single value that represents a constant subframe.
  Constant(i32),
  /// An uncompressed subframe.
  Verbatim(Vec<i32>),
  /// Fixed linear prediction subframe.
  Fixed(Fixed),
  /// FIR linear prediction subframe.
  LPC(LPC),
}

/// Fixed linear prediction subframe.
#[derive(Debug, PartialEq, Eq)]
pub struct Fixed {
  /// Residual coding method.
  pub entropy_coding_method: EntropyCodingMethod,
  /// Polynomial order.
  pub order: u8,
  /// Samples used to warm up, or prime, the predictor.
  pub warmup: [i32; MAX_FIXED_ORDER],
  /// Remaining samples after the warm up samples.
  pub residual: Vec<i32>,
}

/// Finite Impulse Response (FIR) linear prediction subframe.
#[derive(Debug, PartialEq, Eq)]
pub struct LPC {
  /// Residual coding method.
  pub entropy_coding_method: EntropyCodingMethod,
  /// FIR order.
  pub order: u8,
  /// Quantized FIR filter coefficient precision in bits.
  pub qlp_coeff_precision: u8,
  /// Quantized linear predictor coefficient shift needed in bits.
  pub quantization_level: i8,
  /// FIR filter coefficients.
  pub qlp_coefficients: [i32; MAX_LPC_ORDER],
  /// Samples used to warm up, or prime, the predictor.
  pub warmup: [i32; MAX_LPC_ORDER],
  /// Remaining samples after the warm up samples.
  pub residual: Vec<i32>,
}

/// Header for the entropy coding method.
#[derive(Debug, PartialEq, Eq)]
pub struct EntropyCodingMethod {
  /// The type of coding method being used.
  pub method_type: CodingMethod,
  /// Data for each entropy coding method partition.
  pub data: PartitionedRice,
}

/// The available entropy coding methods.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum CodingMethod {
  /// Coding partition with a 4-bit Rice parameter.
  PartitionedRice,
  /// Coding partition with a 5-bit Rice parameter.
  PartitionedRice2,
}

/// Header for a Rice partitioned residual.
#[derive(Debug, PartialEq, Eq)]
pub struct PartitionedRice {
  /// Partition order.
  pub order: u32,
  /// Rice parameters and/or raw bits.
  pub contents: PartitionedRiceContents,
}

/// Contents of a Rice partitioned residual.
#[derive(Debug, PartialEq, Eq)]
pub struct PartitionedRiceContents {
  /// Size of `parameters` and `raw_bits` within the data buffer.
  pub capacity: usize,
  /// Data buffer containing both `parameters` and `raw_bits`.
  pub data: Vec<u32>,
}

impl PartitionedRiceContents {
  pub fn new(capacity: usize) -> PartitionedRiceContents {
    let full_capacity = capacity * 2;
    let mut data      = Vec::with_capacity(full_capacity);

    unsafe { data.set_len(full_capacity) }

    PartitionedRiceContents {
      capacity: capacity,
      data: data,
    }
  }

  /// Rice parameters for each context.
  #[inline]
  pub fn parameters(&mut self) -> &mut [u32] {
    &mut self.data[0..self.capacity]
  }

  /// Widths for escaped-coded partitions.
  #[inline]
  pub fn raw_bits(&mut self) -> &mut [u32] {
    &mut self.data[self.capacity..]
  }
}
<|endoftext|>


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

//! Implementation for WASM via wasm-bindgen
extern crate std;

use core::cell::RefCell;
use core::mem;
use std::thread_local;

use wasm_bindgen::prelude::*;

use crate::error::{BINDGEN_CRYPTO_UNDEF, BINDGEN_GRV_UNDEF};
use crate::Error;

#[derive(Clone, Debug)]
enum RngSource {
    Node(NodeCrypto),
    Browser(BrowserCrypto),
}

// JsValues are always per-thread, so we initialize RngSource for each thread.
//   See: https://github.com/rustwasm/wasm-bindgen/pull/955
thread_local!(
    static RNG_SOURCE: RefCell<Option<RngSource>> = RefCell::new(None);
);

pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
    assert_eq!(mem::size_of::<usize>(), 4);

    RNG_SOURCE.with(|f| {
        let mut source = f.borrow_mut();
        if source.is_none() {
            *source = Some(getrandom_init()?);
        }

        match source.as_ref().unwrap() {
            RngSource::Node(n) => n.random_fill_sync(dest),
            RngSource::Browser(n) => {
                // see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues
                //
                // where it says:
                //
                // > A QuotaExceededError DOMException is thrown if the
                // > requested length is greater than 65536 bytes.
                for chunk in dest.chunks_mut(65536) {
                    n.get_random_values(chunk)
                }
            }
        };
        Ok(())
    })
}

fn getrandom_init() -> Result<RngSource, Error> {
    // First up we need to detect if we're running in node.js or a
    // browser. To do this we get ahold of the `this` object (in a bit
    // of a roundabout fashion).
    //
    // Once we have `this` we look at its `self` property, which is
    // only defined on the web (either a main window or web worker).
    let this = Function::new("return this").call(&JsValue::undefined());
    assert!(this != JsValue::undefined());
    let this = This::from(this);
    let is_browser = this.self_() != JsValue::undefined();

    if !is_browser {
        return Ok(RngSource::Node(node_require("crypto")));
    }

    // If `self` is defined then we're in a browser somehow (main window
    // or web worker). Here we want to try to use
    // `crypto.getRandomValues`, but if `crypto` isn't defined we assume
    // we're in an older web browser and the OS RNG isn't available.
    let crypto = this.crypto();
    if crypto.is_undefined() {
        return Err(BINDGEN_CRYPTO_UNDEF);
    }

    // Test if `crypto.getRandomValues` is undefined as well
    let crypto: BrowserCrypto = crypto.into();
    if crypto.get_random_values_fn().is_undefined() {
        return Err(BINDGEN_GRV_UNDEF);
    }

    // Ok! `self.crypto.getRandomValues` is a defined value, so let's
    // assume we can do browser crypto.
    Ok(RngSource::Browser(crypto))
}

#[wasm_bindgen]
extern "C" {
    type Function;
    #[wasm_bindgen(constructor)]
    fn new(s: &str) -> Function;
    #[wasm_bindgen(method)]
    fn call(this: &Function, self_: &JsValue) -> JsValue;

    type This;
    #[wasm_bindgen(method, getter, structural, js_name = self)]
    fn self_(me: &This) -> JsValue;
    #[wasm_bindgen(method, getter, structural)]
    fn crypto(me: &This) -> JsValue;

    #[derive(Clone, Debug)]
    type BrowserCrypto;

    // TODO: these `structural` annotations here ideally wouldn't be here to
    // avoid a JS shim, but for now with feature detection they're
    // unavoidable.
    #[wasm_bindgen(method, js_name = getRandomValues, structural, getter)]
    fn get_random_values_fn(me: &BrowserCrypto) -> JsValue;
    #[wasm_bindgen(method, js_name = getRandomValues, structural)]
    fn get_random_values(me: &BrowserCrypto, buf: &mut [u8]);

    #[wasm_bindgen(js_name = require)]
    fn node_require(s: &str) -> NodeCrypto;

    #[derive(Clone, Debug)]
    type NodeCrypto;

    #[wasm_bindgen(method, js_name = randomFillSync, structural)]
    fn random_fill_sync(me: &NodeCrypto, buf: &mut [u8]);
}
<commit_msg>Fix CSP error for wasm bindgen (#92)<commit_after>// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Implementation for WASM via wasm-bindgen
extern crate std;

use core::cell::RefCell;
use core::mem;
use std::thread_local;

use wasm_bindgen::prelude::*;

use crate::error::{BINDGEN_CRYPTO_UNDEF, BINDGEN_GRV_UNDEF};
use crate::Error;

#[derive(Clone, Debug)]
enum RngSource {
    Node(NodeCrypto),
    Browser(BrowserCrypto),
}

// JsValues are always per-thread, so we initialize RngSource for each thread.
//   See: https://github.com/rustwasm/wasm-bindgen/pull/955
thread_local!(
    static RNG_SOURCE: RefCell<Option<RngSource>> = RefCell::new(None);
);

pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
    assert_eq!(mem::size_of::<usize>(), 4);

    RNG_SOURCE.with(|f| {
        let mut source = f.borrow_mut();
        if source.is_none() {
            *source = Some(getrandom_init()?);
        }

        match source.as_ref().unwrap() {
            RngSource::Node(n) => n.random_fill_sync(dest),
            RngSource::Browser(n) => {
                // see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues
                //
                // where it says:
                //
                // > A QuotaExceededError DOMException is thrown if the
                // > requested length is greater than 65536 bytes.
                for chunk in dest.chunks_mut(65536) {
                    n.get_random_values(chunk)
                }
            }
        };
        Ok(())
    })
}

fn getrandom_init() -> Result<RngSource, Error> {
    if let Ok(self_) = Global::get_self() {
        // If `self` is defined then we're in a browser somehow (main window
        // or web worker). Here we want to try to use
        // `crypto.getRandomValues`, but if `crypto` isn't defined we assume
        // we're in an older web browser and the OS RNG isn't available.

        let crypto = self_.crypto();
        if crypto.is_undefined() {
            return Err(BINDGEN_CRYPTO_UNDEF);
        }

        // Test if `crypto.getRandomValues` is undefined as well
        let crypto: BrowserCrypto = crypto.into();
        if crypto.get_random_values_fn().is_undefined() {
            return Err(BINDGEN_GRV_UNDEF);
        }

        return Ok(RngSource::Browser(crypto));
    }

    return Ok(RngSource::Node(node_require("crypto")));
}

#[wasm_bindgen]
extern "C" {
    type Global;
    #[wasm_bindgen(getter, catch, static_method_of = Global, js_class = self, js_name = self)]
    fn get_self() -> Result<Self_, JsValue>;

    type Self_;
    #[wasm_bindgen(method, getter, structural)]
    fn crypto(me: &Self_) -> JsValue;

    #[derive(Clone, Debug)]
    type BrowserCrypto;

    // TODO: these `structural` annotations here ideally wouldn't be here to
    // avoid a JS shim, but for now with feature detection they're
    // unavoidable.
    #[wasm_bindgen(method, js_name = getRandomValues, structural, getter)]
    fn get_random_values_fn(me: &BrowserCrypto) -> JsValue;
    #[wasm_bindgen(method, js_name = getRandomValues, structural)]
    fn get_random_values(me: &BrowserCrypto, buf: &mut [u8]);

    #[wasm_bindgen(js_name = require)]
    fn node_require(s: &str) -> NodeCrypto;

    #[derive(Clone, Debug)]
    type NodeCrypto;

    #[wasm_bindgen(method, js_name = randomFillSync, structural)]
    fn random_fill_sync(me: &NodeCrypto, buf: &mut [u8]);
}
<|endoftext|>


<commit_before>///! Process syscalls

use core::mem;
use core::str;

use arch;
use arch::paging::{VirtualAddress, entry};
use context;
use elf;
use syscall::{self, Error, Result};

pub fn brk(address: usize) -> Result<usize> {
    let contexts = context::contexts();
    let context_lock = contexts.current().ok_or(Error::NoProcess)?;
    let mut context = context_lock.write();

    let mut current = arch::USER_HEAP_OFFSET;
    if let Some(ref heap) = context.heap {
        current = heap.start_address().get() + heap.size();
    }
    if address == 0 {
        //println!("Brk query {:X}", current);
        Ok(current)
    } else if address >= arch::USER_HEAP_OFFSET {
        //TODO: out of memory errors
        if let Some(ref mut heap) = context.heap {
            heap.resize(address - arch::USER_HEAP_OFFSET, true, true);
            return Ok(address);
        }

        context.heap = Some(context::memory::Memory::new(
            VirtualAddress::new(arch::USER_HEAP_OFFSET),
            address - arch::USER_HEAP_OFFSET,
            entry::WRITABLE | entry::NO_EXECUTE | entry::USER_ACCESSIBLE,
            true,
            true
        ));

        Ok(address)
    } else {
        //TODO: Return correct error
        Err(Error::NotPermitted)
    }
}

pub fn clone(flags: usize, stack_base: usize) -> Result<usize> {
    println!("Clone {:X}: {:X}", flags, stack_base);

    let arch;
    let mut stack_option = None;
    let mut offset = 0;

    // Copy from old process
    {
        let contexts = context::contexts();
        let context_lock = contexts.current().ok_or(Error::NoProcess)?;
        let context = context_lock.read();
        arch = context.arch.clone();
        if let Some(ref stack) = context.kstack {
            offset = stack_base - stack.as_ptr() as usize - mem::size_of::<usize>(); // Add clone ret
            let mut new_stack = stack.clone();
            unsafe {
                let func_ptr = new_stack.as_mut_ptr().offset(offset as isize);
                *(func_ptr as *mut usize) = arch::interrupt::syscall::clone_ret as usize;
            }
            stack_option = Some(new_stack);
        }
    }

    // Set up new process
    let pid;
    {
        let mut contexts = context::contexts_mut();
        let context_lock = contexts.new_context()?;
        let mut context = context_lock.write();
        context.arch = arch;
        if let Some(stack) = stack_option.take() {
            context.arch.set_stack(stack.as_ptr() as usize + offset);
            context.kstack = Some(stack);
        }
        context.blocked = false;
        pid = context.id;
    }

    println!("Clone {}", pid);

    unsafe { asm!("xchg bx, bx" : : : : "intel", "volatile"); }

    unsafe { context::switch(); }

    Ok(pid)
}

pub fn exit(status: usize) -> ! {
    println!("Exit {}", status);

    {
        let contexts = context::contexts();
        let context_lock = contexts.current().expect("tried to exit without context");
        let mut context = context_lock.write();
        context.image.clear();
        drop(context.heap.take());
        drop(context.stack.take());
        context.exited = true;
    }

    unsafe { context::switch(); }

    unreachable!();
}

pub fn exec(path: &[u8], _args: &[[usize; 2]]) -> Result<usize> {
    //TODO: Use args
    //TODO: Unmap previous mappings
    //TODO: Drop data vec
    println!("Exec {}", unsafe { str::from_utf8_unchecked(path) });

    let file = syscall::open(path, 0)?;
    let mut data = vec![];
    loop {
        let mut buf = [0; 4096];
        let count = syscall::read(file, &mut buf)?;
        if count > 0 {
            data.extend_from_slice(&buf[..count]);
        } else {
            break;
        }
    }
    let _ = syscall::close(file);

    match elf::Elf::from(&data) {
        Ok(elf) => elf.run().and(Ok(0)),
        Err(err) => {
            println!("failed to execute {}: {}", unsafe { str::from_utf8_unchecked(path) }, err);
            Err(Error::NoExec)
        }
    }
}

pub fn getpid() -> Result<usize> {
    let contexts = context::contexts();
    let context_lock = contexts.current().ok_or(Error::NoProcess)?;
    let context = context_lock.read();
    Ok(context.id)
}

pub fn iopl(_level: usize) -> Result<usize> {
    //TODO
    Ok(0)
}

pub fn sched_yield() -> Result<usize> {
    unsafe { context::switch(); }
    Ok(0)
}
<commit_msg>Fix userspace clone by clobbering all variables on clone<commit_after>///! Process syscalls

use core::mem;
use core::str;

use arch;
use arch::paging::{VirtualAddress, entry};
use context;
use elf;
use syscall::{self, Error, Result};

pub fn brk(address: usize) -> Result<usize> {
    let contexts = context::contexts();
    let context_lock = contexts.current().ok_or(Error::NoProcess)?;
    let mut context = context_lock.write();

    let mut current = arch::USER_HEAP_OFFSET;
    if let Some(ref heap) = context.heap {
        current = heap.start_address().get() + heap.size();
    }
    if address == 0 {
        //println!("Brk query {:X}", current);
        Ok(current)
    } else if address >= arch::USER_HEAP_OFFSET {
        //TODO: out of memory errors
        if let Some(ref mut heap) = context.heap {
            heap.resize(address - arch::USER_HEAP_OFFSET, true, true);
            return Ok(address);
        }

        context.heap = Some(context::memory::Memory::new(
            VirtualAddress::new(arch::USER_HEAP_OFFSET),
            address - arch::USER_HEAP_OFFSET,
            entry::WRITABLE | entry::NO_EXECUTE | entry::USER_ACCESSIBLE,
            true,
            true
        ));

        Ok(address)
    } else {
        //TODO: Return correct error
        Err(Error::NotPermitted)
    }
}

pub fn clone(flags: usize, stack_base: usize) -> Result<usize> {
    println!("Clone {:X}: {:X}", flags, stack_base);

    let arch;
    let mut stack_option = None;
    let mut offset = 0;

    // Copy from old process
    {
        let contexts = context::contexts();
        let context_lock = contexts.current().ok_or(Error::NoProcess)?;
        let context = context_lock.read();
        arch = context.arch.clone();
        if let Some(ref stack) = context.kstack {
            offset = stack_base - stack.as_ptr() as usize - mem::size_of::<usize>(); // Add clone ret
            let mut new_stack = stack.clone();
            unsafe {
                let func_ptr = new_stack.as_mut_ptr().offset(offset as isize);
                *(func_ptr as *mut usize) = arch::interrupt::syscall::clone_ret as usize;
            }
            stack_option = Some(new_stack);
        }
    }

    // Set up new process
    let pid;
    {
        let mut contexts = context::contexts_mut();
        let context_lock = contexts.new_context()?;
        let mut context = context_lock.write();
        context.arch = arch;
        if let Some(stack) = stack_option.take() {
            context.arch.set_stack(stack.as_ptr() as usize + offset);
            context.kstack = Some(stack);
        }
        context.blocked = false;
        pid = context.id;
    }

    unsafe { context::switch(); }

    Ok(pid)
}

pub fn exit(status: usize) -> ! {
    println!("Exit {}", status);

    {
        let contexts = context::contexts();
        let context_lock = contexts.current().expect("tried to exit without context");
        let mut context = context_lock.write();
        context.image.clear();
        drop(context.heap.take());
        drop(context.stack.take());
        context.exited = true;
    }

    unsafe { context::switch(); }

    unreachable!();
}

pub fn exec(path: &[u8], _args: &[[usize; 2]]) -> Result<usize> {
    //TODO: Use args
    //TODO: Unmap previous mappings
    //TODO: Drop data vec
    println!("Exec {}", unsafe { str::from_utf8_unchecked(path) });

    let file = syscall::open(path, 0)?;
    let mut data = vec![];
    loop {
        let mut buf = [0; 4096];
        let count = syscall::read(file, &mut buf)?;
        if count > 0 {
            data.extend_from_slice(&buf[..count]);
        } else {
            break;
        }
    }
    let _ = syscall::close(file);

    match elf::Elf::from(&data) {
        Ok(elf) => elf.run().and(Ok(0)),
        Err(err) => {
            println!("failed to execute {}: {}", unsafe { str::from_utf8_unchecked(path) }, err);
            Err(Error::NoExec)
        }
    }
}

pub fn getpid() -> Result<usize> {
    let contexts = context::contexts();
    let context_lock = contexts.current().ok_or(Error::NoProcess)?;
    let context = context_lock.read();
    Ok(context.id)
}

pub fn iopl(_level: usize) -> Result<usize> {
    //TODO
    Ok(0)
}

pub fn sched_yield() -> Result<usize> {
    unsafe { context::switch(); }
    Ok(0)
}
<|endoftext|>