<commit_before>use sys;

use JoystickSubsystem;
use get_error;
use clear_error;
use std::ffi::{CString, CStr, NulError};
use std::fmt::{Display, Formatter, Error};
use libc::c_char;
use common::{validate_int, IntegerOrSdlError};

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

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

    /// Attempt to open the joystick at index `joystick_index` and return it.
    pub fn open(&self, joystick_index: u32)
            -> Result<Joystick, IntegerOrSdlError> {
        use common::IntegerOrSdlError::*;
        let joystick_index = try!(validate_int(joystick_index, "joystick_index"));

        let joystick = unsafe { sys::SDL_JoystickOpen(joystick_index) };

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

    /// Return the name of the joystick at index `joystick_index`.
    pub fn name_for_index(&self, joystick_index: u32) -> Result<String, IntegerOrSdlError> {
        use common::IntegerOrSdlError::*;
        let joystick_index = try!(validate_int(joystick_index, "joystick_index"));

        let c_str = unsafe { sys::SDL_JoystickNameForIndex(joystick_index) };

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

    /// Get the GUID for the joystick at index `joystick_index`
    pub fn device_guid(&self, joystick_index: u32) -> Result<Guid, IntegerOrSdlError> {
        use common::IntegerOrSdlError::*;
        let joystick_index = try!(validate_int(joystick_index, "joystick_index"));

        let raw = unsafe { sys::SDL_JoystickGetDeviceGUID(joystick_index) };

        let guid = Guid { raw: raw };

        if guid.is_zero() {
            Err(SdlError(get_error()))
        } else {
            Ok(guid)
        }
    }

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

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

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

}

/// Wrapper around the `SDL_Joystick` object
pub struct Joystick {
    subsystem: JoystickSubsystem,
    raw: *mut sys::SDL_Joystick
}

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

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

        c_str_to_string(name)
    }

    /// Return true if the joystick has been opened and currently
    /// connected.
    pub fn attached(&self) -> bool {
        unsafe { sys::SDL_JoystickGetAttached(self.raw) != sys::SDL_bool::SDL_FALSE }
    }

    pub fn instance_id(&self) -> i32 {
        let result = unsafe { sys::SDL_JoystickInstanceID(self.raw) };

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

    /// Retrieve the joystick's GUID
    pub fn guid(&self) -> Guid {
        let raw = unsafe { sys::SDL_JoystickGetGUID(self.raw) };

        let guid = Guid { raw: raw };

        if guid.is_zero() {
            // Should only fail if the joystick is NULL.
            panic!(get_error())
        } else {
            guid
        }
    }

    /// Retrieve the number of axes for this joystick
    pub fn num_axes(&self) -> u32 {
        let result = unsafe { sys::SDL_JoystickNumAxes(self.raw) };

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

    /// Gets the position of the given `axis`.
    ///
    /// The function will fail if the joystick doesn't have the provided axis.
    pub fn axis(&self, axis: u32) -> Result<i16, IntegerOrSdlError> {
        use common::IntegerOrSdlError::*;
        // This interface is a bit messed up: 0 is a valid position
        // but can also mean that an error occured. As far as I can
        // tell the only way to know if an error happened is to see if
        // get_error() returns a non-empty string.
        clear_error();

        let axis = try!(validate_int(axis, "axis"));
        let pos = unsafe { sys::SDL_JoystickGetAxis(self.raw, axis) };

        if pos != 0 {
            Ok(pos)
        } else {
            let err = get_error();

            if err.is_empty() {
                Ok(pos)
            } else {
                Err(SdlError(err))
            }
        }
    }

    /// Retrieve the number of buttons for this joystick
    pub fn num_buttons(&self) -> u32 {
        let result = unsafe { sys::SDL_JoystickNumButtons(self.raw) };

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

    /// Return `Ok(true)` if `button` is pressed.
    ///
    /// The function will fail if the joystick doesn't have the provided button.
    pub fn button(&self, button: u32) -> Result<bool, IntegerOrSdlError> {
        use common::IntegerOrSdlError::*;
        // Same deal as axis, 0 can mean both unpressed or
        // error...
        clear_error();

        let button = try!(validate_int(button, "button"));
        let pressed = unsafe { sys::SDL_JoystickGetButton(self.raw, button) };

        match pressed {
            1 => Ok(true),
            0 => {
                let err = get_error();

                if err.is_empty() {
                    // Button is not pressed
                    Ok(false)
                } else {
                    Err(SdlError(err))
                }
            }
            // Should be unreachable
            _ => unreachable!(),
        }
    }

    /// Retrieve the number of balls for this joystick
    pub fn num_balls(&self) -> u32 {
        let result = unsafe { sys::SDL_JoystickNumBalls(self.raw) };

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

    /// Return a pair `(dx, dy)` containing the difference in axis
    /// position since the last poll
    pub fn ball(&self, ball: u32) -> Result<(i32, i32), IntegerOrSdlError> {
        use common::IntegerOrSdlError::*;
        let mut dx = 0;
        let mut dy = 0;

        let ball = try!(validate_int(ball, "ball"));
        let result = unsafe { sys::SDL_JoystickGetBall(self.raw, ball, &mut dx, &mut dy) };

        if result == 0 {
            Ok((dx, dy))
        } else {
            Err(SdlError(get_error()))
        }
    }

    /// Retrieve the number of balls for this joystick
    pub fn num_hats(&self) -> u32 {
        let result = unsafe { sys::SDL_JoystickNumHats(self.raw) };

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

    /// Return the position of `hat` for this joystick
    pub fn hat(&self, hat: u32) -> Result<HatState, IntegerOrSdlError> {
        use common::IntegerOrSdlError::*;
        // Guess what? This function as well uses 0 to report an error
        // but 0 is also a valid value (HatState::Centered). So we
        // have to use the same hack as `axis`...
        clear_error();

        let hat = try!(validate_int(hat, "hat"));
        let result = unsafe { sys::SDL_JoystickGetHat(self.raw, hat) };

        let state = HatState::from_raw(result as u8);

        if result != 0 {
            Ok(state)
        } else {
            let err = get_error();

            if err.is_empty() {
                Ok(state)
            } else {
                Err(SdlError(err))
            }
        }
    }
}

impl Drop for Joystick {
    fn drop(&mut self) {
        if self.attached() {
            unsafe { sys::SDL_JoystickClose(self.raw) }
        }
    }
}

/// Wrapper around a `SDL_JoystickGUID`, a globally unique identifier
/// for a joystick.
#[derive(Copy, Clone)]
pub struct Guid {
    raw: sys::SDL_JoystickGUID,
}

impl PartialEq for Guid {
    fn eq(&self, other: &Guid) -> bool {
        self.raw.data == other.raw.data
    }
}

impl Eq for Guid {}

impl Guid {
    /// Create a GUID from a string representation.
    pub fn from_string(guid: &str) -> Result<Guid, NulError> {
        let guid = try!(CString::new(guid));

        let raw = unsafe { sys::SDL_JoystickGetGUIDFromString(guid.as_ptr() as *const c_char) };

        Ok(Guid { raw: raw })
    }

    /// Return `true` if GUID is full 0s
    pub fn is_zero(&self) -> bool {
        for &i in &self.raw.data {
            if i != 0 {
                return false;
            }
        }

        true
    }

    /// Return a String representation of GUID
    pub fn string(&self) -> String {
        // Doc says "buf should supply at least 33bytes". I took that
        // to mean that 33bytes should be enough in all cases, but
        // maybe I'm wrong?
        let mut buf = [0; 33];

        let len   = buf.len() as i32;
        let c_str = buf.as_mut_ptr();

        unsafe {
            sys::SDL_JoystickGetGUIDString(self.raw, c_str, len);
        }

        // The buffer should always be NUL terminated (the
        // documentation doesn't explicitly say it but I checked the
        // code)
        if c_str.is_null() {
            String::new()
        } else {
            unsafe {
                CStr::from_ptr(c_str as *const _).to_str().unwrap().to_string()
            }
        }
    }

    /// Return a copy of the internal SDL_JoystickGUID
    pub fn raw(self) -> sys::SDL_JoystickGUID {
        self.raw
    }
}

impl Display for Guid {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        write!(f, "{}", self.string())
    }
}

/// This is represented in SDL2 as a bitfield but obviously not all
/// combinations make sense: 5 for instance would mean up and down at
/// the same time... To simplify things I turn it into an enum which
/// is how the SDL2 docs present it anyway (using macros).
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum HatState {
    Centered  = 0,
    Up        = 0x01,
    Right     = 0x02,
    Down      = 0x04,
    Left      = 0x08,
    RightUp   = 0x02 | 0x01,
    RightDown = 0x02 | 0x04,
    LeftUp    = 0x08 | 0x01,
    LeftDown  = 0x08 | 0x04,
}

impl HatState {
    pub fn from_raw(raw: u8) -> HatState {
        match raw {
            0  => HatState::Centered,
            1  => HatState::Up,
            2  => HatState::Right,
            4  => HatState::Down,
            8  => HatState::Left,
            3  => HatState::RightUp,
            6  => HatState::RightDown,
            9  => HatState::LeftUp,
            12 => HatState::LeftDown,
            _  => panic!("Unexpected hat position: {}", raw),
        }
    }

    pub fn to_raw(&self) -> u8 {
        match *self {
            HatState::Centered => 0,
            HatState::Up => 1,
            HatState::Right => 2,
            HatState::Down => 4,
            HatState::Left => 8,
            HatState::RightUp => 3,
            HatState::RightDown => 6,
            HatState::LeftUp => 9,
            HatState::LeftDown => 12,
        }

    }
}

/// 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 {
        let bytes = unsafe { CStr::from_ptr(c_str as *const _).to_bytes() };

        String::from_utf8_lossy(bytes).to_string()
    }
}
<commit_msg>Add `power_level` method to `Joystick` type<commit_after>use sys;

use JoystickSubsystem;
use get_error;
use clear_error;
use std::ffi::{CString, CStr, NulError};
use std::fmt::{Display, Formatter, Error};
use libc::c_char;
use common::{validate_int, IntegerOrSdlError};

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

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

    /// Attempt to open the joystick at index `joystick_index` and return it.
    pub fn open(&self, joystick_index: u32)
            -> Result<Joystick, IntegerOrSdlError> {
        use common::IntegerOrSdlError::*;
        let joystick_index = try!(validate_int(joystick_index, "joystick_index"));

        let joystick = unsafe { sys::SDL_JoystickOpen(joystick_index) };

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

    /// Return the name of the joystick at index `joystick_index`.
    pub fn name_for_index(&self, joystick_index: u32) -> Result<String, IntegerOrSdlError> {
        use common::IntegerOrSdlError::*;
        let joystick_index = try!(validate_int(joystick_index, "joystick_index"));

        let c_str = unsafe { sys::SDL_JoystickNameForIndex(joystick_index) };

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

    /// Get the GUID for the joystick at index `joystick_index`
    pub fn device_guid(&self, joystick_index: u32) -> Result<Guid, IntegerOrSdlError> {
        use common::IntegerOrSdlError::*;
        let joystick_index = try!(validate_int(joystick_index, "joystick_index"));

        let raw = unsafe { sys::SDL_JoystickGetDeviceGUID(joystick_index) };

        let guid = Guid { raw: raw };

        if guid.is_zero() {
            Err(SdlError(get_error()))
        } else {
            Ok(guid)
        }
    }

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

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

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

}

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[repr(i32)]
pub enum PowerLevel {
    Unknown = sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_UNKNOWN as i32,
    Empty   = sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_EMPTY as i32,
    Low     = sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_LOW as i32,
    Medium  = sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_MEDIUM as i32,
    Full    = sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_FULL as i32,
    Wired   = sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_WIRED as i32,
}

impl PowerLevel {
    pub fn from_ll(raw: sys::SDL_JoystickPowerLevel) -> PowerLevel {
        match raw {
            sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_UNKNOWN => PowerLevel::Unknown,
            sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_EMPTY   => PowerLevel::Empty,
            sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_LOW     => PowerLevel::Low,
            sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_MEDIUM  => PowerLevel::Medium,
            sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_FULL    => PowerLevel::Full,
            sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_WIRED   => PowerLevel::Wired,
            _  => panic!("Unexpected power level: {:?}", raw),
        }
    }

    pub fn to_ll(&self) -> sys::SDL_JoystickPowerLevel {
        match *self {
            PowerLevel::Unknown => sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_UNKNOWN,
            PowerLevel::Empty   => sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_EMPTY,
            PowerLevel::Low     => sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_LOW,
            PowerLevel::Medium  => sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_MEDIUM,
            PowerLevel::Full    => sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_FULL,
            PowerLevel::Wired   => sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_WIRED,
        }

    }
}

/// Wrapper around the `SDL_Joystick` object
pub struct Joystick {
    subsystem: JoystickSubsystem,
    raw: *mut sys::SDL_Joystick
}

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

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

        c_str_to_string(name)
    }

    /// Return true if the joystick has been opened and currently
    /// connected.
    pub fn attached(&self) -> bool {
        unsafe { sys::SDL_JoystickGetAttached(self.raw) != sys::SDL_bool::SDL_FALSE }
    }

    pub fn instance_id(&self) -> i32 {
        let result = unsafe { sys::SDL_JoystickInstanceID(self.raw) };

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

    /// Retrieve the joystick's GUID
    pub fn guid(&self) -> Guid {
        let raw = unsafe { sys::SDL_JoystickGetGUID(self.raw) };

        let guid = Guid { raw: raw };

        if guid.is_zero() {
            // Should only fail if the joystick is NULL.
            panic!(get_error())
        } else {
            guid
        }
    }

    /// Retrieve the battery level of this joystick
    pub fn power_level(&self) -> Result<PowerLevel, IntegerOrSdlError> {
        use common::IntegerOrSdlError::*;
        clear_error();

        let result = unsafe { sys::SDL_JoystickCurrentPowerLevel(self.raw) };

        let state = PowerLevel::from_ll(result);

        if result != sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_UNKNOWN {
            Ok(state)
        } else {
            let err = get_error();

            if err.is_empty() {
                Ok(state)
            } else {
                Err(SdlError(err))
            }
        }
    }

    /// Retrieve the number of axes for this joystick
    pub fn num_axes(&self) -> u32 {
        let result = unsafe { sys::SDL_JoystickNumAxes(self.raw) };

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

    /// Gets the position of the given `axis`.
    ///
    /// The function will fail if the joystick doesn't have the provided axis.
    pub fn axis(&self, axis: u32) -> Result<i16, IntegerOrSdlError> {
        use common::IntegerOrSdlError::*;
        // This interface is a bit messed up: 0 is a valid position
        // but can also mean that an error occured. As far as I can
        // tell the only way to know if an error happened is to see if
        // get_error() returns a non-empty string.
        clear_error();

        let axis = try!(validate_int(axis, "axis"));
        let pos = unsafe { sys::SDL_JoystickGetAxis(self.raw, axis) };

        if pos != 0 {
            Ok(pos)
        } else {
            let err = get_error();

            if err.is_empty() {
                Ok(pos)
            } else {
                Err(SdlError(err))
            }
        }
    }

    /// Retrieve the number of buttons for this joystick
    pub fn num_buttons(&self) -> u32 {
        let result = unsafe { sys::SDL_JoystickNumButtons(self.raw) };

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

    /// Return `Ok(true)` if `button` is pressed.
    ///
    /// The function will fail if the joystick doesn't have the provided button.
    pub fn button(&self, button: u32) -> Result<bool, IntegerOrSdlError> {
        use common::IntegerOrSdlError::*;
        // Same deal as axis, 0 can mean both unpressed or
        // error...
        clear_error();

        let button = try!(validate_int(button, "button"));
        let pressed = unsafe { sys::SDL_JoystickGetButton(self.raw, button) };

        match pressed {
            1 => Ok(true),
            0 => {
                let err = get_error();

                if err.is_empty() {
                    // Button is not pressed
                    Ok(false)
                } else {
                    Err(SdlError(err))
                }
            }
            // Should be unreachable
            _ => unreachable!(),
        }
    }

    /// Retrieve the number of balls for this joystick
    pub fn num_balls(&self) -> u32 {
        let result = unsafe { sys::SDL_JoystickNumBalls(self.raw) };

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

    /// Return a pair `(dx, dy)` containing the difference in axis
    /// position since the last poll
    pub fn ball(&self, ball: u32) -> Result<(i32, i32), IntegerOrSdlError> {
        use common::IntegerOrSdlError::*;
        let mut dx = 0;
        let mut dy = 0;

        let ball = try!(validate_int(ball, "ball"));
        let result = unsafe { sys::SDL_JoystickGetBall(self.raw, ball, &mut dx, &mut dy) };

        if result == 0 {
            Ok((dx, dy))
        } else {
            Err(SdlError(get_error()))
        }
    }

    /// Retrieve the number of balls for this joystick
    pub fn num_hats(&self) -> u32 {
        let result = unsafe { sys::SDL_JoystickNumHats(self.raw) };

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

    /// Return the position of `hat` for this joystick
    pub fn hat(&self, hat: u32) -> Result<HatState, IntegerOrSdlError> {
        use common::IntegerOrSdlError::*;
        // Guess what? This function as well uses 0 to report an error
        // but 0 is also a valid value (HatState::Centered). So we
        // have to use the same hack as `axis`...
        clear_error();

        let hat = try!(validate_int(hat, "hat"));
        let result = unsafe { sys::SDL_JoystickGetHat(self.raw, hat) };

        let state = HatState::from_raw(result as u8);

        if result != 0 {
            Ok(state)
        } else {
            let err = get_error();

            if err.is_empty() {
                Ok(state)
            } else {
                Err(SdlError(err))
            }
        }
    }
}

impl Drop for Joystick {
    fn drop(&mut self) {
        if self.attached() {
            unsafe { sys::SDL_JoystickClose(self.raw) }
        }
    }
}

/// Wrapper around a `SDL_JoystickGUID`, a globally unique identifier
/// for a joystick.
#[derive(Copy, Clone)]
pub struct Guid {
    raw: sys::SDL_JoystickGUID,
}

impl PartialEq for Guid {
    fn eq(&self, other: &Guid) -> bool {
        self.raw.data == other.raw.data
    }
}

impl Eq for Guid {}

impl Guid {
    /// Create a GUID from a string representation.
    pub fn from_string(guid: &str) -> Result<Guid, NulError> {
        let guid = try!(CString::new(guid));

        let raw = unsafe { sys::SDL_JoystickGetGUIDFromString(guid.as_ptr() as *const c_char) };

        Ok(Guid { raw: raw })
    }

    /// Return `true` if GUID is full 0s
    pub fn is_zero(&self) -> bool {
        for &i in &self.raw.data {
            if i != 0 {
                return false;
            }
        }

        true
    }

    /// Return a String representation of GUID
    pub fn string(&self) -> String {
        // Doc says "buf should supply at least 33bytes". I took that
        // to mean that 33bytes should be enough in all cases, but
        // maybe I'm wrong?
        let mut buf = [0; 33];

        let len   = buf.len() as i32;
        let c_str = buf.as_mut_ptr();

        unsafe {
            sys::SDL_JoystickGetGUIDString(self.raw, c_str, len);
        }

        // The buffer should always be NUL terminated (the
        // documentation doesn't explicitly say it but I checked the
        // code)
        if c_str.is_null() {
            String::new()
        } else {
            unsafe {
                CStr::from_ptr(c_str as *const _).to_str().unwrap().to_string()
            }
        }
    }

    /// Return a copy of the internal SDL_JoystickGUID
    pub fn raw(self) -> sys::SDL_JoystickGUID {
        self.raw
    }
}

impl Display for Guid {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        write!(f, "{}", self.string())
    }
}

/// This is represented in SDL2 as a bitfield but obviously not all
/// combinations make sense: 5 for instance would mean up and down at
/// the same time... To simplify things I turn it into an enum which
/// is how the SDL2 docs present it anyway (using macros).
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum HatState {
    Centered  = 0,
    Up        = 0x01,
    Right     = 0x02,
    Down      = 0x04,
    Left      = 0x08,
    RightUp   = 0x02 | 0x01,
    RightDown = 0x02 | 0x04,
    LeftUp    = 0x08 | 0x01,
    LeftDown  = 0x08 | 0x04,
}

impl HatState {
    pub fn from_raw(raw: u8) -> HatState {
        match raw {
            0  => HatState::Centered,
            1  => HatState::Up,
            2  => HatState::Right,
            4  => HatState::Down,
            8  => HatState::Left,
            3  => HatState::RightUp,
            6  => HatState::RightDown,
            9  => HatState::LeftUp,
            12 => HatState::LeftDown,
            _  => panic!("Unexpected hat position: {}", raw),
        }
    }

    pub fn to_raw(&self) -> u8 {
        match *self {
            HatState::Centered => 0,
            HatState::Up => 1,
            HatState::Right => 2,
            HatState::Down => 4,
            HatState::Left => 8,
            HatState::RightUp => 3,
            HatState::RightDown => 6,
            HatState::LeftUp => 9,
            HatState::LeftDown => 12,
        }

    }
}

/// 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 {
        let bytes = unsafe { CStr::from_ptr(c_str as *const _).to_bytes() };

        String::from_utf8_lossy(bytes).to_string()
    }
}
<|endoftext|>


<commit_before>use crate::{Point, Value};

/// Resolve the points to line protocol format
pub(crate) fn line_serialization<T: Iterator<Item = Point>>(points: T) -> String {
    let mut line = Vec::new();
    for point in points {
        line.push(escape_measurement(&point.measurement));

        for (tag, value) in point.tags {
            line.push(",".to_string());
            line.push(escape_keys_and_tags(&tag));
            line.push("=".to_string());

            match value {
                Value::String(s) => line.push(escape_keys_and_tags(&s)),
                Value::Float(f) => line.push(f.to_string()),
                Value::Integer(i) => line.push(i.to_string() + "i"),
                Value::Boolean(b) => line.push({
                    if b {
                        "true".to_string()
                    } else {
                        "false".to_string()
                    }
                }),
            }
        }

        let mut was_first = true;

        for (field, value) in point.fields {
            line.push(
                {
                    if was_first {
                        was_first = false;
                        " "
                    } else {
                        ","
                    }
                }
                .to_string(),
            );
            line.push(escape_keys_and_tags(&field));
            line.push("=".to_string());

            match value {
                Value::String(s) => {
                    line.push(escape_string_field_value(&s.replace("\\\"", "\\\\\"")))
                }
                Value::Float(f) => line.push(f.to_string()),
                Value::Integer(i) => line.push(i.to_string() + "i"),
                Value::Boolean(b) => line.push({
                    if b {
                        "true".to_string()
                    } else {
                        "false".to_string()
                    }
                }),
            }
        }

        if let Some(t) = point.timestamp {
            line.push(" ".to_string());
            line.push(t.to_string());
        }

        line.push("\n".to_string())
    }

    line.join("")
}

#[inline]
pub(crate) fn quote_ident(value: &str) -> String {
    format!(
        "\"{}\"",
        value
            .replace("\\", "\\\\")
            .replace("\"", "\\\"")
            .replace("\n", "\\n")
    )
}

#[inline]
pub(crate) fn quote_literal(value: &str) -> String {
    format!("'{}'", value.replace("\\", "\\\\").replace("'", "\\'"))
}

#[inline]
pub(crate) fn conversion(value: &str) -> String {
    value
        .replace("\'", "")
        .replace("\"", "")
        .replace("\\", "")
        .trim()
        .to_string()
}

#[inline]
fn escape_keys_and_tags(value: &str) -> String {
    value
        .replace(",", "\\,")
        .replace("=", "\\=")
        .replace(" ", "\\ ")
}

#[inline]
fn escape_measurement(value: &str) -> String {
    value.replace(",", "\\,").replace(" ", "\\ ")
}

#[inline]
fn escape_string_field_value(value: &str) -> String {
    format!("\"{}\"", value.replace("\"", "\\\""))
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::{Point, Points};

    #[test]
    fn line_serialization_test() {
        let point = Point::new("test")
            .add_field("somefield", Value::Integer(65))
            .add_tag("sometag", Value::Boolean(false));
        let points = Points::new(point);

        assert_eq!(
            line_serialization(points),
            "test,sometag=false somefield=65i\n"
        )
    }

    #[test]
    fn escape_keys_and_tags_test() {
        assert_eq!(
            escape_keys_and_tags("foo, hello=world"),
            "foo\\,\\ hello\\=world"
        )
    }

    #[test]
    fn escape_measurement_test() {
        assert_eq!(escape_measurement("foo, hello"), "foo\\,\\ hello")
    }

    #[test]
    fn escape_string_field_value_test() {
        assert_eq!(escape_string_field_value("\"foo"), "\"\\\"foo\"")
    }

    #[test]
    fn quote_ident_test() {
        assert_eq!(quote_ident("root"), "\"root\"")
    }

    #[test]
    fn quote_literal_test() {
        assert_eq!(quote_literal("root"), "\'root\'")
    }
}
<commit_msg>removed 'i' char added to integer serilization<commit_after>use crate::{Point, Value};

/// Resolve the points to line protocol format
pub(crate) fn line_serialization<T: Iterator<Item = Point>>(points: T) -> String {
    let mut line = Vec::new();
    for point in points {
        line.push(escape_measurement(&point.measurement));

        for (tag, value) in point.tags {
            line.push(",".to_string());
            line.push(escape_keys_and_tags(&tag));
            line.push("=".to_string());

            match value {
                Value::String(s) => line.push(escape_keys_and_tags(&s)),
                Value::Float(f) => line.push(f.to_string()),
                Value::Integer(i) => line.push(i.to_string()),
                Value::Boolean(b) => line.push({
                    if b {
                        "true".to_string()
                    } else {
                        "false".to_string()
                    }
                }),
            }
        }

        let mut was_first = true;

        for (field, value) in point.fields {
            line.push(
                {
                    if was_first {
                        was_first = false;
                        " "
                    } else {
                        ","
                    }
                }
                .to_string(),
            );
            line.push(escape_keys_and_tags(&field));
            line.push("=".to_string());

            match value {
                Value::String(s) => {
                    line.push(escape_string_field_value(&s.replace("\\\"", "\\\\\"")))
                }
                Value::Float(f) => line.push(f.to_string()),
                Value::Integer(i) => line.push(i.to_string() + "i"),
                Value::Boolean(b) => line.push({
                    if b {
                        "true".to_string()
                    } else {
                        "false".to_string()
                    }
                }),
            }
        }

        if let Some(t) = point.timestamp {
            line.push(" ".to_string());
            line.push(t.to_string());
        }

        line.push("\n".to_string())
    }

    line.join("")
}

#[inline]
pub(crate) fn quote_ident(value: &str) -> String {
    format!(
        "\"{}\"",
        value
            .replace("\\", "\\\\")
            .replace("\"", "\\\"")
            .replace("\n", "\\n")
    )
}

#[inline]
pub(crate) fn quote_literal(value: &str) -> String {
    format!("'{}'", value.replace("\\", "\\\\").replace("'", "\\'"))
}

#[inline]
pub(crate) fn conversion(value: &str) -> String {
    value
        .replace("\'", "")
        .replace("\"", "")
        .replace("\\", "")
        .trim()
        .to_string()
}

#[inline]
fn escape_keys_and_tags(value: &str) -> String {
    value
        .replace(",", "\\,")
        .replace("=", "\\=")
        .replace(" ", "\\ ")
}

#[inline]
fn escape_measurement(value: &str) -> String {
    value.replace(",", "\\,").replace(" ", "\\ ")
}

#[inline]
fn escape_string_field_value(value: &str) -> String {
    format!("\"{}\"", value.replace("\"", "\\\""))
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::{Point, Points};

    #[test]
    fn line_serialization_test() {
        let point = Point::new("test")
            .add_field("somefield", Value::Integer(65))
            .add_tag("sometag", Value::Boolean(false));
        let points = Points::new(point);

        assert_eq!(
            line_serialization(points),
            "test,sometag=false somefield=65i\n"
        )
    }

    #[test]
    fn escape_keys_and_tags_test() {
        assert_eq!(
            escape_keys_and_tags("foo, hello=world"),
            "foo\\,\\ hello\\=world"
        )
    }

    #[test]
    fn escape_measurement_test() {
        assert_eq!(escape_measurement("foo, hello"), "foo\\,\\ hello")
    }

    #[test]
    fn escape_string_field_value_test() {
        assert_eq!(escape_string_field_value("\"foo"), "\"\\\"foo\"")
    }

    #[test]
    fn quote_ident_test() {
        assert_eq!(quote_ident("root"), "\"root\"")
    }

    #[test]
    fn quote_literal_test() {
        assert_eq!(quote_literal("root"), "\'root\'")
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-tidy-linelength

#![crate_name = "foo"]

#![doc(html_playground_url = "https://www.example.com/")]

//! module docs
//!
//! ```
//! println!("Hello, world!");
//! ```
//!
//! ```
//! fn main() {
//!     println!("Hello, world!");
//! }
//! ```
//!
//! ```
//! #![feature(something)]
//!
//! fn main() {
//!     println!("Hello, world!");
//! }
//! ```

// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D%0A"]' "Run"
// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn%20main()%20%7B%0Aprintln!(%22Hello%2C%20world!%22)%3B%0A%7D"]' "Run"
// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0A%23!%5Bfeature(something)%5D%0A%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D%0A&version=nightly"]' "Run"
<commit_msg>fix playground test for newly-trimmed doctests<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-tidy-linelength

#![crate_name = "foo"]

#![doc(html_playground_url = "https://www.example.com/")]

//! module docs
//!
//! ```
//! println!("Hello, world!");
//! ```
//!
//! ```
//! fn main() {
//!     println!("Hello, world!");
//! }
//! ```
//!
//! ```
//! #![feature(something)]
//!
//! fn main() {
//!     println!("Hello, world!");
//! }
//! ```

// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D"]' "Run"
// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn%20main()%20%7B%0Aprintln!(%22Hello%2C%20world!%22)%3B%0A%7D"]' "Run"
// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0A%23!%5Bfeature(something)%5D%0A%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D&version=nightly"]' "Run"
<|endoftext|>


<commit_before>//! Code common to structs, unions, and enum variants.

use crate::render::RenderContext;
use hir::{db::HirDatabase, HasAttrs, HasVisibility, HirDisplay};
use ide_db::SnippetCap;
use itertools::Itertools;

/// A rendered struct, union, or enum variant, split into fields for actual
/// auto-completion (`literal`, using `field: ()`) and display in the
/// completions menu (`detail`, using `field: type`).
pub(crate) struct RenderedCompound {
    pub(crate) literal: String,
    pub(crate) detail: String,
}

/// Render a record type (or sub-type) to a `RenderedCompound`. Use `None` for
/// the `name` argument for an anonymous type.
pub(crate) fn render_record(
    db: &dyn HirDatabase,
    snippet_cap: Option<SnippetCap>,
    fields: &[hir::Field],
    name: Option<&str>,
) -> RenderedCompound {
    let fields = fields.iter();

    let (completions, types): (Vec<_>, Vec<_>) = fields
        .enumerate()
        .map(|(idx, field)| {
            (
                if snippet_cap.is_some() {
                    format!("{}: ${{{}:()}}", field.name(db), idx + 1)
                } else {
                    format!("{}: ()", field.name(db))
                },
                format!("{}: {}", field.name(db), field.ty(db).display(db)),
            )
        })
        .unzip();
    RenderedCompound {
        literal: format!("{} {{ {} }}", name.unwrap_or(""), completions.iter().format(", ")),
        detail: format!("{} {{ {} }}", name.unwrap_or(""), types.iter().format(", ")),
    }
}

/// Render a tuple type (or sub-type) to a `RenderedCompound`. Use `None` for
/// the `name` argument for an anonymous type.
pub(crate) fn render_tuple(
    db: &dyn HirDatabase,
    snippet_cap: Option<SnippetCap>,
    fields: &[hir::Field],
    name: Option<&str>,
) -> RenderedCompound {
    let fields = fields.iter();

    let (completions, types): (Vec<_>, Vec<_>) = fields
        .enumerate()
        .map(|(idx, field)| {
            (
                if snippet_cap.is_some() {
                    format!("${{{}:()}}", (idx + 1).to_string())
                } else {
                    "()".to_string()
                },
                field.ty(db).display(db).to_string(),
            )
        })
        .unzip();
    RenderedCompound {
        literal: format!("{}({})", name.unwrap_or(""), completions.iter().format(", ")),
        detail: format!("{}({})", name.unwrap_or(""), types.iter().format(", ")),
    }
}

/// Find all the visible fields in a `HasAttrs`. Returns the list of visible
/// fields, plus a boolean for whether the list is comprehensive (contains no
/// private fields and is not marked `#[non_exhaustive]`).
pub(crate) fn visible_fields(
    ctx: &RenderContext<'_>,
    fields: &[hir::Field],
    item: impl HasAttrs,
) -> Option<(Vec<hir::Field>, bool)> {
    let module = ctx.completion.module?;
    let n_fields = fields.len();
    let fields = fields
        .iter()
        .filter(|field| field.is_visible_from(ctx.db(), module))
        .copied()
        .collect::<Vec<_>>();

    let fields_omitted =
        n_fields - fields.len() > 0 || item.attrs(ctx.db()).by_key("non_exhaustive").exists();
    Some((fields, fields_omitted))
}
<commit_msg>make the doc comment on render::compound::visible_fields a little better<commit_after>//! Code common to structs, unions, and enum variants.

use crate::render::RenderContext;
use hir::{db::HirDatabase, HasAttrs, HasVisibility, HirDisplay};
use ide_db::SnippetCap;
use itertools::Itertools;

/// A rendered struct, union, or enum variant, split into fields for actual
/// auto-completion (`literal`, using `field: ()`) and display in the
/// completions menu (`detail`, using `field: type`).
pub(crate) struct RenderedCompound {
    pub(crate) literal: String,
    pub(crate) detail: String,
}

/// Render a record type (or sub-type) to a `RenderedCompound`. Use `None` for
/// the `name` argument for an anonymous type.
pub(crate) fn render_record(
    db: &dyn HirDatabase,
    snippet_cap: Option<SnippetCap>,
    fields: &[hir::Field],
    name: Option<&str>,
) -> RenderedCompound {
    let fields = fields.iter();

    let (completions, types): (Vec<_>, Vec<_>) = fields
        .enumerate()
        .map(|(idx, field)| {
            (
                if snippet_cap.is_some() {
                    format!("{}: ${{{}:()}}", field.name(db), idx + 1)
                } else {
                    format!("{}: ()", field.name(db))
                },
                format!("{}: {}", field.name(db), field.ty(db).display(db)),
            )
        })
        .unzip();
    RenderedCompound {
        literal: format!("{} {{ {} }}", name.unwrap_or(""), completions.iter().format(", ")),
        detail: format!("{} {{ {} }}", name.unwrap_or(""), types.iter().format(", ")),
    }
}

/// Render a tuple type (or sub-type) to a `RenderedCompound`. Use `None` for
/// the `name` argument for an anonymous type.
pub(crate) fn render_tuple(
    db: &dyn HirDatabase,
    snippet_cap: Option<SnippetCap>,
    fields: &[hir::Field],
    name: Option<&str>,
) -> RenderedCompound {
    let fields = fields.iter();

    let (completions, types): (Vec<_>, Vec<_>) = fields
        .enumerate()
        .map(|(idx, field)| {
            (
                if snippet_cap.is_some() {
                    format!("${{{}:()}}", (idx + 1).to_string())
                } else {
                    "()".to_string()
                },
                field.ty(db).display(db).to_string(),
            )
        })
        .unzip();
    RenderedCompound {
        literal: format!("{}({})", name.unwrap_or(""), completions.iter().format(", ")),
        detail: format!("{}({})", name.unwrap_or(""), types.iter().format(", ")),
    }
}

/// Find all the visible fields in a given list. Returns the list of visible
/// fields, plus a boolean for whether the list is comprehensive (contains no
/// private fields and its item is not marked `#[non_exhaustive]`).
pub(crate) fn visible_fields(
    ctx: &RenderContext<'_>,
    fields: &[hir::Field],
    item: impl HasAttrs,
) -> Option<(Vec<hir::Field>, bool)> {
    let module = ctx.completion.module?;
    let n_fields = fields.len();
    let fields = fields
        .iter()
        .filter(|field| field.is_visible_from(ctx.db(), module))
        .copied()
        .collect::<Vec<_>>();

    let fields_omitted =
        n_fields - fields.len() > 0 || item.attrs(ctx.db()).by_key("non_exhaustive").exists();
    Some((fields, fields_omitted))
}
<|endoftext|>


<commit_before>// Copyright (C) 2016-2017 Sebastian Dröge <sebastian@centricular.com>
//               2018 François Laignel <fengalin@free.fr>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use glib;
use glib::subclass;
use glib::subclass::prelude::*;
use gst;
use gst::prelude::*;
use gst::subclass::prelude::*;
use gst_base;
use gst_base::subclass::prelude::*;

use std::fs::File;
use std::io::{Read, Seek, SeekFrom};
use std::sync::Mutex;

use url::Url;

use file_location::FileLocation;

const DEFAULT_LOCATION: Option<FileLocation> = None;

#[derive(Debug)]
struct Settings {
    location: Option<FileLocation>,
}

impl Default for Settings {
    fn default() -> Self {
        Settings {
            location: DEFAULT_LOCATION,
        }
    }
}

static PROPERTIES: [subclass::Property; 1] = [subclass::Property("location", |name| {
    glib::ParamSpec::string(
        name,
        "File Location",
        "Location of the file to read from",
        None,
        glib::ParamFlags::READWRITE,
    )
})];

enum State {
    Stopped,
    Started { file: File, position: u64 },
}

impl Default for State {
    fn default() -> State {
        State::Stopped
    }
}

pub struct FileSrc {
    cat: gst::DebugCategory,
    settings: Mutex<Settings>,
    state: Mutex<State>,
}

impl FileSrc {
    fn set_location(
        &self,
        element: &gst_base::BaseSrc,
        location: Option<FileLocation>,
    ) -> Result<(), glib::Error> {
        let state = self.state.lock().unwrap();
        if let State::Started { .. } = *state {
            return Err(gst::Error::new(
                gst::LibraryError::Failed,
                "Changing the `location` property on a started `filesrc` is not supported",
            ));
        }

        let mut settings = self.settings.lock().unwrap();
        settings.location = match location {
            Some(location) => {
                if !location.exists() {
                    return Err(gst::Error::new(
                        gst::LibraryError::Failed,
                        format!("{} doesn't exist", location).as_str(),
                    ));
                }

                if !location.is_file() {
                    return Err(gst::Error::new(
                        gst::LibraryError::Failed,
                        format!("{} is not a file", location).as_str(),
                    ));
                }

                match settings.location {
                    Some(ref location_cur) => {
                        gst_info!(
                            self.cat,
                            obj: element,
                            "Changing `location` from {:?} to {}",
                            location_cur,
                            location,
                        );
                    }
                    None => {
                        gst_info!(self.cat, obj: element, "Setting `location to {}", location,);
                    }
                }
                Some(location)
            }
            None => {
                gst_info!(self.cat, obj: element, "Resetting `location` to None",);
                None
            }
        };

        Ok(())
    }
}

impl ObjectSubclass for FileSrc {
    const NAME: &'static str = "RsFileSrc";
    type ParentType = gst_base::BaseSrc;
    type Instance = gst::subclass::ElementInstanceStruct<Self>;
    type Class = subclass::simple::ClassStruct<Self>;

    glib_object_subclass!();

    fn new() -> Self {
        Self {
            cat: gst::DebugCategory::new("rsfilesrc", gst::DebugColorFlags::empty(), "File Source"),
            settings: Mutex::new(Default::default()),
            state: Mutex::new(Default::default()),
        }
    }

    fn type_init(type_: &subclass::InitializingType<Self>) {
        gst::subclass::uri_handler::register(type_);
    }

    fn class_init(klass: &mut subclass::simple::ClassStruct<Self>) {
        klass.set_metadata(
            "File Source",
            "Source/File",
            "Read stream from a file",
            "François Laignel <fengalin@free.fr>, Sebastian Dröge <sebastian@centricular.com>",
        );

        let caps = gst::Caps::new_any();
        let src_pad_template = gst::PadTemplate::new(
            "src",
            gst::PadDirection::Src,
            gst::PadPresence::Always,
            &caps,
        );
        klass.add_pad_template(src_pad_template);

        klass.install_properties(&PROPERTIES);
    }
}

impl ObjectImpl for FileSrc {
    glib_object_impl!();

    fn set_property(&self, obj: &glib::Object, id: usize, value: &glib::Value) {
        let prop = &PROPERTIES[id];
        match *prop {
            subclass::Property("name", ..) => {
                let element = obj.downcast_ref::<gst_base::BaseSrc>().unwrap();

                let res = match value.get::<String>() {
                    Some(location) => FileLocation::try_from_path_str(location)
                        .and_then(|file_location| self.set_location(&element, Some(file_location))),
                    None => self.set_location(&element, None),
                };

                if let Err(err) = res {
                    gst_error!(
                        self.cat,
                        obj: element,
                        "Failed to set property `location`: {}",
                        err
                    );
                }
            }
            _ => unimplemented!(),
        };
    }

    fn get_property(&self, _obj: &glib::Object, id: usize) -> Result<glib::Value, ()> {
        let prop = &PROPERTIES[id];
        match *prop {
            subclass::Property("name", ..) => {
                let settings = self.settings.lock().unwrap();
                let location = settings
                    .location
                    .as_ref()
                    .map(|location| location.to_string());

                Ok(location.to_value())
            }
            _ => unimplemented!(),
        }
    }
}

impl ElementImpl for FileSrc {}

impl BaseSrcImpl for FileSrc {
    fn is_seekable(&self, _src: &gst_base::BaseSrc) -> bool {
        true
    }

    fn get_size(&self, _src: &gst_base::BaseSrc) -> Option<u64> {
        let state = self.state.lock().unwrap();
        if let State::Started { ref file, .. } = *state {
            file.metadata().ok().map(|m| m.len())
        } else {
            None
        }
    }

    fn start(&self, element: &gst_base::BaseSrc) -> bool {
        let mut state = self.state.lock().unwrap();
        if let State::Started { .. } = *state {
            gst_element_info!(
                element,
                gst::CoreError::StateChange,
                ["FileSrc already started"]
            );
            return false;
        }

        let settings = self.settings.lock().unwrap();
        let location = match settings.location {
            Some(ref location) => location,
            None => {
                gst_element_error!(
                    element,
                    gst::CoreError::StateChange,
                    ["File location is not defined"]
                );
                return false;
            }
        };

        let file = match File::open(location) {
            Ok(file) => file,
            Err(err) => {
                gst_element_error!(
                    element,
                    gst::ResourceError::OpenRead,
                    [
                        "Could not open file {} for reading: {}",
                        location,
                        err.to_string(),
                    ]
                );
                return false;
            }
        };

        gst_debug!(self.cat, obj: element, "Opened file {:?}", file);

        *state = State::Started { file, position: 0 };

        gst_info!(self.cat, obj: element, "Started");

        true
    }

    fn stop(&self, element: &gst_base::BaseSrc) -> bool {
        let mut state = self.state.lock().unwrap();
        if let State::Stopped = *state {
            gst_element_warning!(
                element,
                gst::CoreError::StateChange,
                ["FileSink not started"]
            );
            return false;
        }

        *state = State::Stopped;

        gst_info!(self.cat, obj: element, "Stopped");

        true
    }

    fn create(
        &self,
        element: &gst_base::BaseSrc,
        offset: u64,
        length: u32,
    ) -> Result<gst::Buffer, gst::FlowError> {
        let mut state = self.state.lock().unwrap();

        let (file, position) = match *state {
            State::Started {
                ref mut file,
                ref mut position,
            } => (file, position),
            State::Stopped => {
                gst_element_error!(element, gst::CoreError::Failed, ["Not started yet"]);
                return Err(gst::FlowError::Error);
            }
        };

        if *position != offset {
            file.seek(SeekFrom::Start(offset)).map_err(|err| {
                gst_element_error!(
                    element,
                    gst::LibraryError::Failed,
                    ["Failed to seek to {}: {}", offset, err.to_string()]
                );
                gst::FlowError::Error
            })?;

            *position = offset;
        }

        let mut buffer = match gst::Buffer::with_size(length as usize) {
            Some(buffer) => buffer,
            None => {
                gst_element_error!(
                    element,
                    gst::LibraryError::Failed,
                    ["Failed to allocate buffer"]
                );
                return Err(gst::FlowError::Error);
            }
        };

        {
            let buffer = buffer.make_mut();
            let size = {
                let mut map = match buffer.map_writable() {
                    Some(map) => map,
                    None => {
                        gst_element_error!(
                            element,
                            gst::LibraryError::Failed,
                            ["Failed to map buffer"]
                        );
                        return Err(gst::FlowError::Error);
                    }
                };

                file.read(map.as_mut()).map_err(|err| {
                    gst_element_error!(
                        element,
                        gst::LibraryError::Failed,
                        ["Failed to read at {}: {}", offset, err.to_string()]
                    );
                    gst::FlowError::Error
                })?
            };

            *position += size as u64;

            buffer.set_size(size);
        }

        Ok(buffer)
    }
}

impl URIHandlerImpl for FileSrc {
    fn get_uri(&self, _element: &gst::URIHandler) -> Option<String> {
        let settings = self.settings.lock().unwrap();

        // Conversion to Url already checked while building the `FileLocation`
        settings.location.as_ref().map(|location| {
            Url::from_file_path(location)
                .expect("FileSrc::get_uri couldn't build `Url` from `location`")
                .into_string()
        })
    }

    fn set_uri(&self, element: &gst::URIHandler, uri: Option<String>) -> Result<(), glib::Error> {
        let element = element.dynamic_cast_ref::<gst_base::BaseSrc>().unwrap();

        // Special case for "file://" as this is used by some applications to test
        // with `gst_element_make_from_uri` if there's an element that supports the URI protocol
        let uri = uri.filter(|uri| uri != "file://");

        let file_location = match uri {
            Some(uri) => Some(FileLocation::try_from_uri_str(&uri)?),
            None => None,
        };

        self.set_location(&element, file_location)
    }

    fn get_uri_type() -> gst::URIType {
        gst::URIType::Sink
    }

    fn get_protocols() -> Vec<String> {
        vec!["file".to_string()]
    }
}

pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
    gst::Element::register(plugin, "rsfilesrc", 256 + 100, FileSrc::get_type())
}
<commit_msg>rsfilesrc: Fix typo in previous commit<commit_after>// Copyright (C) 2016-2017 Sebastian Dröge <sebastian@centricular.com>
//               2018 François Laignel <fengalin@free.fr>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use glib;
use glib::subclass;
use glib::subclass::prelude::*;
use gst;
use gst::prelude::*;
use gst::subclass::prelude::*;
use gst_base;
use gst_base::subclass::prelude::*;

use std::fs::File;
use std::io::{Read, Seek, SeekFrom};
use std::sync::Mutex;

use url::Url;

use file_location::FileLocation;

const DEFAULT_LOCATION: Option<FileLocation> = None;

#[derive(Debug)]
struct Settings {
    location: Option<FileLocation>,
}

impl Default for Settings {
    fn default() -> Self {
        Settings {
            location: DEFAULT_LOCATION,
        }
    }
}

static PROPERTIES: [subclass::Property; 1] = [subclass::Property("location", |name| {
    glib::ParamSpec::string(
        name,
        "File Location",
        "Location of the file to read from",
        None,
        glib::ParamFlags::READWRITE,
    )
})];

enum State {
    Stopped,
    Started { file: File, position: u64 },
}

impl Default for State {
    fn default() -> State {
        State::Stopped
    }
}

pub struct FileSrc {
    cat: gst::DebugCategory,
    settings: Mutex<Settings>,
    state: Mutex<State>,
}

impl FileSrc {
    fn set_location(
        &self,
        element: &gst_base::BaseSrc,
        location: Option<FileLocation>,
    ) -> Result<(), glib::Error> {
        let state = self.state.lock().unwrap();
        if let State::Started { .. } = *state {
            return Err(gst::Error::new(
                gst::LibraryError::Failed,
                "Changing the `location` property on a started `filesrc` is not supported",
            ));
        }

        let mut settings = self.settings.lock().unwrap();
        settings.location = match location {
            Some(location) => {
                if !location.exists() {
                    return Err(gst::Error::new(
                        gst::LibraryError::Failed,
                        format!("{} doesn't exist", location).as_str(),
                    ));
                }

                if !location.is_file() {
                    return Err(gst::Error::new(
                        gst::LibraryError::Failed,
                        format!("{} is not a file", location).as_str(),
                    ));
                }

                match settings.location {
                    Some(ref location_cur) => {
                        gst_info!(
                            self.cat,
                            obj: element,
                            "Changing `location` from {:?} to {}",
                            location_cur,
                            location,
                        );
                    }
                    None => {
                        gst_info!(self.cat, obj: element, "Setting `location to {}", location,);
                    }
                }
                Some(location)
            }
            None => {
                gst_info!(self.cat, obj: element, "Resetting `location` to None",);
                None
            }
        };

        Ok(())
    }
}

impl ObjectSubclass for FileSrc {
    const NAME: &'static str = "RsFileSrc";
    type ParentType = gst_base::BaseSrc;
    type Instance = gst::subclass::ElementInstanceStruct<Self>;
    type Class = subclass::simple::ClassStruct<Self>;

    glib_object_subclass!();

    fn new() -> Self {
        Self {
            cat: gst::DebugCategory::new("rsfilesrc", gst::DebugColorFlags::empty(), "File Source"),
            settings: Mutex::new(Default::default()),
            state: Mutex::new(Default::default()),
        }
    }

    fn type_init(type_: &subclass::InitializingType<Self>) {
        gst::subclass::uri_handler::register(type_);
    }

    fn class_init(klass: &mut subclass::simple::ClassStruct<Self>) {
        klass.set_metadata(
            "File Source",
            "Source/File",
            "Read stream from a file",
            "François Laignel <fengalin@free.fr>, Sebastian Dröge <sebastian@centricular.com>",
        );

        let caps = gst::Caps::new_any();
        let src_pad_template = gst::PadTemplate::new(
            "src",
            gst::PadDirection::Src,
            gst::PadPresence::Always,
            &caps,
        );
        klass.add_pad_template(src_pad_template);

        klass.install_properties(&PROPERTIES);
    }
}

impl ObjectImpl for FileSrc {
    glib_object_impl!();

    fn set_property(&self, obj: &glib::Object, id: usize, value: &glib::Value) {
        let prop = &PROPERTIES[id];
        match *prop {
            subclass::Property("location", ..) => {
                let element = obj.downcast_ref::<gst_base::BaseSrc>().unwrap();

                let res = match value.get::<String>() {
                    Some(location) => FileLocation::try_from_path_str(location)
                        .and_then(|file_location| self.set_location(&element, Some(file_location))),
                    None => self.set_location(&element, None),
                };

                if let Err(err) = res {
                    gst_error!(
                        self.cat,
                        obj: element,
                        "Failed to set property `location`: {}",
                        err
                    );
                }
            }
            _ => unimplemented!(),
        };
    }

    fn get_property(&self, _obj: &glib::Object, id: usize) -> Result<glib::Value, ()> {
        let prop = &PROPERTIES[id];
        match *prop {
            subclass::Property("location", ..) => {
                let settings = self.settings.lock().unwrap();
                let location = settings
                    .location
                    .as_ref()
                    .map(|location| location.to_string());

                Ok(location.to_value())
            }
            _ => unimplemented!(),
        }
    }
}

impl ElementImpl for FileSrc {}

impl BaseSrcImpl for FileSrc {
    fn is_seekable(&self, _src: &gst_base::BaseSrc) -> bool {
        true
    }

    fn get_size(&self, _src: &gst_base::BaseSrc) -> Option<u64> {
        let state = self.state.lock().unwrap();
        if let State::Started { ref file, .. } = *state {
            file.metadata().ok().map(|m| m.len())
        } else {
            None
        }
    }

    fn start(&self, element: &gst_base::BaseSrc) -> bool {
        let mut state = self.state.lock().unwrap();
        if let State::Started { .. } = *state {
            gst_element_info!(
                element,
                gst::CoreError::StateChange,
                ["FileSrc already started"]
            );
            return false;
        }

        let settings = self.settings.lock().unwrap();
        let location = match settings.location {
            Some(ref location) => location,
            None => {
                gst_element_error!(
                    element,
                    gst::CoreError::StateChange,
                    ["File location is not defined"]
                );
                return false;
            }
        };

        let file = match File::open(location) {
            Ok(file) => file,
            Err(err) => {
                gst_element_error!(
                    element,
                    gst::ResourceError::OpenRead,
                    [
                        "Could not open file {} for reading: {}",
                        location,
                        err.to_string(),
                    ]
                );
                return false;
            }
        };

        gst_debug!(self.cat, obj: element, "Opened file {:?}", file);

        *state = State::Started { file, position: 0 };

        gst_info!(self.cat, obj: element, "Started");

        true
    }

    fn stop(&self, element: &gst_base::BaseSrc) -> bool {
        let mut state = self.state.lock().unwrap();
        if let State::Stopped = *state {
            gst_element_warning!(
                element,
                gst::CoreError::StateChange,
                ["FileSink not started"]
            );
            return false;
        }

        *state = State::Stopped;

        gst_info!(self.cat, obj: element, "Stopped");

        true
    }

    fn create(
        &self,
        element: &gst_base::BaseSrc,
        offset: u64,
        length: u32,
    ) -> Result<gst::Buffer, gst::FlowError> {
        let mut state = self.state.lock().unwrap();

        let (file, position) = match *state {
            State::Started {
                ref mut file,
                ref mut position,
            } => (file, position),
            State::Stopped => {
                gst_element_error!(element, gst::CoreError::Failed, ["Not started yet"]);
                return Err(gst::FlowError::Error);
            }
        };

        if *position != offset {
            file.seek(SeekFrom::Start(offset)).map_err(|err| {
                gst_element_error!(
                    element,
                    gst::LibraryError::Failed,
                    ["Failed to seek to {}: {}", offset, err.to_string()]
                );
                gst::FlowError::Error
            })?;

            *position = offset;
        }

        let mut buffer = match gst::Buffer::with_size(length as usize) {
            Some(buffer) => buffer,
            None => {
                gst_element_error!(
                    element,
                    gst::LibraryError::Failed,
                    ["Failed to allocate buffer"]
                );
                return Err(gst::FlowError::Error);
            }
        };

        {
            let buffer = buffer.make_mut();
            let size = {
                let mut map = match buffer.map_writable() {
                    Some(map) => map,
                    None => {
                        gst_element_error!(
                            element,
                            gst::LibraryError::Failed,
                            ["Failed to map buffer"]
                        );
                        return Err(gst::FlowError::Error);
                    }
                };

                file.read(map.as_mut()).map_err(|err| {
                    gst_element_error!(
                        element,
                        gst::LibraryError::Failed,
                        ["Failed to read at {}: {}", offset, err.to_string()]
                    );
                    gst::FlowError::Error
                })?
            };

            *position += size as u64;

            buffer.set_size(size);
        }

        Ok(buffer)
    }
}

impl URIHandlerImpl for FileSrc {
    fn get_uri(&self, _element: &gst::URIHandler) -> Option<String> {
        let settings = self.settings.lock().unwrap();

        // Conversion to Url already checked while building the `FileLocation`
        settings.location.as_ref().map(|location| {
            Url::from_file_path(location)
                .expect("FileSrc::get_uri couldn't build `Url` from `location`")
                .into_string()
        })
    }

    fn set_uri(&self, element: &gst::URIHandler, uri: Option<String>) -> Result<(), glib::Error> {
        let element = element.dynamic_cast_ref::<gst_base::BaseSrc>().unwrap();

        // Special case for "file://" as this is used by some applications to test
        // with `gst_element_make_from_uri` if there's an element that supports the URI protocol
        let uri = uri.filter(|uri| uri != "file://");

        let file_location = match uri {
            Some(uri) => Some(FileLocation::try_from_uri_str(&uri)?),
            None => None,
        };

        self.set_location(&element, file_location)
    }

    fn get_uri_type() -> gst::URIType {
        gst::URIType::Sink
    }

    fn get_protocols() -> Vec<String> {
        vec!["file".to_string()]
    }
}

pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
    gst::Element::register(plugin, "rsfilesrc", 256 + 100, FileSrc::get_type())
}
<|endoftext|>


<commit_before>//! TODO Documentation

use std::panic;
use std::rc::{Rc, Weak};
use std::sync::atomic::{AtomicBool, Ordering};

use wlroots_sys::wlr_surface;

use errors::{UpgradeHandleErr, UpgradeHandleResult};

/// The state stored in the wlr_surface user data.
struct SurfaceState {
    /// Used to reconstruct a SurfaceHandle from just an *mut wlr_surface.
    handle: Weak<AtomicBool>
}

/// A Wayland object that represents the data that we display on the screen.
///
/// Most surfaces come from Wayland clients, though they can also be created
/// by the compositor directly.
#[derive(Debug)]
pub struct Surface {
    /// The structe that ensures weak handles to this structure are still alive.
    ///
    /// They contain weak handles, and will safely not use dead memory when this
    /// is freed by wlroots.
    ///
    /// If this is `None`, then this is from an upgraded `SurfaceHandle`, and
    /// the operations are **unchecked**.
    /// This is means safe operations might fail, but only if you use the unsafe
    /// marked function `upgrade` on a `SurfaceHandle`.
    liveliness: Option<Rc<AtomicBool>>,
    /// The pointer to the wlroots object that wraps a wl_surface.
    surface: *mut wlr_surface
}

/// See `Surface` for more information on how to use this structure.
#[derive(Clone, Debug)]
pub struct SurfaceHandle {
    /// The Rc that ensures that this handle is still alive.
    ///
    /// When wlroots deallocates the pointer associated with this handle,
    /// this can no longer be used.
    handle: Weak<AtomicBool>,
    /// The pointer to the wlroots object that wraps a wl_surface.
    surface: *mut wlr_surface
}

impl Surface {
    pub(crate) unsafe fn as_ptr(&self) -> *mut wlr_surface {
        self.surface
    }

    pub(crate) unsafe fn from_ptr(surface: *mut wlr_surface) -> Self {
        if !(*surface).data.is_null() {
            panic!("Tried to construct a Surface from an already initialized wlr_surface");
        }
        let liveliness = Rc::new(AtomicBool::new(false));
        let handle = Rc::downgrade(&liveliness);
        (*surface).data = Box::into_raw(Box::new(SurfaceState { handle })) as _;
        let liveliness = Some(liveliness);
        Surface { liveliness,
                  surface }
    }

    unsafe fn from_handle(handle: &SurfaceHandle) -> Self {
        Surface { liveliness: None,
                  surface: handle.surface }
    }
}

impl SurfaceHandle {
    /// Creates an SurfaceHandle from the raw pointer, using the saved
    /// user data to recreate the memory model.
    pub(crate) unsafe fn from_ptr(surface: *mut wlr_surface) -> Self {
        let data = (*surface).data as *mut SurfaceState;
        let handle = (*data).handle.clone();
        SurfaceHandle { handle, surface }
    }

    /// Upgrades the surface handle to a reference to the backing `Surface`.
    ///
    /// # Unsafety
    /// This function is unsafe, because it creates an unbound `Surface`
    /// which may live forever..
    /// But no surface lives forever and might be disconnected at any time.
    pub(crate) unsafe fn upgrade(&self) -> UpgradeHandleResult<Surface> {
        self.handle.upgrade()
            .ok_or(UpgradeHandleErr::AlreadyDropped)
            // NOTE
            // We drop the Rc here because having two would allow a dangling
            // pointer to exist!
            .and_then(|check| {
                if check.load(Ordering::Acquire) {
                    return Err(UpgradeHandleErr::AlreadyBorrowed)
                }
                check.store(true, Ordering::Release);
                Ok(Surface::from_handle(self))
            })
    }

    /// Run a function on the referenced Surface, if it still exists
    ///
    /// Returns the result of the function, if successful
    ///
    /// # Safety
    /// By enforcing a rather harsh limit on the lifetime of the surface
    /// to a short lived scope of an anonymous function,
    /// this function ensures the Surface does not live longer
    /// than it exists.
    ///
    /// # Panics
    /// This function will panic if multiple mutable borrows are detected.
    /// This will happen if you call `upgrade` directly within this callback,
    /// or if you run this function within the another run to the same `Surface`.
    ///
    /// So don't nest `run` calls and everything will be ok :).
    pub fn run<F, R>(&mut self, runner: F) -> UpgradeHandleResult<R>
        where F: FnOnce(&mut Surface) -> R
    {
        let mut surface = unsafe { self.upgrade()? };
        let res = panic::catch_unwind(panic::AssertUnwindSafe(|| runner(&mut surface)));
        self.handle.upgrade().map(|check| {
                                      // Sanity check that it hasn't been tampered with.
                                      if !check.load(Ordering::Acquire) {
                                          wlr_log!(L_ERROR,
                                                   "After running surface callback, mutable lock \
                                                    was false for: {:?}",
                                                   surface);
                                          panic!("Lock in incorrect state!");
                                      }
                                      check.store(false, Ordering::Release);
                                  });
        match res {
            Ok(res) => Ok(res),
            Err(err) => panic::resume_unwind(err)
        }
    }
}
<commit_msg>Implemented some of the things on Surface<commit_after>//! TODO Documentation

use std::{panic, ptr};
use std::rc::{Rc, Weak};
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::Duration;

use wlroots_sys::{timespec, wlr_surface, wlr_surface_get_main_surface, wlr_surface_get_matrix,
                  wlr_surface_has_buffer, wlr_surface_send_enter, wlr_surface_send_frame_done,
                  wlr_surface_send_leave};

use Output;
use errors::{UpgradeHandleErr, UpgradeHandleResult};
use utils::c_to_rust_string;

/// The state stored in the wlr_surface user data.
struct SurfaceState {
    /// Used to reconstruct a SurfaceHandle from just an *mut wlr_surface.
    handle: Weak<AtomicBool>
}

/// A Wayland object that represents the data that we display on the screen.
///
/// Most surfaces come from Wayland clients, though they can also be created
/// by the compositor directly.
#[derive(Debug)]
pub struct Surface {
    /// The structe that ensures weak handles to this structure are still alive.
    ///
    /// They contain weak handles, and will safely not use dead memory when this
    /// is freed by wlroots.
    ///
    /// If this is `None`, then this is from an upgraded `SurfaceHandle`, and
    /// the operations are **unchecked**.
    /// This is means safe operations might fail, but only if you use the unsafe
    /// marked function `upgrade` on a `SurfaceHandle`.
    liveliness: Option<Rc<AtomicBool>>,
    /// The pointer to the wlroots object that wraps a wl_surface.
    surface: *mut wlr_surface
}

/// See `Surface` for more information on how to use this structure.
#[derive(Clone, Debug)]
pub struct SurfaceHandle {
    /// The Rc that ensures that this handle is still alive.
    ///
    /// When wlroots deallocates the pointer associated with this handle,
    /// this can no longer be used.
    handle: Weak<AtomicBool>,
    /// The pointer to the wlroots object that wraps a wl_surface.
    surface: *mut wlr_surface
}

impl Surface {
    pub(crate) unsafe fn as_ptr(&self) -> *mut wlr_surface {
        self.surface
    }

    pub(crate) unsafe fn from_ptr(surface: *mut wlr_surface) -> Self {
        if !(*surface).data.is_null() {
            panic!("Tried to construct a Surface from an already initialized wlr_surface");
        }
        let liveliness = Rc::new(AtomicBool::new(false));
        let handle = Rc::downgrade(&liveliness);
        (*surface).data = Box::into_raw(Box::new(SurfaceState { handle })) as _;
        let liveliness = Some(liveliness);
        Surface { liveliness,
                  surface }
    }

    /// Get the lifetime bound role (if one exists) for this surface.
    pub fn role(&self) -> Option<String> {
        unsafe { c_to_rust_string((*self.surface).role) }
    }

    /// Gets a matrix you can pass into wlr_render_with_matrix to display this
    /// surface.
    ///
    /// `matrix` is the output matrix, `projection` is the wlr_output
    /// projection matrix, and `transform` is any additional transformations you want
    /// to perform on the surface (or None/the identity matrix if you don't).
    ///
    /// `transform` is used before the surface is scaled, so its geometry extends
    /// from 0 to 1 in both dimensions.
    pub fn get_matrix<'a, T>(&mut self,
                             matrix: &mut [f32; 16],
                             projection: &[f32; 16],
                             transform: T)
        where T: Into<Option<&'a [f32; 16]>>
    {
        let transform = transform.into()
                                 .map(|transform| transform as *const _)
                                 .unwrap_or_else(|| ptr::null());
        unsafe { wlr_surface_get_matrix(self.surface, matrix, projection, transform) }
    }

    /// Whether or not this surface currently has an attached buffer.
    ///
    /// A surface has an attached buffer when it commits with a non-null buffer in its pending
    /// state.
    ///
    /// A surface will not have a buffer if it has never committed one, has
    /// committed a null buffer, or something went wrong with uploading the buffer.
    pub fn has_buffer(&self) -> bool {
        unsafe { wlr_surface_has_buffer(self.surface) }
    }

    /// Get the top of the subsurface tree for this surface.
    pub fn get_main_surface(&self) -> Option<SurfaceHandle> {
        unsafe {
            let surface = wlr_surface_get_main_surface(self.surface);
            if surface.is_null() {
                None
            } else {
                Some(SurfaceHandle::from_ptr(surface))
            }
        }
    }

    pub fn send_enter(&mut self, output: &mut Output) {
        unsafe { wlr_surface_send_enter(self.surface, output.as_ptr()) }
    }

    pub fn send_leave(&mut self, output: &mut Output) {
        unsafe { wlr_surface_send_leave(self.surface, output.as_ptr()) }
    }

    /// Send the frame done event.
    pub fn send_frame_done<D>(&mut self, duration: Duration) {
        unsafe {
            // FIXME
            // This is converting from a u64 -> i64
            // Something bad could happen!
            let when = timespec { tv_sec: duration.as_secs() as i64,
                                  tv_nsec: duration.subsec_nanos() as i64 };
            wlr_surface_send_frame_done(self.surface, &when);
        }
    }

    /// Get the matrix used to convert the internal byte buffer to use in the
    /// surface.
    pub fn buffer_to_surface_matrix(&self) -> [f32; 16] {
        unsafe { (*self.surface).buffer_to_surface_matrix }
    }

    /// Get the matrix used to convert the surface back to the internal byte
    /// buffer.
    pub fn surface_to_buffer_matrix(&self) -> [f32; 16] {
        unsafe { (*self.surface).surface_to_buffer_matrix }
    }

    unsafe fn from_handle(handle: &SurfaceHandle) -> Self {
        Surface { liveliness: None,
                  surface: handle.surface }
    }
}

impl SurfaceHandle {
    /// Creates an SurfaceHandle from the raw pointer, using the saved
    /// user data to recreate the memory model.
    pub(crate) unsafe fn from_ptr(surface: *mut wlr_surface) -> Self {
        let data = (*surface).data as *mut SurfaceState;
        let handle = (*data).handle.clone();
        SurfaceHandle { handle, surface }
    }

    /// Upgrades the surface handle to a reference to the backing `Surface`.
    ///
    /// # Unsafety
    /// This function is unsafe, because it creates an unbound `Surface`
    /// which may live forever..
    /// But no surface lives forever and might be disconnected at any time.
    pub(crate) unsafe fn upgrade(&self) -> UpgradeHandleResult<Surface> {
        self.handle.upgrade()
            .ok_or(UpgradeHandleErr::AlreadyDropped)
            // NOTE
            // We drop the Rc here because having two would allow a dangling
            // pointer to exist!
            .and_then(|check| {
                if check.load(Ordering::Acquire) {
                    return Err(UpgradeHandleErr::AlreadyBorrowed)
                }
                check.store(true, Ordering::Release);
                Ok(Surface::from_handle(self))
            })
    }

    /// Run a function on the referenced Surface, if it still exists
    ///
    /// Returns the result of the function, if successful
    ///
    /// # Safety
    /// By enforcing a rather harsh limit on the lifetime of the surface
    /// to a short lived scope of an anonymous function,
    /// this function ensures the Surface does not live longer
    /// than it exists.
    ///
    /// # Panics
    /// This function will panic if multiple mutable borrows are detected.
    /// This will happen if you call `upgrade` directly within this callback,
    /// or if you run this function within the another run to the same `Surface`.
    ///
    /// So don't nest `run` calls and everything will be ok :).
    pub fn run<F, R>(&mut self, runner: F) -> UpgradeHandleResult<R>
        where F: FnOnce(&mut Surface) -> R
    {
        let mut surface = unsafe { self.upgrade()? };
        let res = panic::catch_unwind(panic::AssertUnwindSafe(|| runner(&mut surface)));
        self.handle.upgrade().map(|check| {
                                      // Sanity check that it hasn't been tampered with.
                                      if !check.load(Ordering::Acquire) {
                                          wlr_log!(L_ERROR,
                                                   "After running surface callback, mutable lock \
                                                    was false for: {:?}",
                                                   surface);
                                          panic!("Lock in incorrect state!");
                                      }
                                      check.store(false, Ordering::Release);
                                  });
        match res {
            Ok(res) => Ok(res),
            Err(err) => panic::resume_unwind(err)
        }
    }
}
<|endoftext|>