<commit_before>use libc::c_char;
use std::ffi::{CString, CStr, NulError};
use std::path::Path;
use rwops::RWops;

use GameControllerSubsystem;
use get_error;
use joystick;
use common::{validate_int, IntegerOrSdlError};

use sys::controller as ll;
use sys::event::{SDL_QUERY, SDL_ENABLE};

#[derive(Debug)]
pub enum AddMappingError {
    InvalidMapping(NulError),
    InvalidFilePath(String),
    SdlError(String),
}

impl GameControllerSubsystem {
    /// Retreive the total number of attached joysticks *and* controllers identified by SDL.
    pub fn num_joysticks(&self) -> Result<u32, String> {
        let result = unsafe { ::sys::joystick::SDL_NumJoysticks() };

        if result >= 0 {
            Ok(result as u32)
        } else {
            Err(get_error())
        }
    }

    /// Return true if the joystick at index `id` is a game controller.
    #[inline]
    pub fn is_game_controller(&self, id: u32) -> bool {
        match validate_int(id, "id") {
            Ok(id) => unsafe { ll::SDL_IsGameController(id) != 0 },
            Err(_) => false
        }
    }

    /// Attempt to open the controller number `id` and return
    /// it. Controller IDs are the same as joystick IDs and the
    /// maximum number can be retreived using the `SDL_NumJoysticks`
    /// function.
    pub fn open(&self, id: u32) -> Result<GameController, IntegerOrSdlError> {
        use common::IntegerOrSdlError::*;
        let id = try!(validate_int(id, "id"));
        let controller = unsafe { ll::SDL_GameControllerOpen(id) };

        if controller.is_null() {
            Err(SdlError(get_error()))
        } else {
            Ok(GameController {
                subsystem: self.clone(),
                raw: controller
            })
        }
    }

    /// Return the name of the controller at the given index.
    pub fn name_for_index(&self, index: u32) -> Result<String, IntegerOrSdlError> {
        use common::IntegerOrSdlError::*;
        let index = try!(validate_int(index, "index"));
        let c_str = unsafe { ll::SDL_GameControllerNameForIndex(index) };

        if c_str.is_null() {
            Err(SdlError(get_error()))
        } else {
            Ok(unsafe {
                CStr::from_ptr(c_str as *const _).to_str().unwrap().to_owned()
            })
        }
    }

    /// If state is `true` controller events are processed, otherwise
    /// they're ignored.
    pub fn set_event_state(&self, state: bool) {
        unsafe { ll::SDL_GameControllerEventState(state as i32) };
    }

    /// Return `true` if controller events are processed.
    pub fn event_state(&self) -> bool {
        unsafe { ll::SDL_GameControllerEventState(SDL_QUERY as i32)
                 == SDL_ENABLE as i32 }
    }

    /// Add a new mapping from a mapping string
    pub fn add_mapping(&self, mapping: &str)
            -> Result<MappingStatus, AddMappingError> {
        use self::AddMappingError::*;
        let mapping = match CString::new(mapping) {
            Ok(s) => s,
            Err(err) => return Err(InvalidMapping(err)),
        };

        let result = unsafe { ll::SDL_GameControllerAddMapping(mapping.as_ptr() as *const c_char) };

        match result {
            1 => Ok(MappingStatus::Added),
            0 => Ok(MappingStatus::Updated),
            _ => Err(SdlError(get_error())),
        }
    }

    /// Load mappings from a file
    pub fn load_mappings<P: AsRef<Path>>(&self, path: P)
            -> Result<i32, AddMappingError> {
        use self::AddMappingError::*;

        let file = match RWops::from_file(path, "r") {
            Ok(f) => f,
            Err(s) => return Err(InvalidFilePath(s))
        };

        let result = unsafe { ll::SDL_GameControllerAddMappingsFromRW(file.raw(), 0) };

        match result {
            -1 => Err(SdlError(get_error())),
            _ => Ok(result)
        }
    }

    pub fn mapping_for_guid(&self, guid: joystick::Guid) -> Result<String, String> {
        let c_str = unsafe { ll::SDL_GameControllerMappingForGUID(guid.raw()) };

        c_str_to_string_or_err(c_str)
    }

    #[inline]
    /// Force controller update when not using the event loop
    pub fn update(&self) {
        unsafe { ll::SDL_GameControllerUpdate() };
    }
}

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[repr(i32)]
pub enum Axis {
    LeftX        = ll::SDL_CONTROLLER_AXIS_LEFTX,
    LeftY        = ll::SDL_CONTROLLER_AXIS_LEFTY,
    RightX       = ll::SDL_CONTROLLER_AXIS_RIGHTX,
    RightY       = ll::SDL_CONTROLLER_AXIS_RIGHTY,
    TriggerLeft  = ll::SDL_CONTROLLER_AXIS_TRIGGERLEFT,
    TriggerRight = ll::SDL_CONTROLLER_AXIS_TRIGGERRIGHT,
}

impl Axis {
    /// Return the Axis from a string description in the same format
    /// used by the game controller mapping strings.
    pub fn from_string(axis: &str) -> Option<Axis> {
        let id = match CString::new(axis) {
            Ok(axis) => unsafe { ll::SDL_GameControllerGetAxisFromString(axis.as_ptr() as *const c_char) },
            // string contains a nul byte - it won't match anything.
            Err(_) => ll::SDL_CONTROLLER_AXIS_INVALID
        };

        Axis::from_ll(id)
    }

    /// Return a string for a given axis in the same format using by
    /// the game controller mapping strings
    pub fn string(self) -> String {
        let axis = self as ll::SDL_GameControllerAxis;

        let string = unsafe { ll::SDL_GameControllerGetStringForAxis(axis) };

        c_str_to_string(string)
    }

    pub fn from_ll(bitflags: ll::SDL_GameControllerAxis) -> Option<Axis> {
        Some(match bitflags {
            ll::SDL_CONTROLLER_AXIS_INVALID      => return None,
            ll::SDL_CONTROLLER_AXIS_LEFTX        => Axis::LeftX,
            ll::SDL_CONTROLLER_AXIS_LEFTY        => Axis::LeftY,
            ll::SDL_CONTROLLER_AXIS_RIGHTX       => Axis::RightX,
            ll::SDL_CONTROLLER_AXIS_RIGHTY       => Axis::RightY,
            ll::SDL_CONTROLLER_AXIS_TRIGGERLEFT  => Axis::TriggerLeft,
            ll::SDL_CONTROLLER_AXIS_TRIGGERRIGHT => Axis::TriggerRight,
            _ => panic!("unhandled controller axis")
        })
    }

    pub fn to_ll(&self) -> ll::SDL_GameControllerAxis {
        match *self {
            Axis::LeftX => ll::SDL_CONTROLLER_AXIS_LEFTX,
            Axis::LeftY => ll::SDL_CONTROLLER_AXIS_LEFTY,
            Axis::RightX => ll::SDL_CONTROLLER_AXIS_RIGHTX,
            Axis::RightY => ll::SDL_CONTROLLER_AXIS_RIGHTY,
            Axis::TriggerLeft => ll::SDL_CONTROLLER_AXIS_TRIGGERLEFT,
            Axis::TriggerRight => ll::SDL_CONTROLLER_AXIS_TRIGGERRIGHT,
        }
    }
}

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[repr(i32)]
pub enum Button {
    A             = ll::SDL_CONTROLLER_BUTTON_A,
    B             = ll::SDL_CONTROLLER_BUTTON_B,
    X             = ll::SDL_CONTROLLER_BUTTON_X,
    Y             = ll::SDL_CONTROLLER_BUTTON_Y,
    Back          = ll::SDL_CONTROLLER_BUTTON_BACK,
    Guide         = ll::SDL_CONTROLLER_BUTTON_GUIDE,
    Start         = ll::SDL_CONTROLLER_BUTTON_START,
    LeftStick     = ll::SDL_CONTROLLER_BUTTON_LEFTSTICK,
    RightStick    = ll::SDL_CONTROLLER_BUTTON_RIGHTSTICK,
    LeftShoulder  = ll::SDL_CONTROLLER_BUTTON_LEFTSHOULDER,
    RightShoulder = ll::SDL_CONTROLLER_BUTTON_RIGHTSHOULDER,
    DPadUp        = ll::SDL_CONTROLLER_BUTTON_DPAD_UP,
    DPadDown      = ll::SDL_CONTROLLER_BUTTON_DPAD_DOWN,
    DPadLeft      = ll::SDL_CONTROLLER_BUTTON_DPAD_LEFT,
    DPadRight     = ll::SDL_CONTROLLER_BUTTON_DPAD_RIGHT,
}

impl Button {
    /// Return the Button from a string description in the same format
    /// used by the game controller mapping strings.
    pub fn from_string(button: &str) -> Option<Button> {
        let id = match CString::new(button) {
            Ok(button) => unsafe { ll::SDL_GameControllerGetButtonFromString(button.as_ptr() as *const c_char) },
            // string contains a nul byte - it won't match anything.
            Err(_) => ll::SDL_CONTROLLER_BUTTON_INVALID
        };

        Button::from_ll(id)
    }

    /// Return a string for a given button in the same format using by
    /// the game controller mapping strings
    pub fn string(self) -> String {
        let button = self as ll::SDL_GameControllerButton;

        let string = unsafe { ll::SDL_GameControllerGetStringForButton(button) };

        c_str_to_string(string)
    }

    pub fn from_ll(bitflags: ll::SDL_GameControllerButton) -> Option<Button> {
        Some(match bitflags {
            ll::SDL_CONTROLLER_BUTTON_INVALID       => return None,
            ll::SDL_CONTROLLER_BUTTON_A             => Button::A,
            ll::SDL_CONTROLLER_BUTTON_B             => Button::B,
            ll::SDL_CONTROLLER_BUTTON_X             => Button::X,
            ll::SDL_CONTROLLER_BUTTON_Y             => Button::Y,
            ll::SDL_CONTROLLER_BUTTON_BACK          => Button::Back,
            ll::SDL_CONTROLLER_BUTTON_GUIDE         => Button::Guide,
            ll::SDL_CONTROLLER_BUTTON_START         => Button::Start,
            ll::SDL_CONTROLLER_BUTTON_LEFTSTICK     => Button::LeftStick,
            ll::SDL_CONTROLLER_BUTTON_RIGHTSTICK    => Button::RightStick,
            ll::SDL_CONTROLLER_BUTTON_LEFTSHOULDER  => Button::LeftShoulder,
            ll::SDL_CONTROLLER_BUTTON_RIGHTSHOULDER => Button::RightShoulder,
            ll::SDL_CONTROLLER_BUTTON_DPAD_UP       => Button::DPadUp,
            ll::SDL_CONTROLLER_BUTTON_DPAD_DOWN     => Button::DPadDown,
            ll::SDL_CONTROLLER_BUTTON_DPAD_LEFT     => Button::DPadLeft,
            ll::SDL_CONTROLLER_BUTTON_DPAD_RIGHT    => Button::DPadRight,
            _ => panic!("unhandled controller button")
        })
    }

    pub fn to_ll(&self) -> ll::SDL_GameControllerButton {
        match *self {
            Button::A             => ll::SDL_CONTROLLER_BUTTON_A,
            Button::B             => ll::SDL_CONTROLLER_BUTTON_B,
            Button::X             => ll::SDL_CONTROLLER_BUTTON_X,
            Button::Y             => ll::SDL_CONTROLLER_BUTTON_Y,
            Button::Back          => ll::SDL_CONTROLLER_BUTTON_BACK,
            Button::Guide         => ll::SDL_CONTROLLER_BUTTON_GUIDE,
            Button::Start         => ll::SDL_CONTROLLER_BUTTON_START,
            Button::LeftStick     => ll::SDL_CONTROLLER_BUTTON_LEFTSTICK,
            Button::RightStick    => ll::SDL_CONTROLLER_BUTTON_RIGHTSTICK,
            Button::LeftShoulder  => ll::SDL_CONTROLLER_BUTTON_LEFTSHOULDER,
            Button::RightShoulder => ll::SDL_CONTROLLER_BUTTON_RIGHTSHOULDER,
            Button::DPadUp        => ll::SDL_CONTROLLER_BUTTON_DPAD_UP,
            Button::DPadDown      => ll::SDL_CONTROLLER_BUTTON_DPAD_DOWN,
            Button::DPadLeft      => ll::SDL_CONTROLLER_BUTTON_DPAD_LEFT,
            Button::DPadRight     => ll::SDL_CONTROLLER_BUTTON_DPAD_RIGHT,
        }
    }
}

/// Possible return values for `add_mapping`
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum MappingStatus {
    Added   = 1,
    Updated = 0,
}

/// Wrapper around the SDL_GameController object
pub struct GameController {
    subsystem: GameControllerSubsystem,
    raw: *mut ll::SDL_GameController
}

impl GameController {
    #[inline]
    pub fn subsystem(&self) -> &GameControllerSubsystem { &self.subsystem }

    /// Return the name of the controller or an empty string if no
    /// name is found.
    pub fn name(&self) -> String {
        let name = unsafe { ll::SDL_GameControllerName(self.raw) };

        c_str_to_string(name)
    }

    /// Return a String describing the controller's button and axis
    /// mappings
    pub fn mapping(&self) -> String {
        let mapping = unsafe { ll::SDL_GameControllerMapping(self.raw) };

        c_str_to_string(mapping)
    }

    /// Return true if the controller has been opened and currently
    /// connected.
    pub fn attached(&self) -> bool {
        unsafe { ll::SDL_GameControllerGetAttached(self.raw) != 0 }
    }

    /// Return the joystick id of this controller
    pub fn instance_id(&self) -> i32 {
        let result = unsafe {
          let joystick = ll::SDL_GameControllerGetJoystick(self.raw);
          ::sys::joystick::SDL_JoystickInstanceID(joystick)
        };

        if result < 0 {
            // Should only fail if the joystick is NULL.
            panic!(get_error())
        } else {
            result
        }
    }

    /// Get the position of the given `axis`
    pub fn axis(&self, axis: Axis) -> i16 {
        // This interface is a bit messed up: 0 is a valid position
        // but can also mean that an error occured.
        // Fortunately, an error can only occur if the controller pointer is NULL.
        // There should be no apparent reason for this to change in the future.

        let axis = axis as ll::SDL_GameControllerAxis;

        unsafe { ll::SDL_GameControllerGetAxis(self.raw, axis) }
    }

    /// Returns `true` if `button` is pressed.
    pub fn button(&self, button: Button) -> bool {
        // This interface is a bit messed up: 0 is a valid position
        // but can also mean that an error occured.
        // Fortunately, an error can only occur if the controller pointer is NULL.
        // There should be no apparent reason for this to change in the future.

        let button = button as ll::SDL_GameControllerButton;

        unsafe { ll::SDL_GameControllerGetButton(self.raw, button) != 0 }
    }
}

impl Drop for GameController {
    fn drop(&mut self) {
        unsafe { ll::SDL_GameControllerClose(self.raw) }
    }
}

/// Convert C string `c_str` to a String. Return an empty string if
/// c_str is NULL.
fn c_str_to_string(c_str: *const c_char) -> String {
    if c_str.is_null() {
        String::new()
    } else {
        unsafe {
            CStr::from_ptr(c_str as *const _).to_str().unwrap().to_owned()
        }
    }
}

/// Convert C string `c_str` to a String. Return an SDL error if
/// `c_str` is NULL.
fn c_str_to_string_or_err(c_str: *const c_char) -> Result<String, String> {
    if c_str.is_null() {
        Err(get_error())
    } else {
        Ok(unsafe {
            CStr::from_ptr(c_str as *const _).to_str().unwrap().to_owned()
        })
    }
}
<commit_msg>Implement Display for AddMappingError.<commit_after>use libc::c_char;
use std::ffi::{CString, CStr, NulError};
use std::fmt;
use std::path::Path;
use rwops::RWops;

use GameControllerSubsystem;
use get_error;
use joystick;
use common::{validate_int, IntegerOrSdlError};

use sys::controller as ll;
use sys::event::{SDL_QUERY, SDL_ENABLE};

#[derive(Debug)]
pub enum AddMappingError {
    InvalidMapping(NulError),
    InvalidFilePath(String),
    SdlError(String),
}

impl fmt::Display for AddMappingError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::AddMappingError::*;

        match *self {
            InvalidMapping(ref e) => write!(f, "Null error: {}", e),
            InvalidFilePath(ref value) => write!(f, "Invalid file path ({})", value),
            SdlError(ref e) => write!(f, "SDL error: {}", e)
        }
    }
}

impl GameControllerSubsystem {
    /// Retreive the total number of attached joysticks *and* controllers identified by SDL.
    pub fn num_joysticks(&self) -> Result<u32, String> {
        let result = unsafe { ::sys::joystick::SDL_NumJoysticks() };

        if result >= 0 {
            Ok(result as u32)
        } else {
            Err(get_error())
        }
    }

    /// Return true if the joystick at index `id` is a game controller.
    #[inline]
    pub fn is_game_controller(&self, id: u32) -> bool {
        match validate_int(id, "id") {
            Ok(id) => unsafe { ll::SDL_IsGameController(id) != 0 },
            Err(_) => false
        }
    }

    /// Attempt to open the controller number `id` and return
    /// it. Controller IDs are the same as joystick IDs and the
    /// maximum number can be retreived using the `SDL_NumJoysticks`
    /// function.
    pub fn open(&self, id: u32) -> Result<GameController, IntegerOrSdlError> {
        use common::IntegerOrSdlError::*;
        let id = try!(validate_int(id, "id"));
        let controller = unsafe { ll::SDL_GameControllerOpen(id) };

        if controller.is_null() {
            Err(SdlError(get_error()))
        } else {
            Ok(GameController {
                subsystem: self.clone(),
                raw: controller
            })
        }
    }

    /// Return the name of the controller at the given index.
    pub fn name_for_index(&self, index: u32) -> Result<String, IntegerOrSdlError> {
        use common::IntegerOrSdlError::*;
        let index = try!(validate_int(index, "index"));
        let c_str = unsafe { ll::SDL_GameControllerNameForIndex(index) };

        if c_str.is_null() {
            Err(SdlError(get_error()))
        } else {
            Ok(unsafe {
                CStr::from_ptr(c_str as *const _).to_str().unwrap().to_owned()
            })
        }
    }

    /// If state is `true` controller events are processed, otherwise
    /// they're ignored.
    pub fn set_event_state(&self, state: bool) {
        unsafe { ll::SDL_GameControllerEventState(state as i32) };
    }

    /// Return `true` if controller events are processed.
    pub fn event_state(&self) -> bool {
        unsafe { ll::SDL_GameControllerEventState(SDL_QUERY as i32)
                 == SDL_ENABLE as i32 }
    }

    /// Add a new mapping from a mapping string
    pub fn add_mapping(&self, mapping: &str)
            -> Result<MappingStatus, AddMappingError> {
        use self::AddMappingError::*;
        let mapping = match CString::new(mapping) {
            Ok(s) => s,
            Err(err) => return Err(InvalidMapping(err)),
        };

        let result = unsafe { ll::SDL_GameControllerAddMapping(mapping.as_ptr() as *const c_char) };

        match result {
            1 => Ok(MappingStatus::Added),
            0 => Ok(MappingStatus::Updated),
            _ => Err(SdlError(get_error())),
        }
    }

    /// Load mappings from a file
    pub fn load_mappings<P: AsRef<Path>>(&self, path: P)
            -> Result<i32, AddMappingError> {
        use self::AddMappingError::*;

        let file = match RWops::from_file(path, "r") {
            Ok(f) => f,
            Err(s) => return Err(InvalidFilePath(s))
        };

        let result = unsafe { ll::SDL_GameControllerAddMappingsFromRW(file.raw(), 0) };

        match result {
            -1 => Err(SdlError(get_error())),
            _ => Ok(result)
        }
    }

    pub fn mapping_for_guid(&self, guid: joystick::Guid) -> Result<String, String> {
        let c_str = unsafe { ll::SDL_GameControllerMappingForGUID(guid.raw()) };

        c_str_to_string_or_err(c_str)
    }

    #[inline]
    /// Force controller update when not using the event loop
    pub fn update(&self) {
        unsafe { ll::SDL_GameControllerUpdate() };
    }
}

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[repr(i32)]
pub enum Axis {
    LeftX        = ll::SDL_CONTROLLER_AXIS_LEFTX,
    LeftY        = ll::SDL_CONTROLLER_AXIS_LEFTY,
    RightX       = ll::SDL_CONTROLLER_AXIS_RIGHTX,
    RightY       = ll::SDL_CONTROLLER_AXIS_RIGHTY,
    TriggerLeft  = ll::SDL_CONTROLLER_AXIS_TRIGGERLEFT,
    TriggerRight = ll::SDL_CONTROLLER_AXIS_TRIGGERRIGHT,
}

impl Axis {
    /// Return the Axis from a string description in the same format
    /// used by the game controller mapping strings.
    pub fn from_string(axis: &str) -> Option<Axis> {
        let id = match CString::new(axis) {
            Ok(axis) => unsafe { ll::SDL_GameControllerGetAxisFromString(axis.as_ptr() as *const c_char) },
            // string contains a nul byte - it won't match anything.
            Err(_) => ll::SDL_CONTROLLER_AXIS_INVALID
        };

        Axis::from_ll(id)
    }

    /// Return a string for a given axis in the same format using by
    /// the game controller mapping strings
    pub fn string(self) -> String {
        let axis = self as ll::SDL_GameControllerAxis;

        let string = unsafe { ll::SDL_GameControllerGetStringForAxis(axis) };

        c_str_to_string(string)
    }

    pub fn from_ll(bitflags: ll::SDL_GameControllerAxis) -> Option<Axis> {
        Some(match bitflags {
            ll::SDL_CONTROLLER_AXIS_INVALID      => return None,
            ll::SDL_CONTROLLER_AXIS_LEFTX        => Axis::LeftX,
            ll::SDL_CONTROLLER_AXIS_LEFTY        => Axis::LeftY,
            ll::SDL_CONTROLLER_AXIS_RIGHTX       => Axis::RightX,
            ll::SDL_CONTROLLER_AXIS_RIGHTY       => Axis::RightY,
            ll::SDL_CONTROLLER_AXIS_TRIGGERLEFT  => Axis::TriggerLeft,
            ll::SDL_CONTROLLER_AXIS_TRIGGERRIGHT => Axis::TriggerRight,
            _ => panic!("unhandled controller axis")
        })
    }

    pub fn to_ll(&self) -> ll::SDL_GameControllerAxis {
        match *self {
            Axis::LeftX => ll::SDL_CONTROLLER_AXIS_LEFTX,
            Axis::LeftY => ll::SDL_CONTROLLER_AXIS_LEFTY,
            Axis::RightX => ll::SDL_CONTROLLER_AXIS_RIGHTX,
            Axis::RightY => ll::SDL_CONTROLLER_AXIS_RIGHTY,
            Axis::TriggerLeft => ll::SDL_CONTROLLER_AXIS_TRIGGERLEFT,
            Axis::TriggerRight => ll::SDL_CONTROLLER_AXIS_TRIGGERRIGHT,
        }
    }
}

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[repr(i32)]
pub enum Button {
    A             = ll::SDL_CONTROLLER_BUTTON_A,
    B             = ll::SDL_CONTROLLER_BUTTON_B,
    X             = ll::SDL_CONTROLLER_BUTTON_X,
    Y             = ll::SDL_CONTROLLER_BUTTON_Y,
    Back          = ll::SDL_CONTROLLER_BUTTON_BACK,
    Guide         = ll::SDL_CONTROLLER_BUTTON_GUIDE,
    Start         = ll::SDL_CONTROLLER_BUTTON_START,
    LeftStick     = ll::SDL_CONTROLLER_BUTTON_LEFTSTICK,
    RightStick    = ll::SDL_CONTROLLER_BUTTON_RIGHTSTICK,
    LeftShoulder  = ll::SDL_CONTROLLER_BUTTON_LEFTSHOULDER,
    RightShoulder = ll::SDL_CONTROLLER_BUTTON_RIGHTSHOULDER,
    DPadUp        = ll::SDL_CONTROLLER_BUTTON_DPAD_UP,
    DPadDown      = ll::SDL_CONTROLLER_BUTTON_DPAD_DOWN,
    DPadLeft      = ll::SDL_CONTROLLER_BUTTON_DPAD_LEFT,
    DPadRight     = ll::SDL_CONTROLLER_BUTTON_DPAD_RIGHT,
}

impl Button {
    /// Return the Button from a string description in the same format
    /// used by the game controller mapping strings.
    pub fn from_string(button: &str) -> Option<Button> {
        let id = match CString::new(button) {
            Ok(button) => unsafe { ll::SDL_GameControllerGetButtonFromString(button.as_ptr() as *const c_char) },
            // string contains a nul byte - it won't match anything.
            Err(_) => ll::SDL_CONTROLLER_BUTTON_INVALID
        };

        Button::from_ll(id)
    }

    /// Return a string for a given button in the same format using by
    /// the game controller mapping strings
    pub fn string(self) -> String {
        let button = self as ll::SDL_GameControllerButton;

        let string = unsafe { ll::SDL_GameControllerGetStringForButton(button) };

        c_str_to_string(string)
    }

    pub fn from_ll(bitflags: ll::SDL_GameControllerButton) -> Option<Button> {
        Some(match bitflags {
            ll::SDL_CONTROLLER_BUTTON_INVALID       => return None,
            ll::SDL_CONTROLLER_BUTTON_A             => Button::A,
            ll::SDL_CONTROLLER_BUTTON_B             => Button::B,
            ll::SDL_CONTROLLER_BUTTON_X             => Button::X,
            ll::SDL_CONTROLLER_BUTTON_Y             => Button::Y,
            ll::SDL_CONTROLLER_BUTTON_BACK          => Button::Back,
            ll::SDL_CONTROLLER_BUTTON_GUIDE         => Button::Guide,
            ll::SDL_CONTROLLER_BUTTON_START         => Button::Start,
            ll::SDL_CONTROLLER_BUTTON_LEFTSTICK     => Button::LeftStick,
            ll::SDL_CONTROLLER_BUTTON_RIGHTSTICK    => Button::RightStick,
            ll::SDL_CONTROLLER_BUTTON_LEFTSHOULDER  => Button::LeftShoulder,
            ll::SDL_CONTROLLER_BUTTON_RIGHTSHOULDER => Button::RightShoulder,
            ll::SDL_CONTROLLER_BUTTON_DPAD_UP       => Button::DPadUp,
            ll::SDL_CONTROLLER_BUTTON_DPAD_DOWN     => Button::DPadDown,
            ll::SDL_CONTROLLER_BUTTON_DPAD_LEFT     => Button::DPadLeft,
            ll::SDL_CONTROLLER_BUTTON_DPAD_RIGHT    => Button::DPadRight,
            _ => panic!("unhandled controller button")
        })
    }

    pub fn to_ll(&self) -> ll::SDL_GameControllerButton {
        match *self {
            Button::A             => ll::SDL_CONTROLLER_BUTTON_A,
            Button::B             => ll::SDL_CONTROLLER_BUTTON_B,
            Button::X             => ll::SDL_CONTROLLER_BUTTON_X,
            Button::Y             => ll::SDL_CONTROLLER_BUTTON_Y,
            Button::Back          => ll::SDL_CONTROLLER_BUTTON_BACK,
            Button::Guide         => ll::SDL_CONTROLLER_BUTTON_GUIDE,
            Button::Start         => ll::SDL_CONTROLLER_BUTTON_START,
            Button::LeftStick     => ll::SDL_CONTROLLER_BUTTON_LEFTSTICK,
            Button::RightStick    => ll::SDL_CONTROLLER_BUTTON_RIGHTSTICK,
            Button::LeftShoulder  => ll::SDL_CONTROLLER_BUTTON_LEFTSHOULDER,
            Button::RightShoulder => ll::SDL_CONTROLLER_BUTTON_RIGHTSHOULDER,
            Button::DPadUp        => ll::SDL_CONTROLLER_BUTTON_DPAD_UP,
            Button::DPadDown      => ll::SDL_CONTROLLER_BUTTON_DPAD_DOWN,
            Button::DPadLeft      => ll::SDL_CONTROLLER_BUTTON_DPAD_LEFT,
            Button::DPadRight     => ll::SDL_CONTROLLER_BUTTON_DPAD_RIGHT,
        }
    }
}

/// Possible return values for `add_mapping`
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum MappingStatus {
    Added   = 1,
    Updated = 0,
}

/// Wrapper around the SDL_GameController object
pub struct GameController {
    subsystem: GameControllerSubsystem,
    raw: *mut ll::SDL_GameController
}

impl GameController {
    #[inline]
    pub fn subsystem(&self) -> &GameControllerSubsystem { &self.subsystem }

    /// Return the name of the controller or an empty string if no
    /// name is found.
    pub fn name(&self) -> String {
        let name = unsafe { ll::SDL_GameControllerName(self.raw) };

        c_str_to_string(name)
    }

    /// Return a String describing the controller's button and axis
    /// mappings
    pub fn mapping(&self) -> String {
        let mapping = unsafe { ll::SDL_GameControllerMapping(self.raw) };

        c_str_to_string(mapping)
    }

    /// Return true if the controller has been opened and currently
    /// connected.
    pub fn attached(&self) -> bool {
        unsafe { ll::SDL_GameControllerGetAttached(self.raw) != 0 }
    }

    /// Return the joystick id of this controller
    pub fn instance_id(&self) -> i32 {
        let result = unsafe {
          let joystick = ll::SDL_GameControllerGetJoystick(self.raw);
          ::sys::joystick::SDL_JoystickInstanceID(joystick)
        };

        if result < 0 {
            // Should only fail if the joystick is NULL.
            panic!(get_error())
        } else {
            result
        }
    }

    /// Get the position of the given `axis`
    pub fn axis(&self, axis: Axis) -> i16 {
        // This interface is a bit messed up: 0 is a valid position
        // but can also mean that an error occured.
        // Fortunately, an error can only occur if the controller pointer is NULL.
        // There should be no apparent reason for this to change in the future.

        let axis = axis as ll::SDL_GameControllerAxis;

        unsafe { ll::SDL_GameControllerGetAxis(self.raw, axis) }
    }

    /// Returns `true` if `button` is pressed.
    pub fn button(&self, button: Button) -> bool {
        // This interface is a bit messed up: 0 is a valid position
        // but can also mean that an error occured.
        // Fortunately, an error can only occur if the controller pointer is NULL.
        // There should be no apparent reason for this to change in the future.

        let button = button as ll::SDL_GameControllerButton;

        unsafe { ll::SDL_GameControllerGetButton(self.raw, button) != 0 }
    }
}

impl Drop for GameController {
    fn drop(&mut self) {
        unsafe { ll::SDL_GameControllerClose(self.raw) }
    }
}

/// Convert C string `c_str` to a String. Return an empty string if
/// c_str is NULL.
fn c_str_to_string(c_str: *const c_char) -> String {
    if c_str.is_null() {
        String::new()
    } else {
        unsafe {
            CStr::from_ptr(c_str as *const _).to_str().unwrap().to_owned()
        }
    }
}

/// Convert C string `c_str` to a String. Return an SDL error if
/// `c_str` is NULL.
fn c_str_to_string_or_err(c_str: *const c_char) -> Result<String, String> {
    if c_str.is_null() {
        Err(get_error())
    } else {
        Ok(unsafe {
            CStr::from_ptr(c_str as *const _).to_str().unwrap().to_owned()
        })
    }
}
<|endoftext|>


<commit_before>extern crate surfviz;
#[macro_use]
extern crate glium;
extern crate isosurface;
extern crate ndarray;

use ndarray::Array;
use isosurface::marching_tetrahedra;
use glium::glutin;

use surfviz::surface;
use surfviz::camera;

fn main() {
    let res = 10;
    let xs = Array::linspace(-0.5, 0.5, res);
    let ys = Array::linspace(-0.5, 0.5, res);
    let zs = Array::linspace(-0.5, 0.5, res);

    let dim = (xs.len(), ys.len(), zs.len());

    let u = {
        let mut u = Array::from_elem(dim, 0.);

        let r = 0.3;
        for ((i, j, k), u) in u.indexed_iter_mut() {
            let (x, y, z) = (xs[i], ys[j], zs[k]);
            *u = x * x + y * y + z * z - r * r;
        }
        u
    };

    let level = 0.0;
    let (verts, faces, normals) = marching_tetrahedra(u.as_slice().unwrap(), dim, level);

    use glium::{DisplayBuild, Surface};
    let display = glium::glutin::WindowBuilder::new()
        .with_depth_buffer(24)
        .build_glium()
        .unwrap();

    let surface = surface::Surface::new(&display, &verts, &faces, &normals);

    let mut camera = camera::CameraState::new();
    let mut wireframe = false;
    let mut show_normals = false;

    loop {
        camera.update();

        let mut target = display.draw();
        target.clear_color_and_depth((0.0, 0.0, 0.0, 1.0), 1.0);

        surface.draw(&mut target, &camera, wireframe, show_normals).unwrap();

        target.finish().unwrap();

        for ev in display.poll_events() {
            match ev {
                glium::glutin::Event::Closed => return,
                glutin::Event::KeyboardInput(glutin::ElementState::Pressed,
                                             _,
                                             Some(glutin::VirtualKeyCode::F)) => {
                    wireframe = !wireframe
                }
                glutin::Event::KeyboardInput(glutin::ElementState::Pressed,
                                             _,
                                             Some(glutin::VirtualKeyCode::N)) => {
                    show_normals = !show_normals
                }
                ev => camera.process_input(&ev),
            }
        }
    }
}
<commit_msg>Compare with original surface<commit_after>extern crate fast_sweeping;
extern crate surfviz;
#[macro_use]
extern crate glium;
extern crate isosurface;
extern crate ndarray;

use ndarray::Array;
use isosurface::marching_tetrahedra;
use glium::glutin;

use surfviz::surface;
use surfviz::camera;

fn main() {
    let res = 10;
    let h = 1. / res as f64;
    let xs = Array::linspace(-0.5, 0.5, res);
    let ys = Array::linspace(-0.5, 0.5, res);
    let zs = Array::linspace(-0.5, 0.5, res);

    let dim = (xs.len(), ys.len(), zs.len());

    let u = {
        let mut u: Array<f64, _> = Array::from_elem(dim, 0.);

        let r = 0.3;
        for ((i, j, k), u) in u.indexed_iter_mut() {
            let (x, y, z) = (xs[i], ys[j], zs[k]);
            *u = x * x + y * y + z * z - r * r;
            *u = u.min((x - 0.25) * (x - 0.25) + y * y + z * z - 0.2 * 0.2);
        }
        u
    };

    let mut d = u.clone();

    let mut v = u.clone();
    for _ in 0..10 {
        fast_sweeping::signed_distance_3d(d.as_slice_mut().unwrap(), v.as_slice().unwrap(), dim, h);
        v.clone_from(&d);
    }

    let level = 0.0;

    use glium::{DisplayBuild, Surface};
    let display = glium::glutin::WindowBuilder::new()
        .with_depth_buffer(24)
        .build_glium()
        .unwrap();

    let (verts, faces, normals) = marching_tetrahedra(u.as_slice().unwrap(), dim, level);
    let surface = surface::Surface::new(&display, &verts, &faces, &normals);

    let (verts, faces, normals) = marching_tetrahedra(d.as_slice().unwrap(), dim, level);
    let signed_distance_surface = {
        let mut s = surface::Surface::new(&display, &verts, &faces, &normals);
        s.set_color([0., 0., 1., 1.]);
        s
    };

    let mut camera = camera::CameraState::new();
    let mut wireframe = false;
    let mut show_normals = false;

    loop {
        camera.update();

        let mut target = display.draw();
        target.clear_color_and_depth((0.0, 0.0, 0.0, 1.0), 1.0);

        surface.draw(&mut target, &camera, wireframe, show_normals).unwrap();
        signed_distance_surface.draw(&mut target, &camera, wireframe, show_normals).unwrap();

        target.finish().unwrap();

        for ev in display.poll_events() {
            match ev {
                glium::glutin::Event::Closed => return,
                glutin::Event::KeyboardInput(glutin::ElementState::Pressed,
                                             _,
                                             Some(glutin::VirtualKeyCode::F)) => {
                    wireframe = !wireframe
                }
                glutin::Event::KeyboardInput(glutin::ElementState::Pressed,
                                             _,
                                             Some(glutin::VirtualKeyCode::N)) => {
                    show_normals = !show_normals
                }
                ev => camera.process_input(&ev),
            }
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright 2020 Google LLC All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
use std::result;
use std::str::from_utf8;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering::Relaxed;
use std::sync::Arc;

use slog::{debug, error, o, Logger};
use tokio::io::Result;
use tokio::net::udp::{RecvHalf, SendHalf};
use tokio::net::UdpSocket;
use tokio::select;
use tokio::sync::{mpsc, watch, RwLock};
use tokio::time::{Duration, Instant};

use crate::config::EndPoint;
use crate::extensions::{Filter, FilterChain};

/// SESSION_TIMEOUT_SECONDS is the default session timeout - which is one minute.
pub const SESSION_TIMEOUT_SECONDS: u64 = 60;

/// Session encapsulates a UDP stream session
pub struct Session {
    log: Logger,
    chain: Arc<FilterChain>,
    send: SendHalf,
    /// dest is where to send data to
    dest: EndPoint,
    /// from is the original sender
    from: SocketAddr,
    /// session expiration timestamp
    expiration: Arc<RwLock<Instant>>,
    /// closer is a channel to broadcast on if we are shutting down this Session
    closer: watch::Sender<bool>,
    /// closed is if this Session has closed, and isn't receiving packets anymore
    is_closed: Arc<AtomicBool>,
}

/// Packet represents a packet that needs to go somewhere
pub struct Packet {
    dest: SocketAddr,
    contents: Vec<u8>,
}

impl Packet {
    pub fn new(dest: SocketAddr, contents: Vec<u8>) -> Packet {
        Packet { dest, contents }
    }

    pub fn dest(&self) -> SocketAddr {
        self.dest
    }

    pub fn contents(&self) -> &Vec<u8> {
        &self.contents
    }
}

impl Session {
    /// new creates a new Session, and starts the process of receiving udp sockets
    /// from its ephemeral port from endpoint(s)
    pub async fn new(
        base: &Logger,
        chain: Arc<FilterChain>,
        from: SocketAddr,
        dest: EndPoint,
        sender: mpsc::Sender<Packet>,
    ) -> Result<Self> {
        let addr = SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), 0);
        let (recv, send) = UdpSocket::bind(addr).await?.split();
        let (closer, closed) = watch::channel::<bool>(false);
        let mut s = Session {
            log: base.new(o!("source" => "server::Session", "from" => from, "dest_name" => dest.name.clone(), "dest_address" => dest.address.clone())),
            chain,
            send,
            from,
            dest,
            expiration: Arc::new(RwLock::new(
                Instant::now() + Duration::from_secs(SESSION_TIMEOUT_SECONDS),
            )),
            closer,
            is_closed: Arc::new(AtomicBool::new(false)),
        };
        debug!(s.log, "Session created");

        s.run(recv, sender, closed);
        Ok(s)
    }

    /// run starts processing received udp packets on its UdpSocket
    fn run(
        &mut self,
        mut recv: RecvHalf,
        sender: mpsc::Sender<Packet>,
        closed: watch::Receiver<bool>,
    ) {
        let log = self.log.clone();
        let from = self.from;
        let expiration_mtx = self.expiration.clone();
        let mut closed = Box::new(closed);
        let is_closed = self.is_closed.clone();
        tokio::spawn(async move {
            let mut buf: Vec<u8> = vec![0; 65535];
            loop {
                debug!(log, "Awaiting incoming packet");
                select! {
                    received = recv.recv_from(&mut buf) => {
                        match received {
                            Err(err) => error!(log, "Error receiving packet"; "error" => %err),
                            Ok((size, recv_addr)) => Session::process_recv_packet(
                                &log,
                                &buf[..size],
                                recv_addr,
                                from,
                                sender.clone(),
                                expiration_mtx.clone()).await,
                        };
                    }
                    close_request = closed.recv() => {
                        debug!(log, "Attempting to close session"; "result" => format!("{:?}", close_request));
                        if let Some(true) = close_request {
                            is_closed.store(true, Relaxed);
                            debug!(log, "Closing Session");
                            return;
                        } else if let None = close_request {
                            is_closed.store(true, Relaxed);
                            debug!(log, "Dropping Session");
                            return;
                        }
                    }
                };
            }
        });
    }

    /// expiration returns the current expiration Instant value
    pub async fn expiration(&self) -> Instant {
        *self.expiration.read().await
    }

    /// key returns the key to be used for this session in a SessionMap
    pub fn key(&self) -> (SocketAddr, SocketAddr) {
        (self.from, self.dest.address)
    }

    /// process_recv_packet processes a packet that is received by this session.
    async fn process_recv_packet(
        log: &Logger,
        packet: &[u8],
        from: SocketAddr,
        dest: SocketAddr,
        mut sender: mpsc::Sender<Packet>,
        expiration: Arc<RwLock<Instant>>,
    ) {
        debug!(log, "Received packet"; "from" => %from, "contents" => from_utf8(packet).unwrap());
        Session::inc_expiration(expiration).await;
        if let Err(err) = sender.send(Packet::new(dest, packet.to_vec())).await {
            error!(log, "Error sending packet to channel"; "error" => %err);
        }
    }

    /// increment_expiration increments the expiration value by the session timeout
    pub async fn increment_expiration(&mut self) {
        let expiration = self.expiration.clone();
        Session::inc_expiration(expiration).await
    }

    /// increment_expiration increments the expiration value by the session timeout (internal)
    async fn inc_expiration(expiration: Arc<RwLock<Instant>>) {
        let mut expiration = expiration.write().await;
        *expiration = Instant::now() + Duration::from_secs(SESSION_TIMEOUT_SECONDS);
    }

    /// Sends a packet to the Session's dest.
    pub async fn send_to(&mut self, buf: &[u8]) -> Result<Option<usize>> {
        debug!(self.log, "Sending packet"; "dest_name" => &self.dest.name, "dest_address" => &self.dest.address, "contents" => from_utf8(buf).unwrap());

        if let Some(data) = self
            .chain
            .endpoint_send_filter(&self.dest, self.from, buf.to_vec())
        {
            return match self.send.send_to(data.as_slice(), &self.dest.address).await {
                Ok(size) => Ok(Some(size)),
                Err(err) => Err(err),
            };
        }

        Ok(None)
    }

    /// is_closed returns if the Session is closed or not.
    #[allow(dead_code)]
    pub fn is_closed(&self) -> bool {
        return self.is_closed.load(Relaxed);
    }

    /// close closes this Session.
    pub fn close(&self) -> result::Result<(), watch::error::SendError<bool>> {
        debug!(self.log, "Session closed"; "from" => self.from, "dest_name" => &self.dest.name, "dest_address" => &self.dest.address);
        self.closer.broadcast(true)
    }
}

#[cfg(test)]
mod tests {
    use slog::info;
    use tokio::time;
    use tokio::time::delay_for;

    use crate::test_utils::{ephemeral_socket, logger, recv_udp, TestFilter};

    use super::*;

    #[tokio::test]
    async fn session_new() {
        time::pause();

        let log = logger();
        let mut socket = ephemeral_socket().await;
        let local_addr = socket.local_addr().unwrap();
        let endpoint = EndPoint {
            name: "endpoint".to_string(),
            address: local_addr,
            connection_ids: vec![],
        };
        let (send_packet, mut recv_packet) = mpsc::channel::<Packet>(5);

        let mut sess = Session::new(
            &log,
            Arc::new(FilterChain::new(vec![])),
            local_addr,
            endpoint,
            send_packet,
        )
        .await
        .unwrap();

        let initial_expiration: Instant;
        {
            initial_expiration = sess.expiration.read().await.clone();
        }
        let diff = initial_expiration.duration_since(Instant::now());
        assert_eq!(diff.as_secs(), SESSION_TIMEOUT_SECONDS);

        let time_increment = 10;
        time::advance(Duration::from_secs(time_increment)).await;

        // echo the packet back again
        tokio::spawn(async move {
            let mut buf = vec![0; 1024];
            let (size, recv_addr) = socket.recv_from(&mut buf).await.unwrap();
            assert_eq!("hello", from_utf8(&buf[..size]).unwrap());
            socket.send_to(&buf[..size], recv_addr).await.unwrap();
        });

        sess.send_to("hello".as_bytes()).await.unwrap();

        let packet = recv_packet
            .recv()
            .await
            .expect("Should receive a packet 'hello'");
        assert_eq!(String::from("hello").into_bytes(), packet.contents);
        assert_eq!(local_addr, packet.dest);

        let current_expiration = sess.expiration.read().await.clone();
        assert!(Instant::now() < current_expiration);

        let diff = current_expiration.duration_since(initial_expiration);
        info!(log, "difference during test"; "duration" => format!("{:?}", diff));
        assert!(diff.as_secs() >= time_increment);

        sess.close().unwrap();
        time::resume();
    }

    #[tokio::test]
    async fn session_send_to() {
        let log = logger();
        let msg = "hello";

        // without a filter
        let (sender, _) = mpsc::channel::<Packet>(1);
        let (local_addr, wait) = recv_udp().await;
        let endpoint = EndPoint {
            name: "endpoint".to_string(),
            address: local_addr,
            connection_ids: vec![],
        };

        let mut session = Session::new(
            &log,
            Arc::new(FilterChain::new(vec![])),
            local_addr,
            endpoint.clone(),
            sender,
        )
        .await
        .unwrap();
        session.send_to(msg.as_bytes()).await.unwrap();
        assert_eq!(msg, wait.await.unwrap());

        // with a filter
        let (sender, _) = mpsc::channel::<Packet>(1);
        let (local_addr, wait) = recv_udp().await;
        let endpoint = EndPoint {
            name: "endpoint".to_string(),
            address: local_addr,
            connection_ids: vec![],
        };
        let mut session = Session::new(
            &log,
            Arc::new(FilterChain::new(vec![Arc::new(TestFilter {})])),
            local_addr,
            endpoint.clone(),
            sender,
        )
        .await
        .unwrap();

        session.send_to(msg.as_bytes()).await.unwrap();
        assert_eq!(
            format!("{}:esf:{}:{}", msg, endpoint.name, local_addr),
            wait.await.unwrap()
        );
    }

    #[tokio::test]
    async fn session_close() {
        let log = logger();
        let socket = ephemeral_socket().await;
        let local_addr = socket.local_addr().unwrap();
        let (send_packet, _) = mpsc::channel::<Packet>(5);
        let endpoint = EndPoint {
            name: "endpoint".to_string(),
            address: local_addr,
            connection_ids: vec![],
        };

        info!(log, ">> creating sessions");
        let sess = Session::new(
            &log,
            Arc::new(FilterChain::new(vec![])),
            local_addr,
            endpoint,
            send_packet,
        )
        .await
        .unwrap();
        info!(log, ">> session created and running");

        assert!(!sess.is_closed(), "session should not be closed");
        sess.close().unwrap();

        // Poll the state to wait for the change, because everything is async
        for _ in 1..10 {
            let is_closed = sess.is_closed();
            info!(log, "session closed?"; "closed" => is_closed);
            if is_closed {
                break;
            }

            delay_for(Duration::from_secs(1)).await;
        }

        assert!(sess.is_closed(), "session should be closed");
    }
}
<commit_msg>Implementation of endpoint_receive_filter (#59)<commit_after>/*
 * Copyright 2020 Google LLC All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
use std::result;
use std::str::from_utf8;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering::Relaxed;
use std::sync::Arc;

use slog::{debug, error, o, Logger};
use tokio::io::Result;
use tokio::net::udp::{RecvHalf, SendHalf};
use tokio::net::UdpSocket;
use tokio::select;
use tokio::sync::{mpsc, watch, RwLock};
use tokio::time::{Duration, Instant};

use crate::config::EndPoint;
use crate::extensions::{Filter, FilterChain};

/// SESSION_TIMEOUT_SECONDS is the default session timeout - which is one minute.
pub const SESSION_TIMEOUT_SECONDS: u64 = 60;

/// Session encapsulates a UDP stream session
pub struct Session {
    log: Logger,
    chain: Arc<FilterChain>,
    send: SendHalf,
    /// dest is where to send data to
    dest: EndPoint,
    /// from is the original sender
    from: SocketAddr,
    /// session expiration timestamp
    expiration: Arc<RwLock<Instant>>,
    /// closer is a channel to broadcast on if we are shutting down this Session
    closer: watch::Sender<bool>,
    /// closed is if this Session has closed, and isn't receiving packets anymore
    is_closed: Arc<AtomicBool>,
}

/// Packet represents a packet that needs to go somewhere
pub struct Packet {
    dest: SocketAddr,
    contents: Vec<u8>,
}

impl Packet {
    pub fn new(dest: SocketAddr, contents: Vec<u8>) -> Packet {
        Packet { dest, contents }
    }

    pub fn dest(&self) -> SocketAddr {
        self.dest
    }

    pub fn contents(&self) -> &Vec<u8> {
        &self.contents
    }
}

impl Session {
    /// new creates a new Session, and starts the process of receiving udp sockets
    /// from its ephemeral port from endpoint(s)
    pub async fn new(
        base: &Logger,
        chain: Arc<FilterChain>,
        from: SocketAddr,
        dest: EndPoint,
        sender: mpsc::Sender<Packet>,
    ) -> Result<Self> {
        let addr = SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), 0);
        let (recv, send) = UdpSocket::bind(addr).await?.split();
        let (closer, closed) = watch::channel::<bool>(false);
        let mut s = Session {
            log: base.new(o!("source" => "server::Session", "from" => from, "dest_name" => dest.name.clone(), "dest_address" => dest.address.clone())),
            chain,
            send,
            from,
            dest,
            expiration: Arc::new(RwLock::new(
                Instant::now() + Duration::from_secs(SESSION_TIMEOUT_SECONDS),
            )),
            closer,
            is_closed: Arc::new(AtomicBool::new(false)),
        };
        debug!(s.log, "Session created");

        s.run(recv, sender, closed);
        Ok(s)
    }

    /// run starts processing received udp packets on its UdpSocket
    fn run(
        &mut self,
        mut recv: RecvHalf,
        sender: mpsc::Sender<Packet>,
        closed: watch::Receiver<bool>,
    ) {
        let log = self.log.clone();
        let from = self.from;
        let expiration_mtx = self.expiration.clone();
        let mut closed = Box::new(closed);
        let is_closed = self.is_closed.clone();
        let chain = self.chain.clone();
        let endpoint = self.dest.clone();
        tokio::spawn(async move {
            let mut buf: Vec<u8> = vec![0; 65535];
            loop {
                debug!(log, "Awaiting incoming packet");
                select! {
                    received = recv.recv_from(&mut buf) => {
                        match received {
                            Err(err) => error!(log, "Error receiving packet"; "error" => %err),
                            Ok((size, recv_addr)) => Session::process_recv_packet(
                                &log,
                                chain.clone(),
                                &buf[..size],
                                &endpoint,
                                recv_addr,
                                from,
                                sender.clone(),
                                expiration_mtx.clone()).await,
                        };
                    }
                    close_request = closed.recv() => {
                        debug!(log, "Attempting to close session"; "result" => format!("{:?}", close_request));
                        if let Some(true) = close_request {
                            is_closed.store(true, Relaxed);
                            debug!(log, "Closing Session");
                            return;
                        } else if let None = close_request {
                            is_closed.store(true, Relaxed);
                            debug!(log, "Dropping Session");
                            return;
                        }
                    }
                };
            }
        });
    }

    /// expiration returns the current expiration Instant value
    pub async fn expiration(&self) -> Instant {
        *self.expiration.read().await
    }

    /// key returns the key to be used for this session in a SessionMap
    pub fn key(&self) -> (SocketAddr, SocketAddr) {
        (self.from, self.dest.address)
    }

    /// process_recv_packet processes a packet that is received by this session.
    async fn process_recv_packet(
        log: &Logger,
        chain: Arc<FilterChain>,
        packet: &[u8],
        from: &EndPoint,
        recv_addr: SocketAddr,
        dest: SocketAddr,
        mut sender: mpsc::Sender<Packet>,
        expiration: Arc<RwLock<Instant>>,
    ) {
        debug!(log, "Received packet"; "recv_address" => recv_addr, "from_name" => &from.name, "from_addr" => &from.address, "contents" => from_utf8(packet).unwrap());
        Session::inc_expiration(expiration).await;

        if let Some(data) = chain.endpoint_receive_filter(from, recv_addr, packet.to_vec()) {
            if let Err(err) = sender.send(Packet::new(dest, data)).await {
                error!(log, "Error sending packet to channel"; "error" => %err);
            }
        }
    }

    /// increment_expiration increments the expiration value by the session timeout
    pub async fn increment_expiration(&mut self) {
        let expiration = self.expiration.clone();
        Session::inc_expiration(expiration).await
    }

    /// increment_expiration increments the expiration value by the session timeout (internal)
    async fn inc_expiration(expiration: Arc<RwLock<Instant>>) {
        let mut expiration = expiration.write().await;
        *expiration = Instant::now() + Duration::from_secs(SESSION_TIMEOUT_SECONDS);
    }

    /// Sends a packet to the Session's dest.
    pub async fn send_to(&mut self, buf: &[u8]) -> Result<Option<usize>> {
        debug!(self.log, "Sending packet"; "dest_name" => &self.dest.name, "dest_address" => &self.dest.address, "contents" => from_utf8(buf).unwrap());

        if let Some(data) = self
            .chain
            .endpoint_send_filter(&self.dest, self.from, buf.to_vec())
        {
            return match self.send.send_to(data.as_slice(), &self.dest.address).await {
                Ok(size) => Ok(Some(size)),
                Err(err) => Err(err),
            };
        }

        Ok(None)
    }

    /// is_closed returns if the Session is closed or not.
    #[allow(dead_code)]
    pub fn is_closed(&self) -> bool {
        return self.is_closed.load(Relaxed);
    }

    /// close closes this Session.
    pub fn close(&self) -> result::Result<(), watch::error::SendError<bool>> {
        debug!(self.log, "Session closed"; "from" => self.from, "dest_name" => &self.dest.name, "dest_address" => &self.dest.address);
        self.closer.broadcast(true)
    }
}

#[cfg(test)]
mod tests {
    use slog::info;
    use tokio::time;
    use tokio::time::delay_for;

    use crate::test_utils::{ephemeral_socket, logger, recv_udp, TestFilter};

    use super::*;

    #[tokio::test]
    async fn session_new() {
        time::pause();

        let log = logger();
        let mut socket = ephemeral_socket().await;
        let local_addr = socket.local_addr().unwrap();
        let endpoint = EndPoint {
            name: "endpoint".to_string(),
            address: local_addr,
            connection_ids: vec![],
        };
        let (send_packet, mut recv_packet) = mpsc::channel::<Packet>(5);

        let mut sess = Session::new(
            &log,
            Arc::new(FilterChain::new(vec![])),
            local_addr,
            endpoint,
            send_packet,
        )
        .await
        .unwrap();

        let initial_expiration: Instant;
        {
            initial_expiration = sess.expiration.read().await.clone();
        }
        let diff = initial_expiration.duration_since(Instant::now());
        assert_eq!(diff.as_secs(), SESSION_TIMEOUT_SECONDS);

        let time_increment = 10;
        time::advance(Duration::from_secs(time_increment)).await;

        // echo the packet back again
        tokio::spawn(async move {
            let mut buf = vec![0; 1024];
            let (size, recv_addr) = socket.recv_from(&mut buf).await.unwrap();
            assert_eq!("hello", from_utf8(&buf[..size]).unwrap());
            socket.send_to(&buf[..size], recv_addr).await.unwrap();
        });

        sess.send_to("hello".as_bytes()).await.unwrap();

        let packet = recv_packet
            .recv()
            .await
            .expect("Should receive a packet 'hello'");
        assert_eq!(String::from("hello").into_bytes(), packet.contents);
        assert_eq!(local_addr, packet.dest);

        let current_expiration = sess.expiration.read().await.clone();
        assert!(Instant::now() < current_expiration);

        let diff = current_expiration.duration_since(initial_expiration);
        info!(log, "difference during test"; "duration" => format!("{:?}", diff));
        assert!(diff.as_secs() >= time_increment);

        sess.close().unwrap();
        time::resume();
    }

    #[tokio::test]
    async fn session_send_to() {
        let log = logger();
        let msg = "hello";

        // without a filter
        let (sender, _) = mpsc::channel::<Packet>(1);
        let (local_addr, wait) = recv_udp().await;
        let endpoint = EndPoint {
            name: "endpoint".to_string(),
            address: local_addr,
            connection_ids: vec![],
        };

        let mut session = Session::new(
            &log,
            Arc::new(FilterChain::new(vec![])),
            local_addr,
            endpoint.clone(),
            sender,
        )
        .await
        .unwrap();
        session.send_to(msg.as_bytes()).await.unwrap();
        assert_eq!(msg, wait.await.unwrap());

        // with a filter
        let (sender, _) = mpsc::channel::<Packet>(1);
        let (local_addr, wait) = recv_udp().await;
        let endpoint = EndPoint {
            name: "endpoint".to_string(),
            address: local_addr,
            connection_ids: vec![],
        };
        let mut session = Session::new(
            &log,
            Arc::new(FilterChain::new(vec![Arc::new(TestFilter {})])),
            local_addr,
            endpoint.clone(),
            sender,
        )
        .await
        .unwrap();

        session.send_to(msg.as_bytes()).await.unwrap();
        assert_eq!(
            format!("{}:esf:{}:{}", msg, endpoint.name, local_addr),
            wait.await.unwrap()
        );
    }

    #[tokio::test]
    async fn session_close() {
        let log = logger();
        let socket = ephemeral_socket().await;
        let local_addr = socket.local_addr().unwrap();
        let (send_packet, _) = mpsc::channel::<Packet>(5);
        let endpoint = EndPoint {
            name: "endpoint".to_string(),
            address: local_addr,
            connection_ids: vec![],
        };

        info!(log, ">> creating sessions");
        let sess = Session::new(
            &log,
            Arc::new(FilterChain::new(vec![])),
            local_addr,
            endpoint,
            send_packet,
        )
        .await
        .unwrap();
        info!(log, ">> session created and running");

        assert!(!sess.is_closed(), "session should not be closed");
        sess.close().unwrap();

        // Poll the state to wait for the change, because everything is async
        for _ in 1..10 {
            let is_closed = sess.is_closed();
            info!(log, "session closed?"; "closed" => is_closed);
            if is_closed {
                break;
            }

            delay_for(Duration::from_secs(1)).await;
        }

        assert!(sess.is_closed(), "session should be closed");
    }

    #[tokio::test]
    async fn process_recv_packet() {
        let log = logger();
        let chain = Arc::new(FilterChain::new(vec![]));
        let endpoint = EndPoint {
            name: "endpoint".to_string(),
            address: "127.0.1.1:80".parse().unwrap(),
            connection_ids: vec![],
        };
        let dest = "127.0.0.1:88".parse().unwrap();
        let (sender, mut receiver) = mpsc::channel::<Packet>(10);
        let expiration = Arc::new(RwLock::new(Instant::now()));
        let mut initial_expiration: Instant;
        {
            initial_expiration = expiration.read().await.clone();
        }

        // first test with no filtering
        let msg = "hello";
        Session::process_recv_packet(
            &log,
            chain,
            msg.as_bytes(),
            &endpoint,
            endpoint.address,
            dest,
            sender.clone(),
            expiration.clone(),
        )
        .await;

        assert!(initial_expiration < *expiration.read().await);
        let p = receiver.try_recv().unwrap();
        assert_eq!(msg, from_utf8(p.contents.as_slice()).unwrap());
        assert_eq!(dest, p.dest);

        {
            initial_expiration = expiration.read().await.clone();
        }
        // add filter
        let chain = Arc::new(FilterChain::new(vec![Arc::new(TestFilter {})]));
        Session::process_recv_packet(
            &log,
            chain,
            msg.as_bytes(),
            &endpoint,
            endpoint.address,
            dest,
            sender.clone(),
            expiration.clone(),
        )
        .await;

        assert!(initial_expiration < *expiration.read().await);
        let p = receiver.try_recv().unwrap();
        assert_eq!(
            format!("{}:erf:endpoint:127.0.1.1:80", msg),
            from_utf8(p.contents.as_slice()).unwrap()
        );
        assert_eq!(dest, p.dest);
    }
}
<|endoftext|>


<commit_before>extern crate iron;
extern crate mount;
extern crate logger;
extern crate rustc_serialize;
#[macro_use] extern crate juniper;

use std::env;

use mount::Mount;
use logger::Logger;
use iron::prelude::*;
use juniper::EmptyMutation;
use juniper::iron_handlers::{GraphQLHandler, GraphiQLHandler};
use juniper::tests::model::Database;

fn context_factory(_: &mut Request) -> Database {
    Database::new()
}

fn main() {
    let mut mount = Mount::new();

    let graphql_endpoint = GraphQLHandler::new(
        context_factory,
        Database::new(),
        EmptyMutation::<Database>::new(),
    );
    let graphiql_endpoint = GraphiQLHandler::new("/graphql");

    mount.mount("/", graphiql_endpoint);
    mount.mount("/graphql", graphql_endpoint);

    let (logger_before, logger_after) = Logger::new(None);

    let mut chain = Chain::new(mount);
    chain.link_before(logger_before);
    chain.link_after(logger_after);

    let host = env::var("LISTEN").unwrap_or("0.0.0.0:8080".to_owned());
    println!("GraphQL server started on {}", host);
    Iron::new(chain).http(host.as_str()).unwrap();
}
<commit_msg>Don't attach Iron logger middleware on Windows<commit_after>extern crate iron;
extern crate mount;
extern crate logger;
extern crate rustc_serialize;
#[macro_use] extern crate juniper;

use std::env;

use mount::Mount;
use logger::Logger;
use iron::prelude::*;
use juniper::EmptyMutation;
use juniper::iron_handlers::{GraphQLHandler, GraphiQLHandler};
use juniper::tests::model::Database;

fn context_factory(_: &mut Request) -> Database {
    Database::new()
}

fn main() {
    let mut mount = Mount::new();

    let graphql_endpoint = GraphQLHandler::new(
        context_factory,
        Database::new(),
        EmptyMutation::<Database>::new(),
    );
    let graphiql_endpoint = GraphiQLHandler::new("/graphql");

    mount.mount("/", graphiql_endpoint);
    mount.mount("/graphql", graphql_endpoint);

    let mut chain = Chain::new(mount);

    // Temporary fix - Iron's logger middleware does not work on Windows
    #[cfg(not(windows))] setup_logger(&mut chain);

    let host = env::var("LISTEN").unwrap_or("0.0.0.0:8080".to_owned());
    println!("GraphQL server started on {}", host);
    Iron::new(chain).http(host.as_str()).unwrap();
}

fn setup_logger(chain: &mut Chain) {
    let (logger_before, logger_after) = Logger::new(None);
    chain.link_before(logger_before);
    chain.link_after(logger_after);
}
<|endoftext|>


<commit_before>use std::cmp::{min, max};
use std::ops::{Index, IndexMut};

/// The game's grid, internally represented by matrices provided by the nalgebra crate.
#[derive(Clone)]
pub struct Grid {
    cols: usize,
    matrix: Vec<bool>,
    rows: usize,
}

impl Grid {
    /// Create a new grid with the specified dimensions. All cells default to `false`.
    pub fn new(rows: usize, columns: usize) -> Grid {
        Grid {
            cols: columns,
            matrix: vec![false; rows * columns],
            rows: rows,
        }
    }

    /// The number of columns in the grid.
    pub fn cols(&self) -> usize {
        self.cols
    }

    /// The number of rows in the grid.
    pub fn rows(&self) -> usize {
        self.rows
    }

    /// The amount of neighbours a cell has.
    pub fn neighbours(&self, (x, y): (usize, usize)) -> u8 {
        let mut total = 0;

        for p in max(x, 1) - 1..min(x + 2, self.cols() - 1) {
            for q in max(y, 1) - 1..min(y + 2, self.rows() - 1) {
                if self[(p, q)] {
                    total += 1;
                }
            }
        }

        // Otherwise we would count the cell itself
        if self[(x, y)] {
            total -= 1;
        }

        total
    }
}

impl Index<(usize, usize)> for Grid {
    type Output = bool;

    fn index(&self, (x, y): (usize, usize)) -> &bool {
        &self.matrix[x + y * self.cols]
    }
}

impl IndexMut<(usize, usize)> for Grid {
    fn index_mut(&mut self, (x, y): (usize, usize)) -> &mut bool {
        &mut self.matrix[x + y * self.cols]
    }
}

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

    #[test]
    fn bounds_are_reported_correctly() {
        let grid = Grid::new(10, 10);

        assert_eq!(10, grid.rows());
        assert_eq!(10, grid.cols());

        assert_eq!(false, grid[(9, 9)]);
    }

    #[test]
    #[should_panic]
    fn horizontal_bound_should_overflow() {
        let grid = Grid::new(10, 10);

        grid[(10, 9)];
    }

    #[test]
    #[should_panic]
    fn vertical_bound_should_overflow() {
        let grid = Grid::new(10, 10);

        grid[(9, 10)];
    }

    #[test]
    fn indexing_works() {
        let mut grid = Grid::new(10, 10);

        for i in 0..10 {
            grid[(i, 0)] = true;
        }

        for x in 0..10 {
            for y in 0..10 {
                if y == 0 {
                    assert_eq!(true, grid[(x, y)])
                } else {
                    assert_eq!(false, grid[(x, y)])
                }
            }
        }
    }

    #[test]
    fn neighbours_are_reported_correctly() {
        let mut grid = Grid::new(10, 10);
        grid[(5, 5)] = true;
        grid[(4, 4)] = true;
        grid[(5, 4)] = true;
        grid[(6, 4)] = true;
        grid[(4, 6)] = true;

        assert_eq!(4, grid.neighbours((5, 5)));
    }

    #[test]
    fn neighbours_are_reported_correctly_for_corners() {
        let mut grid = Grid::new(10, 10);
        grid[(1, 0)] = true;
        grid[(1, 1)] = true;
        grid[(0, 1)] = true;

        assert_eq!(3, grid.neighbours((0, 0)));
    }
}
<commit_msg>Fix an integer underflow in the neighbour checking algorithm<commit_after>use std::cmp::{min, max};
use std::ops::{Index, IndexMut};

/// The game's grid, internally represented by matrices provided by the nalgebra crate.
#[derive(Clone)]
pub struct Grid {
    cols: usize,
    matrix: Vec<bool>,
    rows: usize,
}

impl Grid {
    /// Create a new grid with the specified dimensions. All cells default to `false`.
    pub fn new(rows: usize, columns: usize) -> Grid {
        Grid {
            cols: columns,
            matrix: vec![false; rows * columns],
            rows: rows,
        }
    }

    /// The number of columns in the grid.
    pub fn cols(&self) -> usize {
        self.cols
    }

    /// The number of rows in the grid.
    pub fn rows(&self) -> usize {
        self.rows
    }

    /// The amount of neighbours a cell has.
    pub fn neighbours(&self, (x, y): (usize, usize)) -> u8 {
        let mut total = 0;

        for p in max(x, 1) - 1..min(x + 2, self.cols() - 1) {
            for q in max(y, 1) - 1..min(y + 2, self.rows() - 1) {
                if self[(p, q)] {
                    total += 1;
                }
            }
        }

        // Otherwise we would count the cell itself
        if self[(x, y)] && total > 0 {
            total -= 1;
        }

        total
    }
}

impl Index<(usize, usize)> for Grid {
    type Output = bool;

    fn index(&self, (x, y): (usize, usize)) -> &bool {
        &self.matrix[x + y * self.cols]
    }
}

impl IndexMut<(usize, usize)> for Grid {
    fn index_mut(&mut self, (x, y): (usize, usize)) -> &mut bool {
        &mut self.matrix[x + y * self.cols]
    }
}

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

    #[test]
    fn bounds_are_reported_correctly() {
        let grid = Grid::new(10, 10);

        assert_eq!(10, grid.rows());
        assert_eq!(10, grid.cols());

        assert_eq!(false, grid[(9, 9)]);
    }

    #[test]
    #[should_panic]
    fn horizontal_bound_should_overflow() {
        let grid = Grid::new(10, 10);

        grid[(10, 9)];
    }

    #[test]
    #[should_panic]
    fn vertical_bound_should_overflow() {
        let grid = Grid::new(10, 10);

        grid[(9, 10)];
    }

    #[test]
    fn indexing_works() {
        let mut grid = Grid::new(10, 10);

        for i in 0..10 {
            grid[(i, 0)] = true;
        }

        for x in 0..10 {
            for y in 0..10 {
                if y == 0 {
                    assert_eq!(true, grid[(x, y)])
                } else {
                    assert_eq!(false, grid[(x, y)])
                }
            }
        }
    }

    #[test]
    fn neighbours_are_reported_correctly() {
        let mut grid = Grid::new(10, 10);
        grid[(5, 5)] = true;
        grid[(4, 4)] = true;
        grid[(5, 4)] = true;
        grid[(6, 4)] = true;
        grid[(4, 6)] = true;

        assert_eq!(4, grid.neighbours((5, 5)));
    }

    #[test]
    fn neighbours_are_reported_correctly_for_corners() {
        let mut grid = Grid::new(10, 10);
        grid[(1, 0)] = true;
        grid[(1, 1)] = true;
        grid[(0, 1)] = true;

        assert_eq!(3, grid.neighbours((0, 0)));
    }
}
<|endoftext|>


<commit_before>//! Pieces pertaining to the HTTP message protocol.
use std::{io, mem, str};
use std::error::Error as Error;
use std::convert::Into;

use cookie::CookieJar;
use http::{StatusCode, Version, HeaderMap, HttpTryFrom, Error as HttpError};
use http::header::{self, HeaderName, HeaderValue};

use Cookie;
use body::Body;

/// Represents various types of connection
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum ConnectionType {
    /// Close connection after response
    Close,
    /// Keep connection alive after response
    KeepAlive,
    /// Connection is upgraded to different type
    Upgrade,
}

#[derive(Debug)]
/// An HTTP Response
pub struct HttpResponse {
    pub version: Option<Version>,
    pub headers: HeaderMap,
    pub status: StatusCode,
    reason: Option<&'static str>,
    body: Body,
    chunked: bool,
    connection_type: Option<ConnectionType>,
    error: Option<Box<Error>>,
}

impl HttpResponse {

    #[inline]
    pub fn builder(status: StatusCode) -> HttpResponseBuilder {
        HttpResponseBuilder {
            parts: Some(Parts::new(status)),
            err: None,
        }
    }

    /// Constructs a response
    #[inline]
    pub fn new(status: StatusCode, body: Body) -> HttpResponse {
        HttpResponse {
            version: None,
            headers: Default::default(),
            status: status,
            reason: None,
            body: body,
            chunked: false,
            // compression: None,
            connection_type: None,
            error: None,
        }
    }

    /// Constructs a response from error
    #[inline]
    pub fn from_error<E: Error + 'static>(status: StatusCode, error: E) -> HttpResponse {
        HttpResponse {
            version: None,
            headers: Default::default(),
            status: status,
            reason: None,
            body: Body::from_slice(error.description().as_ref()),
            chunked: false,
            // compression: None,
            connection_type: None,
            error: Some(Box::new(error)),
        }
    }

    /// The `error` which is responsible for this response
    #[inline]
    #[cfg_attr(feature="cargo-clippy", allow(borrowed_box))]
    pub fn error(&self) -> Option<&Box<Error>> {
        self.error.as_ref()
    }

    /// Get the HTTP version of this response.
    #[inline]
    pub fn version(&self) -> Option<Version> {
        self.version
    }

    /// Get the headers from the response.
    #[inline]
    pub fn headers(&self) -> &HeaderMap {
        &self.headers
    }

    /// Get a mutable reference to the headers.
    #[inline]
    pub fn headers_mut(&mut self) -> &mut HeaderMap {
        &mut self.headers
    }

    /// Get the status from the server.
    #[inline]
    pub fn status(&self) -> StatusCode {
        self.status
    }

    /// Set the `StatusCode` for this response.
    #[inline]
    pub fn status_mut(&mut self) -> &mut StatusCode {
        &mut self.status
    }

    /// Get custom reason for the response.
    #[inline]
    pub fn reason(&self) -> &str {
        if let Some(reason) = self.reason {
            reason
        } else {
            ""
        }
    }

    /// Set the custom reason for the response.
    #[inline]
    pub fn set_reason(&mut self, reason: &'static str) -> &mut Self {
        self.reason = Some(reason);
        self
    }

    /// Set connection type
    pub fn set_connection_type(&mut self, conn: ConnectionType) -> &mut Self {
        self.connection_type = Some(conn);
        self
    }

    /// Connection upgrade status
    pub fn upgrade(&self) -> bool {
        self.connection_type == Some(ConnectionType::Upgrade)
    }

    /// Keep-alive status for this connection
    pub fn keep_alive(&self) -> Option<bool> {
        if let Some(ct) = self.connection_type {
            match ct {
                ConnectionType::KeepAlive => Some(true),
                ConnectionType::Close | ConnectionType::Upgrade => Some(false),
            }
        } else {
            None
        }
    }

    /// is chunked encoding enabled
    pub fn chunked(&self) -> bool {
        self.chunked
    }

    /// Enables automatic chunked transfer encoding
    pub fn enable_chunked_encoding(&mut self) -> Result<(), io::Error> {
        if self.headers.contains_key(header::CONTENT_LENGTH) {
            Err(io::Error::new(io::ErrorKind::Other,
                "You can't enable chunked encoding when a content length is set"))
        } else {
            self.chunked = true;
            Ok(())
        }
    }

    /// Get body os this response
    pub fn body(&self) -> &Body {
        &self.body
    }

    /// Set a body
    pub fn set_body<B: Into<Body>>(&mut self, body: B) {
        self.body = body.into();
    }

    /// Set a body and return previous body value
    pub fn replace_body<B: Into<Body>>(&mut self, body: B) -> Body {
        mem::replace(&mut self.body, body.into())
    }
}

/// Helper conversion implementation
impl<I: Into<HttpResponse>, E: Into<HttpResponse>> From<Result<I, E>> for HttpResponse {
    fn from(res: Result<I, E>) -> Self {
        match res {
            Ok(val) => val.into(),
            Err(err) => err.into(),
        }
    }
}

#[derive(Debug)]
struct Parts {
    version: Option<Version>,
    headers: HeaderMap,
    status: StatusCode,
    reason: Option<&'static str>,
    chunked: bool,
    connection_type: Option<ConnectionType>,
    cookies: CookieJar,
}

impl Parts {
    fn new(status: StatusCode) -> Self {
        Parts {
            version: None,
            headers: HeaderMap::new(),
            status: status,
            reason: None,
            chunked: false,
            connection_type: None,
            cookies: CookieJar::new(),
        }
    }
}

/// An HTTP response builder
///
/// This type can be used to construct an instance of `HttpResponse` through a
/// builder-like pattern.
#[derive(Debug)]
pub struct HttpResponseBuilder {
    parts: Option<Parts>,
    err: Option<HttpError>,
}

impl HttpResponseBuilder {
    /// Get the HTTP version of this response.
    #[inline]
    pub fn version(&mut self, version: Version) -> &mut Self {
        if let Some(parts) = parts(&mut self.parts, &self.err) {
            parts.version = Some(version);
        }
        self
    }

    /// Set the `StatusCode` for this response.
    #[inline]
    pub fn status(&mut self, status: StatusCode) -> &mut Self {
        if let Some(parts) = parts(&mut self.parts, &self.err) {
            parts.status = status;
        }
        self
    }

    /// Set a header.
    #[inline]
    pub fn header<K, V>(&mut self, key: K, value: V) -> &mut Self
        where HeaderName: HttpTryFrom<K>,
              HeaderValue: HttpTryFrom<V>
    {
        if let Some(parts) = parts(&mut self.parts, &self.err) {
            match HeaderName::try_from(key) {
                Ok(key) => {
                    match HeaderValue::try_from(value) {
                        Ok(value) => { parts.headers.append(key, value); }
                        Err(e) => self.err = Some(e.into()),
                    }
                },
                Err(e) => self.err = Some(e.into()),
            };
        }
        self
    }

    /// Set the custom reason for the response.
    #[inline]
    pub fn reason(&mut self, reason: &'static str) -> &mut Self {
        if let Some(parts) = parts(&mut self.parts, &self.err) {
            parts.reason = Some(reason);
        }
        self
    }

    /// Set connection type
    pub fn connection_type(&mut self, conn: ConnectionType) -> &mut Self {
        if let Some(parts) = parts(&mut self.parts, &self.err) {
            parts.connection_type = Some(conn);
        }
        self
    }

    /// Set connection type to Upgrade
    pub fn upgrade(&mut self) -> &mut Self {
        self.connection_type(ConnectionType::Upgrade)
    }

    /// Force close connection, even if it is marked as keep-alive
    pub fn force_close(&mut self) -> &mut Self {
        self.connection_type(ConnectionType::Close)
    }

    /// Enables automatic chunked transfer encoding
    pub fn enable_chunked(&mut self) -> &mut Self {
        if let Some(parts) = parts(&mut self.parts, &self.err) {
            parts.chunked = true;
        }
        self
    }

    /// Set response content type
    pub fn content_type<V>(&mut self, value: V) -> &mut Self
        where HeaderValue: HttpTryFrom<V>
    {
        if let Some(parts) = parts(&mut self.parts, &self.err) {
            match HeaderValue::try_from(value) {
                Ok(value) => { parts.headers.insert(header::CONTENT_TYPE, value); },
                Err(e) => self.err = Some(e.into()),
            };
        }
        self
    }

    /* /// Set response content charset
    pub fn charset<V>(&mut self, value: V) -> &mut Self
        where HeaderValue: HttpTryFrom<V>
    {
        if let Some(parts) = parts(&mut self.parts, &self.err) {
            match HeaderValue::try_from(value) {
                Ok(value) => { parts.headers.insert(header::CONTENT_TYPE, value); },
                Err(e) => self.err = Some(e.into()),
            };
        }
        self
    }*/

    /// Set a cookie
    pub fn cookie<'c>(&mut self, cookie: Cookie<'c>) -> &mut Self {
        if let Some(parts) = parts(&mut self.parts, &self.err) {
            parts.cookies.add(cookie.into_owned());
        }
        self
    }

    /// Remote cookie, cookie has to be cookie from `HttpRequest::cookies()` method.
    pub fn del_cookie<'a>(&mut self, cookie: &Cookie<'a>) -> &mut Self {
        if let Some(parts) = parts(&mut self.parts, &self.err) {
            let cookie = cookie.clone().into_owned();
            parts.cookies.add_original(cookie.clone());
            parts.cookies.remove(cookie);
        }
        self
    }

    /// Set a body
    pub fn body<B: Into<Body>>(&mut self, body: B) -> Result<HttpResponse, HttpError> {
        let mut parts = self.parts.take().expect("cannot reuse response builder");
        if let Some(e) = self.err.take() {
            return Err(e)
        }
        for cookie in parts.cookies.delta() {
            parts.headers.append(
                header::SET_COOKIE,
                HeaderValue::from_str(&cookie.to_string())?);
        }
        Ok(HttpResponse {
            version: parts.version,
            headers: parts.headers,
            status: parts.status,
            reason: parts.reason,
            body: body.into(),
            chunked: parts.chunked,
            connection_type: parts.connection_type,
            error: None,
        })
    }
}

fn parts<'a>(parts: &'a mut Option<Parts>, err: &Option<HttpError>) -> Option<&'a mut Parts>
{
    if err.is_some() {
        return None
    }
    parts.as_mut()
}

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

    #[test]
    fn test_body() {
        assert!(Body::Length(10).has_body());
        assert!(Body::Streaming.has_body());
    }

    #[test]
    fn test_upgrade() {
        let resp = HttpResponse::builder(StatusCode::OK)
            .upgrade().body(Body::Empty).unwrap();
        assert!(resp.upgrade())
    }

    #[test]
    fn test_force_close() {
        let resp = HttpResponse::builder(StatusCode::OK)
            .force_close().body(Body::Empty).unwrap();
        assert!(!resp.keep_alive().unwrap())
    }

    #[test]
    fn test_content_type() {
        let resp = HttpResponse::builder(StatusCode::OK)
            .content_type("text/plain").body(Body::Empty).unwrap();
        assert_eq!(resp.headers().get(header::CONTENT_TYPE).unwrap(), "text/plain")
    }
}
<commit_msg>added response's helper method finish<commit_after>//! Pieces pertaining to the HTTP message protocol.
use std::{io, mem, str};
use std::error::Error as Error;
use std::convert::Into;

use cookie::CookieJar;
use http::{StatusCode, Version, HeaderMap, HttpTryFrom, Error as HttpError};
use http::header::{self, HeaderName, HeaderValue};

use Cookie;
use body::Body;

/// Represents various types of connection
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum ConnectionType {
    /// Close connection after response
    Close,
    /// Keep connection alive after response
    KeepAlive,
    /// Connection is upgraded to different type
    Upgrade,
}

#[derive(Debug)]
/// An HTTP Response
pub struct HttpResponse {
    pub version: Option<Version>,
    pub headers: HeaderMap,
    pub status: StatusCode,
    reason: Option<&'static str>,
    body: Body,
    chunked: bool,
    connection_type: Option<ConnectionType>,
    error: Option<Box<Error>>,
}

impl HttpResponse {

    #[inline]
    pub fn builder(status: StatusCode) -> HttpResponseBuilder {
        HttpResponseBuilder {
            parts: Some(Parts::new(status)),
            err: None,
        }
    }

    /// Constructs a response
    #[inline]
    pub fn new(status: StatusCode, body: Body) -> HttpResponse {
        HttpResponse {
            version: None,
            headers: Default::default(),
            status: status,
            reason: None,
            body: body,
            chunked: false,
            // compression: None,
            connection_type: None,
            error: None,
        }
    }

    /// Constructs a response from error
    #[inline]
    pub fn from_error<E: Error + 'static>(status: StatusCode, error: E) -> HttpResponse {
        HttpResponse {
            version: None,
            headers: Default::default(),
            status: status,
            reason: None,
            body: Body::from_slice(error.description().as_ref()),
            chunked: false,
            // compression: None,
            connection_type: None,
            error: Some(Box::new(error)),
        }
    }

    /// The `error` which is responsible for this response
    #[inline]
    #[cfg_attr(feature="cargo-clippy", allow(borrowed_box))]
    pub fn error(&self) -> Option<&Box<Error>> {
        self.error.as_ref()
    }

    /// Get the HTTP version of this response.
    #[inline]
    pub fn version(&self) -> Option<Version> {
        self.version
    }

    /// Get the headers from the response.
    #[inline]
    pub fn headers(&self) -> &HeaderMap {
        &self.headers
    }

    /// Get a mutable reference to the headers.
    #[inline]
    pub fn headers_mut(&mut self) -> &mut HeaderMap {
        &mut self.headers
    }

    /// Get the status from the server.
    #[inline]
    pub fn status(&self) -> StatusCode {
        self.status
    }

    /// Set the `StatusCode` for this response.
    #[inline]
    pub fn status_mut(&mut self) -> &mut StatusCode {
        &mut self.status
    }

    /// Get custom reason for the response.
    #[inline]
    pub fn reason(&self) -> &str {
        if let Some(reason) = self.reason {
            reason
        } else {
            ""
        }
    }

    /// Set the custom reason for the response.
    #[inline]
    pub fn set_reason(&mut self, reason: &'static str) -> &mut Self {
        self.reason = Some(reason);
        self
    }

    /// Set connection type
    pub fn set_connection_type(&mut self, conn: ConnectionType) -> &mut Self {
        self.connection_type = Some(conn);
        self
    }

    /// Connection upgrade status
    pub fn upgrade(&self) -> bool {
        self.connection_type == Some(ConnectionType::Upgrade)
    }

    /// Keep-alive status for this connection
    pub fn keep_alive(&self) -> Option<bool> {
        if let Some(ct) = self.connection_type {
            match ct {
                ConnectionType::KeepAlive => Some(true),
                ConnectionType::Close | ConnectionType::Upgrade => Some(false),
            }
        } else {
            None
        }
    }

    /// is chunked encoding enabled
    pub fn chunked(&self) -> bool {
        self.chunked
    }

    /// Enables automatic chunked transfer encoding
    pub fn enable_chunked_encoding(&mut self) -> Result<(), io::Error> {
        if self.headers.contains_key(header::CONTENT_LENGTH) {
            Err(io::Error::new(io::ErrorKind::Other,
                "You can't enable chunked encoding when a content length is set"))
        } else {
            self.chunked = true;
            Ok(())
        }
    }

    /// Get body os this response
    pub fn body(&self) -> &Body {
        &self.body
    }

    /// Set a body
    pub fn set_body<B: Into<Body>>(&mut self, body: B) {
        self.body = body.into();
    }

    /// Set a body and return previous body value
    pub fn replace_body<B: Into<Body>>(&mut self, body: B) -> Body {
        mem::replace(&mut self.body, body.into())
    }
}

/// Helper conversion implementation
impl<I: Into<HttpResponse>, E: Into<HttpResponse>> From<Result<I, E>> for HttpResponse {
    fn from(res: Result<I, E>) -> Self {
        match res {
            Ok(val) => val.into(),
            Err(err) => err.into(),
        }
    }
}

#[derive(Debug)]
struct Parts {
    version: Option<Version>,
    headers: HeaderMap,
    status: StatusCode,
    reason: Option<&'static str>,
    chunked: bool,
    connection_type: Option<ConnectionType>,
    cookies: CookieJar,
}

impl Parts {
    fn new(status: StatusCode) -> Self {
        Parts {
            version: None,
            headers: HeaderMap::new(),
            status: status,
            reason: None,
            chunked: false,
            connection_type: None,
            cookies: CookieJar::new(),
        }
    }
}

/// An HTTP response builder
///
/// This type can be used to construct an instance of `HttpResponse` through a
/// builder-like pattern.
#[derive(Debug)]
pub struct HttpResponseBuilder {
    parts: Option<Parts>,
    err: Option<HttpError>,
}

impl HttpResponseBuilder {
    /// Get the HTTP version of this response.
    #[inline]
    pub fn version(&mut self, version: Version) -> &mut Self {
        if let Some(parts) = parts(&mut self.parts, &self.err) {
            parts.version = Some(version);
        }
        self
    }

    /// Set the `StatusCode` for this response.
    #[inline]
    pub fn status(&mut self, status: StatusCode) -> &mut Self {
        if let Some(parts) = parts(&mut self.parts, &self.err) {
            parts.status = status;
        }
        self
    }

    /// Set a header.
    #[inline]
    pub fn header<K, V>(&mut self, key: K, value: V) -> &mut Self
        where HeaderName: HttpTryFrom<K>,
              HeaderValue: HttpTryFrom<V>
    {
        if let Some(parts) = parts(&mut self.parts, &self.err) {
            match HeaderName::try_from(key) {
                Ok(key) => {
                    match HeaderValue::try_from(value) {
                        Ok(value) => { parts.headers.append(key, value); }
                        Err(e) => self.err = Some(e.into()),
                    }
                },
                Err(e) => self.err = Some(e.into()),
            };
        }
        self
    }

    /// Set the custom reason for the response.
    #[inline]
    pub fn reason(&mut self, reason: &'static str) -> &mut Self {
        if let Some(parts) = parts(&mut self.parts, &self.err) {
            parts.reason = Some(reason);
        }
        self
    }

    /// Set connection type
    pub fn connection_type(&mut self, conn: ConnectionType) -> &mut Self {
        if let Some(parts) = parts(&mut self.parts, &self.err) {
            parts.connection_type = Some(conn);
        }
        self
    }

    /// Set connection type to Upgrade
    pub fn upgrade(&mut self) -> &mut Self {
        self.connection_type(ConnectionType::Upgrade)
    }

    /// Force close connection, even if it is marked as keep-alive
    pub fn force_close(&mut self) -> &mut Self {
        self.connection_type(ConnectionType::Close)
    }

    /// Enables automatic chunked transfer encoding
    pub fn enable_chunked(&mut self) -> &mut Self {
        if let Some(parts) = parts(&mut self.parts, &self.err) {
            parts.chunked = true;
        }
        self
    }

    /// Set response content type
    pub fn content_type<V>(&mut self, value: V) -> &mut Self
        where HeaderValue: HttpTryFrom<V>
    {
        if let Some(parts) = parts(&mut self.parts, &self.err) {
            match HeaderValue::try_from(value) {
                Ok(value) => { parts.headers.insert(header::CONTENT_TYPE, value); },
                Err(e) => self.err = Some(e.into()),
            };
        }
        self
    }

    /* /// Set response content charset
    pub fn charset<V>(&mut self, value: V) -> &mut Self
        where HeaderValue: HttpTryFrom<V>
    {
        if let Some(parts) = parts(&mut self.parts, &self.err) {
            match HeaderValue::try_from(value) {
                Ok(value) => { parts.headers.insert(header::CONTENT_TYPE, value); },
                Err(e) => self.err = Some(e.into()),
            };
        }
        self
    }*/

    /// Set a cookie
    pub fn cookie<'c>(&mut self, cookie: Cookie<'c>) -> &mut Self {
        if let Some(parts) = parts(&mut self.parts, &self.err) {
            parts.cookies.add(cookie.into_owned());
        }
        self
    }

    /// Remote cookie, cookie has to be cookie from `HttpRequest::cookies()` method.
    pub fn del_cookie<'a>(&mut self, cookie: &Cookie<'a>) -> &mut Self {
        if let Some(parts) = parts(&mut self.parts, &self.err) {
            let cookie = cookie.clone().into_owned();
            parts.cookies.add_original(cookie.clone());
            parts.cookies.remove(cookie);
        }
        self
    }

    /// Set a body
    pub fn body<B: Into<Body>>(&mut self, body: B) -> Result<HttpResponse, HttpError> {
        let mut parts = self.parts.take().expect("cannot reuse response builder");
        if let Some(e) = self.err.take() {
            return Err(e)
        }
        for cookie in parts.cookies.delta() {
            parts.headers.append(
                header::SET_COOKIE,
                HeaderValue::from_str(&cookie.to_string())?);
        }
        Ok(HttpResponse {
            version: parts.version,
            headers: parts.headers,
            status: parts.status,
            reason: parts.reason,
            body: body.into(),
            chunked: parts.chunked,
            connection_type: parts.connection_type,
            error: None,
        })
    }

    /// Set an empty body
    pub fn finish(&mut self) -> Result<HttpResponse, HttpError> {
        self.body(Body::Empty)
    }
}

fn parts<'a>(parts: &'a mut Option<Parts>, err: &Option<HttpError>) -> Option<&'a mut Parts>
{
    if err.is_some() {
        return None
    }
    parts.as_mut()
}

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

    #[test]
    fn test_body() {
        assert!(Body::Length(10).has_body());
        assert!(Body::Streaming.has_body());
    }

    #[test]
    fn test_upgrade() {
        let resp = HttpResponse::builder(StatusCode::OK)
            .upgrade().body(Body::Empty).unwrap();
        assert!(resp.upgrade())
    }

    #[test]
    fn test_force_close() {
        let resp = HttpResponse::builder(StatusCode::OK)
            .force_close().body(Body::Empty).unwrap();
        assert!(!resp.keep_alive().unwrap())
    }

    #[test]
    fn test_content_type() {
        let resp = HttpResponse::builder(StatusCode::OK)
            .content_type("text/plain").body(Body::Empty).unwrap();
        assert_eq!(resp.headers().get(header::CONTENT_TYPE).unwrap(), "text/plain")
    }
}
<|endoftext|>