<commit_before>//! Reminisce is a lightweight library intended to be used for detecting and
//! reading from joysticks.
#![feature(into_cow)]
#![cfg_attr(feature = "mappings", feature(alloc))]
#![cfg_attr(target_os = "linux", feature(libc, fs_walk))]
extern crate libc;
#[cfg(target_os = "windows")]
#[macro_use] extern crate rustc_bitflags;

#[cfg(feature = "sdl")]
extern crate sdl2;

/// Someday, somehow
#[cfg(all(feature = "emscripten", not(feature = "sdl")))]
pub mod emscripten;

#[cfg(all(feature = "emscripten", not(feature = "sdl")))]
pub use emscripten as native;

#[cfg(all(target_os = "linux", not(feature = "sdl")))]
pub mod linux;

#[cfg(all(target_os = "linux", not(feature = "sdl")))]
pub use linux as native;

#[cfg(all(target_os = "windows", not(feature = "sdl")))]
pub mod windows;

#[cfg(all(target_os = "windows", not(feature = "sdl")))]
pub use windows as native;

#[cfg(feature = "sdl")]
pub mod sdl;

#[cfg(feature = "sdl")]
pub use sdl as native;

#[cfg(feature = "mappings")]
pub mod mapper;

#[cfg(feature = "mappings")]
pub use mapper::JoystickMapper;
pub use native::{NativeJoystick, scan};

/// The maximum axis value
pub static MAX_AXIS_VALUE:i16 = 32767;
/// The minimum axis value
pub static MIN_AXIS_VALUE:i16 = -32767;

use std::borrow::Cow;
use std::error::Error;
use std::fmt::Debug;
use std::mem::transmute as cast;

#[cfg(feature = "mappings")]
macro_rules! text_enum(
    ($name:ident, $($enumer:ident => $text:expr),+) => (
        impl ::std::fmt::Display for $name {
            fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                write!(fmt, "{}", match *self {
                    $($name::$enumer => $text),+
                })
            }
        }
        impl ::std::str::FromStr for $name {
            type Err = String;
            fn from_str(s: &str) -> Result<$name, String> {
                match s {
                    $($text => Ok($name::$enumer),)+
                    _ => Err(format!("Could not make {} from {}", stringify!($name), s))
                }
            }
        }
    )
);
#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
/// A direction on a joystick
///
/// This uses the order that Linux drivers and the HTML5 Gamepad API uses so it should ring a bell
pub enum Axis {
	/// The x direction of the left stick
    ///
    /// This is usually used for horizontal movement in a game
    LeftX,
	/// The y direction of the left stick
    ///
    /// This is usually used for vertical movement in a game
    LeftY,
	/// The x direction of the right stick
    //
    /// This is usually used for looking around in a game
    RightX,
	/// The y direction of the right stick
    //
    /// This is usually used for looking around in a game
    RightY,
	/// How far down the left trigger is pressed
    ///
    /// This is only used as a button on some platforms so don't rely on just this
    TriggerLeft,
	/// How far down the right trigger is pressed
    ///
    /// This is only used as a button on some platforms so don't rely on just this
    TriggerRight
}
#[cfg(feature = "mappings")]
text_enum!(Axis,
    LeftX => "leftx",
    LeftY => "lefty",
    RightX => "rightx",
    RightY => "righty",
    TriggerLeft => "triggerleft",
    TriggerRight => "triggerright"
);

#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
/// A button on a joystick
///
/// This uses the order that Linux drivers and the HTML5 Gamepad API uses so it should be familiar
pub enum Button {
	/// The A button
    ///
    /// This is typically used for jumping
	A,
	/// The B button
    ///
    /// This is typically used for hitting
	B,
	/// The X button
	X,
	/// The Y button
	Y,
	/// The left top shoulder button
    ///
    /// This is usually used in FPS games for throwing a certain kind of grenade
	LeftShoulder,
	/// The right top shoulder button
	RightShoulder,
	/// The left bottom shoulder / trigger button
    ///
    /// This is typically used in FPS games for aiming down the sights in a weapon
	LeftTrigger,
	/// The right bottom shoulder / trigger button
    ///
    /// This is typically used in FPS games for shooting with a weapon
	RightTrigger,
	/// The back / select button
    ///
    /// This is usually used as an alternate pause menu or to open a menu in-game.
	Select,
	/// The start / forward button
    ///
    /// This is usually used to start and pause a game
	Start,
	/// The left stick button
	LeftStick,
	/// The right stick button
	RightStick,
	/// The up button on the directional pad
	DPadUp,
	/// The down button on the directional pad
	DPadDown,
	/// The left button on the directional pad
	DPadLeft,
	/// The right button on the directional pad
	DPadRight
}
#[cfg(feature = "mappings")]
text_enum!(Button,
    A => "a",
    B => "b",
    X => "x",
    Y => "y",
    LeftShoulder => "leftshoulder",
    RightShoulder => "rightshoulder",
    LeftTrigger => "lefttrigger",
    RightTrigger => "righttrigger",
    Select => "select",
    Start => "start",
    LeftStick => "leftstick",
    RightStick => "rightstick",
    DPadUp => "dpadup",
    DPadDown => "dpaddown",
    DPadLeft => "dpadleft",
    DPadRight => "dpadright"
);

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
/// An event from a joystick
pub enum Event {
	/// Fired when a button is pressed with the button's index
	ButtonPressed(Button),
	/// Fired when a button is released with the button's index
	ButtonReleased(Button),
	/// Fired when a axis is moved with the axis index and its value,
	/// which is between `MIN_JOYSTICK_VALUE` and `MAX_JOYSTICK_VALUE`
	AxisMoved(Axis, i16)
}
/// Convert a raw event into a Reminisce event
pub trait IntoEvent {
	/// Convert this into a Reminisce event
	fn into_event(self) -> Event;
}

impl IntoEvent for Event {
    /// Convert the event into itself
    ///
    /// The only reason this exists is because windows doesn't have events so the backend has to
    /// make reminisce events directly and pretend that they are the native events.
    fn into_event(self) -> Event {
        self
    }
}

/// A joystick or gamepad
///
/// Each `Joystick` has its own event queue that can be polled repeatedly
/// using the `iter()` method or by calling the `poll()` method repeatedly.
///
/// ``` rust
/// use reminisce::{scan, Axis, Event, Joystick};
/// let mut joysticks = scan();
/// let (mut x, mut y) = (0, 0);
/// for joystick in &mut joysticks {
///     for event in joystick.iter() {
///         match event {
///             Event::AxisMoved(Axis::LeftX, nx) =>
///                 x += nx,
///             Event::AxisMoved(Axis::LeftY, ny) =>
///                 y += ny,
///             _ => ()
///         }
///     }
/// }
/// println!("{}, {}", x, y);
/// ```
pub trait Joystick : Sized {
	/// The version of this joystick that includes the state
    ///
    /// On Linux, this is a wrapper around the joystick, but on Windows,
    /// this is the same stucture because the joystick always includes
    /// state on it.
	type WithState : StatefulJoystick;

    /// The event that this joystick processes
    type NativeEvent: IntoEvent;

    type OpenError: Error + Debug;

	/// Create a new joystick from its index
    ///
    /// If an error occurs, this will return the textual representation of that error.
    ///
    /// ``` rust
    /// use reminisce::{NativeJoystick, Joystick};
    /// let joystick:NativeJoystick = Joystick::new(0).unwrap();
    /// if let Ok(joystick) = joystick {
    ///     println!("{}", joystick.get_id())
    /// } else {
    ///     println!("No joystick plugged in")
    /// }
    /// ```
	fn new(index: u8) -> Result<Self, Self::OpenError>;

	/// Check if the joystick is still connected
	fn is_connected(&self) -> bool;

	/// Get the identifier of this joystick
    ///
    /// This is a cow because it can be a static or owned String depending on the
    /// implementation.
	fn get_id(&self) -> Cow<str>;

	/// Get the index of this joystick
	fn get_index(&self) -> u8;

	/// Get the number of axes this joystick has
    ///
    /// This is capped at 6 axes for now.
	fn get_num_axes(&self) -> u8;

	/// Get the number of buttons this joystick has
    ///
    /// This is capped at 16 buttons currently.
	fn get_num_buttons(&self) -> u8;

    /// Get the battery level of this joystick
    ///
    /// Returns none if the joystick is wired or this operation is not supported
    /// by the backend
    fn get_battery(&self) -> Option<f32>;

    /// Poll the joystick for events in non-blocking mode and return the native event
    /// as returned from the backend
	fn poll_native(&mut self) -> Option<Self::NativeEvent>;

    /// Poll the joystick for events in non-blocking mode
    ///
    /// This runs `self.poll_native()` then converts it into an event using
    /// the `into_event` method.
    fn poll(&mut self) -> Option<Event> {
        self.poll_native().map(|e| e.into_event())
    }

    /// Map the axes and buttons of this joystick by wrapping it in a `JoystickMapper`
    #[cfg(feature = "mappings")]
    fn into_mapper(self) -> JoystickMapper<Self> {
        JoystickMapper::new(self)
    }

    /// Iterate through the events that haven't been processed yet
    fn iter(&mut self) -> Poller<Self> {
        Poller {
            joystick: self
        }
    }

	/// Get the version of this joystick which includes state
    ///
    /// On the Linux backend, a wrapper is made, but on the Windows
    /// backend no wrapper is needed so this just returns the
    ///n `NativeJoystick` structure
	fn with_state(self) -> Self::WithState;
}

/// A joystick that keeps a record of its state
/// This makes it really easy to write the input for games, etc because its just a matter
/// of calling a single method to query where the axes are
///
/// ``` rust
/// use reminisce::{scan, Axis, NativeJoystick, Joystick, StatefulJoystick};
/// let mut joysticks = scan().into_iter().map(|js| js.with_state()).collect::<Vec<_>>();
/// for joystick in &joysticks {
///     let x = joystick.get_axis(Axis::LeftX).unwrap_or(0);
///     let y = joystick.get_axis(Axis::LeftY).unwrap_or(0);
///     println!("{}, {}", x, y)
/// }
/// ```
pub trait StatefulJoystick : Joystick + Sized {
	/// Get the value of a specific axis as an integer between `MIN_AXIS_VALUE` and `MAX_AXIS_VALUE`
	fn get_axis(&self, index: Axis) -> Option<i16>;

	/// Get the value of a specific axis normalised to between -1.0 and 1.0
	fn get_normalised_axis(&self, index: Axis) -> Option<f32> {
		self.get_axis(index).map(|v| v as f32 / MAX_AXIS_VALUE as f32)
	}

	/// Iterate over the axes in this joystick
	fn axes(&self) -> Axes<Self> {
		use std::mem;
		Axes {
			joystick: self,
			axis: unsafe { mem::zeroed() }
		}
	}

	/// Iterate over the buttons in this joystick
	fn buttons(&self) -> Buttons<Self> {
		use std::mem;
		Buttons {
			joystick: self,
			button: unsafe { mem::zeroed() }
		}
	}

	/// Get the value (if it is pressed or not) of a specific button
	///
	/// The first two buttons are usually the accept and back buttons
	fn get_button(&self, index: Button) -> Option<bool>;

	/// Update the state of this joystick by polling the native backend
	fn update(&mut self);
}

/// An iterator over a joystick's axes
pub struct Axes<'a, J> where J:StatefulJoystick+'a {
	joystick: &'a J,
	axis: u8
}
impl<'a, J> Iterator for Axes<'a, J> where J:StatefulJoystick {
	type Item = (Axis, i16);
	fn next(&mut self) -> Option<(Axis, i16)> {
		self.axis += 1;
		let axis = unsafe { cast(self.axis - 1) };
		self.joystick.get_axis(axis).map(|v| (axis, v))
	}
}

/// An iterator over a joystick's buttons
pub struct Buttons<'a, J> where J:StatefulJoystick+'a {
	joystick: &'a J,
	button: u8
}
impl<'a, J> Iterator for Buttons<'a, J> where J:StatefulJoystick {
	type Item = (Button, bool);
	fn next(&mut self) -> Option<(Button, bool)> {
		self.button += 1;
		let button = unsafe { cast(self.button - 1) };
		self.joystick.get_button(button).map(|v| (button, v))
	}
}

/// An iterator over a joystick's event queue
pub struct Poller<'a, J> where J:Joystick+'a {
    joystick: &'a mut J
}

impl<'a, J> Iterator for Poller<'a, J> where J:Joystick {
	type Item = Event;
    /// This calls the `joystick.poll()` method to poll for the next event
	fn next(&mut self) -> Option<Event> {
		self.joystick.poll()
	}
}
<commit_msg>Improve documentation<commit_after>//! Reminisce is a lightweight library intended to be used for detecting and
//! reading from joysticks.
#![feature(into_cow)]
#![cfg_attr(feature = "mappings", feature(alloc))]
#![cfg_attr(target_os = "linux", feature(libc, fs_walk))]
extern crate libc;
#[cfg(target_os = "windows")]
#[macro_use] extern crate rustc_bitflags;

#[cfg(feature = "sdl")]
extern crate sdl2;

/// Someday, somehow
#[cfg(all(feature = "emscripten", not(feature = "sdl")))]
pub mod emscripten;

#[cfg(all(feature = "emscripten", not(feature = "sdl")))]
pub use emscripten as native;

#[cfg(all(target_os = "linux", not(feature = "sdl")))]
pub mod linux;

#[cfg(all(target_os = "linux", not(feature = "sdl")))]
pub use linux as native;

#[cfg(all(target_os = "windows", not(feature = "sdl")))]
pub mod windows;

#[cfg(all(target_os = "windows", not(feature = "sdl")))]
pub use windows as native;

#[cfg(feature = "sdl")]
pub mod sdl;

#[cfg(feature = "sdl")]
pub use sdl as native;

#[cfg(feature = "mappings")]
pub mod mapper;

#[cfg(feature = "mappings")]
pub use mapper::JoystickMapper;
pub use native::{NativeJoystick, scan};

/// The maximum axis value
pub static MAX_AXIS_VALUE:i16 = 32767;
/// The minimum axis value
pub static MIN_AXIS_VALUE:i16 = -32767;

use std::borrow::Cow;
use std::error::Error;
use std::fmt::Debug;
use std::mem::transmute as cast;

#[cfg(feature = "mappings")]
macro_rules! text_enum(
    ($name:ident, $($enumer:ident => $text:expr),+) => (
        impl ::std::fmt::Display for $name {
            fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                write!(fmt, "{}", match *self {
                    $($name::$enumer => $text),+
                })
            }
        }
        impl ::std::str::FromStr for $name {
            type Err = String;
            fn from_str(s: &str) -> Result<$name, String> {
                match s {
                    $($text => Ok($name::$enumer),)+
                    _ => Err(format!("Could not make {} from {}", stringify!($name), s))
                }
            }
        }
    )
);
#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
/// A direction on a joystick
///
/// This uses the order that Linux drivers and the HTML5 Gamepad API uses so it should ring a bell
pub enum Axis {
	/// The x direction of the left stick
    ///
    /// This is usually used for horizontal movement in a game
    LeftX,
	/// The y direction of the left stick
    ///
    /// This is usually used for vertical movement in a game
    LeftY,
	/// The x direction of the right stick
    //
    /// This is usually used for looking around in a game
    RightX,
	/// The y direction of the right stick
    //
    /// This is usually used for looking around in a game
    RightY,
	/// How far down the left trigger is pressed
    ///
    /// This is only used as a button on some platforms so don't rely on just this
    TriggerLeft,
	/// How far down the right trigger is pressed
    ///
    /// This is only used as a button on some platforms so don't rely on just this
    TriggerRight
}
#[cfg(feature = "mappings")]
text_enum!(Axis,
    LeftX => "leftx",
    LeftY => "lefty",
    RightX => "rightx",
    RightY => "righty",
    TriggerLeft => "triggerleft",
    TriggerRight => "triggerright"
);

#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
/// A button on a joystick
///
/// This uses the order that Linux drivers and the HTML5 Gamepad API uses so it should be familiar
pub enum Button {
	/// The A button
    ///
    /// This is typically used for jumping
	A,
	/// The B button
    ///
    /// This is typically used for attacking
	B,
	/// The X button
	X,
	/// The Y button
	Y,
	/// The left top shoulder button
    ///
    /// This is usually used in FPS games for throwing a certain kind of grenade
	LeftShoulder,
	/// The right top shoulder button
	RightShoulder,
	/// The left bottom shoulder / trigger button
    ///
    /// This is typically used in FPS games for aiming down the sights in a weapon
	LeftTrigger,
	/// The right bottom shoulder / trigger button
    ///
    /// This is typically used in FPS games for shooting with a weapon
	RightTrigger,
	/// The back / select button
    ///
    /// This is usually used as an alternate pause menu or to open a menu in-game.
	Select,
	/// The start / forward button
    ///
    /// This is usually used to start and pause a game
	Start,
	/// The left stick button
	LeftStick,
	/// The right stick button
	RightStick,
	/// The up button on the directional pad
	DPadUp,
	/// The down button on the directional pad
	DPadDown,
	/// The left button on the directional pad
	DPadLeft,
	/// The right button on the directional pad
	DPadRight
}
#[cfg(feature = "mappings")]
text_enum!(Button,
    A => "a",
    B => "b",
    X => "x",
    Y => "y",
    LeftShoulder => "leftshoulder",
    RightShoulder => "rightshoulder",
    LeftTrigger => "lefttrigger",
    RightTrigger => "righttrigger",
    Select => "select",
    Start => "start",
    LeftStick => "leftstick",
    RightStick => "rightstick",
    DPadUp => "dpadup",
    DPadDown => "dpaddown",
    DPadLeft => "dpadleft",
    DPadRight => "dpadright"
);

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
/// An event emitted by a joystick
pub enum Event {
	/// Fired when a button is pressed with the button's index
	ButtonPressed(Button),
	/// Fired when a button is released with the button's index
	ButtonReleased(Button),
	/// Fired when a axis is moved with the axis index and its value,
	/// which is between `MIN_JOYSTICK_VALUE` and `MAX_JOYSTICK_VALUE`
	AxisMoved(Axis, i16)
}
/// Convert a raw event into a Reminisce event
pub trait IntoEvent {
	/// Convert this into a Reminisce event
	fn into_event(self) -> Event;
}

impl IntoEvent for Event {
    /// Convert the event into itself
    ///
    /// The only reason this exists is because windows doesn't have events so the backend has to
    /// make reminisce events directly and pretend that they are the native events.
    fn into_event(self) -> Event {
        self
    }
}

/// A joystick or gamepad
///
/// Each `Joystick` has its own event queue that can be polled repeatedly
/// using the `iter()` method or by calling the `poll()` method repeatedly.
///
/// ``` rust
/// use reminisce::{scan, Axis, Event, Joystick};
/// let mut joysticks = scan();
/// let (mut x, mut y) = (0, 0);
/// for joystick in &mut joysticks {
///     for event in joystick.iter() {
///         match event {
///             Event::AxisMoved(Axis::LeftX, nx) =>
///                 x += nx,
///             Event::AxisMoved(Axis::LeftY, ny) =>
///                 y += ny,
///             _ => ()
///         }
///     }
/// }
/// println!("{}, {}", x, y);
/// ```
pub trait Joystick : Sized {
	/// The version of this joystick that includes the state
    ///
    /// On Linux, this is a wrapper around the joystick, but on Windows,
    /// this is the same stucture because the joystick always includes
    /// state on it.
	type WithState : StatefulJoystick;

    /// The event that this joystick processes
    type NativeEvent: IntoEvent;

    /// The error that could be thrown while trying to open the joystick
    type OpenError: Error + Debug;

	/// Create a new joystick from its index
    ///
    /// If an error occurs, this will return the textual representation of that error.
    ///
    /// ``` rust
    /// use reminisce::{NativeJoystick, Joystick};
    /// let joystick:NativeJoystick = Joystick::new(0).unwrap();
    /// if let Ok(joystick) = joystick {
    ///     println!("{}", joystick.get_id())
    /// } else {
    ///     println!("No joystick plugged in")
    /// }
    /// ```
	fn new(index: u8) -> Result<Self, Self::OpenError>;

	/// Check if the joystick is still connected
	fn is_connected(&self) -> bool;

	/// Get the identifier of this joystick
    ///
    /// This is copy-on-write because it can be a borrowed or owned String depending on the
    /// implementation.
	fn get_id(&self) -> Cow<str>;

	/// Get the index of this joystick
	fn get_index(&self) -> u8;

	/// Get the number of axes this joystick has
    ///
    /// This is capped at 6 axes for now.
	fn get_num_axes(&self) -> u8;

	/// Get the number of buttons this joystick has
    ///
    /// This is capped at 16 buttons currently.
	fn get_num_buttons(&self) -> u8;

    /// Get the battery level of this joystick
    ///
    /// Returns none if the joystick is wired or this operation is not supported
    /// by the backend
    fn get_battery(&self) -> Option<f32>;

    /// Poll the joystick for events in non-blocking mode and return the native event
    /// as returned from the backend
	fn poll_native(&mut self) -> Option<Self::NativeEvent>;

    /// Poll the joystick for events in non-blocking mode
    ///
    /// This runs `self.poll_native()` then converts it into an event using
    /// the `into_event` method.
    fn poll(&mut self) -> Option<Event> {
        self.poll_native().map(|e| e.into_event())
    }

    /// Map the axes and buttons of this joystick by wrapping it in a `JoystickMapper`
    #[cfg(feature = "mappings")]
    fn into_mapper(self) -> JoystickMapper<Self> {
        JoystickMapper::new(self)
    }

    /// Iterate through the events that haven't been processed yet
    fn iter(&mut self) -> Poller<Self> {
        Poller {
            joystick: self
        }
    }

	/// Get the version of this joystick which includes state
    ///
    /// On the Linux backend, a wrapper is created that records the changes in state, but on the
    /// Windows backend no wrapper is needed so this just returns the `NativeJoystick` structure
	fn with_state(self) -> Self::WithState;
}

/// A joystick that tracks its state
///
/// This makes it really easy to write the input for games, etc because its just a matter
/// of calling a single method to query the current value of the axes
///
/// ``` rust
/// use reminisce::{scan, Axis, NativeJoystick, Joystick, StatefulJoystick};
/// let mut joysticks = scan().into_iter().map(|js| js.with_state()).collect::<Vec<_>>();
/// for joystick in &joysticks {
///     let x = joystick.get_axis(Axis::LeftX).unwrap_or(0);
///     let y = joystick.get_axis(Axis::LeftY).unwrap_or(0);
///     println!("{}, {}", x, y)
/// }
/// ```
pub trait StatefulJoystick : Joystick + Sized {
	/// Get the value of a specific axis as an integer between `MIN_AXIS_VALUE` and `MAX_AXIS_VALUE`
    ///
    /// If the axis is horizontal, a negative value indicates it is pointing leftwards and a positive
    /// value indicates it is pointing rightwards. However, is the axis is vertical a negative value
    /// indicates it is pointing upwards and a positive value indicates it is pointing downwards
	fn get_axis(&self, index: Axis) -> Option<i16>;

	/// Get the value of a specific axis normalised to between -1.0 and 1.0
    ///
    /// This is equivalent to calling `get_axis` then dividing the value by the `MAX_AXIS_VALUE`
	fn get_normalised_axis(&self, index: Axis) -> Option<f32> {
		self.get_axis(index).map(|v| v as f32 / MAX_AXIS_VALUE as f32)
	}

	/// Iterate over the axes in this joystick
	fn axes(&self) -> Axes<Self> {
		use std::mem;
		Axes {
			joystick: self,
			axis: unsafe { mem::zeroed() }
		}
	}

	/// Iterate over the buttons in this joystick
	fn buttons(&self) -> Buttons<Self> {
		use std::mem;
		Buttons {
			joystick: self,
			button: unsafe { mem::zeroed() }
		}
	}

	/// Get the pressed state of a specific button
	fn get_button(&self, index: Button) -> Option<bool>;

	/// Update the state of this joystick by polling the native backend
	fn update(&mut self);
}

/// An iterator over a joystick's axes
pub struct Axes<'a, J> where J:StatefulJoystick+'a {
	joystick: &'a J,
	axis: u8
}
impl<'a, J> Iterator for Axes<'a, J> where J:StatefulJoystick {
    /// The axis index and state, respectively
	type Item = (Axis, i16);
	fn next(&mut self) -> Option<(Axis, i16)> {
		self.axis += 1;
		let axis = unsafe { cast(self.axis - 1) };
		self.joystick.get_axis(axis).map(|v| (axis, v))
	}
}

/// An iterator over a joystick's buttons
pub struct Buttons<'a, J> where J:StatefulJoystick+'a {
	joystick: &'a J,
	button: u8
}
impl<'a, J> Iterator for Buttons<'a, J> where J:StatefulJoystick {
    /// The button index and state, respectively
	type Item = (Button, bool);
	fn next(&mut self) -> Option<(Button, bool)> {
		self.button += 1;
		let button = unsafe { cast(self.button - 1) };
		self.joystick.get_button(button).map(|v| (button, v))
	}
}

/// An iterator over a joystick's event queue
pub struct Poller<'a, J> where J:Joystick+'a {
    joystick: &'a mut J
}

impl<'a, J> Iterator for Poller<'a, J> where J:Joystick {
	type Item = Event;
    /// This calls the `joystick.poll()` method to poll for the next event
	fn next(&mut self) -> Option<Event> {
		self.joystick.poll()
	}
}
<|endoftext|>


<commit_before>use {Color, Rgb, Xyz, Lab, Lch, Hsv, Hsl, ColorSpace, Mix, Shade, clamp};

///Linear luminance with an alpha component.
///
///Luma is a purely gray scale color space, which is included more for
///completeness than anything else, and represents how bright a color is
///perceived to be. It's basically the `Y` component of [CIE
///XYZ](struct.Xyz.html). The lack of any form of hue representation limits
///the set of operations that can be performed on it.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Luma {
    ///The lightness of the color. 0.0 is black and 1.0 is white.
    pub luma: f32,

    ///The transparency of the color. 0.0 is completely transparent and 1.0 is
    ///completely opaque.
    pub alpha: f32,
}

impl Luma {
    ///Linear luminance.
    pub fn y(luma: f32) -> Luma {
        Luma {
            luma: luma,
            alpha: 0.0,
        }
    }

    ///Linear luminance with transparency.
    pub fn ya(luma: f32, alpha: f32) -> Luma {
        Luma {
            luma: luma,
            alpha: alpha,
        }
    }

    ///Linear luminance from an 8 bit value.
    pub fn y8(luma: u8) -> Luma {
        Luma {
            luma: luma as f32 / 255.0,
            alpha: 0.0,
        }
    }

    ///Linear luminance and transparency from 8 bit values.
    pub fn ya8(luma: u8, alpha: u8) -> Luma {
        Luma {
            luma: luma as f32 / 255.0,
            alpha: alpha as f32 / 255.0,
        }
    }
}

impl ColorSpace for Luma {
    fn is_valid(&self) -> bool {
        self.luma >= 0.0 && self.luma <= 1.0 &&
        self.alpha >= 0.0 && self.alpha <= 1.0
    }

    fn clamp(&self) -> Luma {
        let mut c = *self;
        c.clamp_self();
        c
    }

    fn clamp_self(&mut self) {
        self.luma = clamp(self.luma, 0.0, 1.0);
        self.alpha = clamp(self.alpha, 0.0, 1.0);
    }
}

impl Mix for Luma {
    fn mix(&self, other: &Luma, factor: f32) -> Luma {
        let factor = clamp(factor, 0.0, 1.0);

        Luma {
            luma: self.luma + factor * (other.luma - self.luma),
            alpha: self.alpha + factor * (other.alpha - self.alpha),
        }
    }
}

impl Shade for Luma {
    fn lighten(&self, amount: f32) -> Luma {
        Luma {
            luma: (self.luma + amount).max(0.0),
            alpha: self.alpha,
        }
    }
}

impl Default for Luma {
    fn default() -> Luma {
        Luma::y(0.0)
    }
}

from_color!(to Luma from Rgb, Xyz, Lab, Lch, Hsv, Hsl);

impl From<Rgb> for Luma {
    fn from(rgb: Rgb) -> Luma {
        Luma {
            luma: rgb.red * 0.2126 + rgb.green * 0.7152 + rgb.blue * 0.0722,
            alpha: rgb.alpha
        }
    }
}

impl From<Xyz> for Luma {
    fn from(xyz: Xyz) -> Luma {
        Luma {
            luma: xyz.y,
            alpha: xyz.alpha
        }
    }
}

impl From<Lab> for Luma {
    fn from(lab: Lab) -> Luma {
        Xyz::from(lab).into()
    }
}

impl From<Lch> for Luma {
    fn from(lch: Lch) -> Luma {
        Xyz::from(lch).into()
    }
}

impl From<Hsv> for Luma {
    fn from(hsv: Hsv) -> Luma {
        Rgb::from(hsv).into()
    }
}

impl From<Hsl> for Luma {
    fn from(hsl: Hsl) -> Luma {
        Rgb::from(hsl).into()
    }
}
<commit_msg>Implement arithmetic operators for Luma<commit_after>use std::ops::{Add, Sub, Mul, Div};

use {Color, Rgb, Xyz, Lab, Lch, Hsv, Hsl, ColorSpace, Mix, Shade, clamp};

///Linear luminance with an alpha component.
///
///Luma is a purely gray scale color space, which is included more for
///completeness than anything else, and represents how bright a color is
///perceived to be. It's basically the `Y` component of [CIE
///XYZ](struct.Xyz.html). The lack of any form of hue representation limits
///the set of operations that can be performed on it.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Luma {
    ///The lightness of the color. 0.0 is black and 1.0 is white.
    pub luma: f32,

    ///The transparency of the color. 0.0 is completely transparent and 1.0 is
    ///completely opaque.
    pub alpha: f32,
}

impl Luma {
    ///Linear luminance.
    pub fn y(luma: f32) -> Luma {
        Luma {
            luma: luma,
            alpha: 0.0,
        }
    }

    ///Linear luminance with transparency.
    pub fn ya(luma: f32, alpha: f32) -> Luma {
        Luma {
            luma: luma,
            alpha: alpha,
        }
    }

    ///Linear luminance from an 8 bit value.
    pub fn y8(luma: u8) -> Luma {
        Luma {
            luma: luma as f32 / 255.0,
            alpha: 0.0,
        }
    }

    ///Linear luminance and transparency from 8 bit values.
    pub fn ya8(luma: u8, alpha: u8) -> Luma {
        Luma {
            luma: luma as f32 / 255.0,
            alpha: alpha as f32 / 255.0,
        }
    }
}

impl ColorSpace for Luma {
    fn is_valid(&self) -> bool {
        self.luma >= 0.0 && self.luma <= 1.0 &&
        self.alpha >= 0.0 && self.alpha <= 1.0
    }

    fn clamp(&self) -> Luma {
        let mut c = *self;
        c.clamp_self();
        c
    }

    fn clamp_self(&mut self) {
        self.luma = clamp(self.luma, 0.0, 1.0);
        self.alpha = clamp(self.alpha, 0.0, 1.0);
    }
}

impl Mix for Luma {
    fn mix(&self, other: &Luma, factor: f32) -> Luma {
        let factor = clamp(factor, 0.0, 1.0);

        Luma {
            luma: self.luma + factor * (other.luma - self.luma),
            alpha: self.alpha + factor * (other.alpha - self.alpha),
        }
    }
}

impl Shade for Luma {
    fn lighten(&self, amount: f32) -> Luma {
        Luma {
            luma: (self.luma + amount).max(0.0),
            alpha: self.alpha,
        }
    }
}

impl Default for Luma {
    fn default() -> Luma {
        Luma::y(0.0)
    }
}

impl Add<Luma> for Luma {
    type Output = Luma;

    fn add(self, other: Luma) -> Luma {
        Luma {
            luma: self.luma + other.luma,
            alpha: self.alpha + other.alpha,
        }
    }
}

impl Add<f32> for Luma {
    type Output = Luma;

    fn add(self, c: f32) -> Luma {
        Luma {
            luma: self.luma + c,
            alpha: self.alpha + c,
        }
    }
}

impl Sub<Luma> for Luma {
    type Output = Luma;

    fn sub(self, other: Luma) -> Luma {
        Luma {
            luma: self.luma - other.luma,
            alpha: self.alpha - other.alpha,
        }
    }
}

impl Sub<f32> for Luma {
    type Output = Luma;

    fn sub(self, c: f32) -> Luma {
        Luma {
            luma: self.luma - c,
            alpha: self.alpha - c,
        }
    }
}

impl Mul<Luma> for Luma {
    type Output = Luma;

    fn mul(self, other: Luma) -> Luma {
        Luma {
            luma: self.luma * other.luma,
            alpha: self.alpha * other.alpha,
        }
    }
}

impl Mul<f32> for Luma {
    type Output = Luma;

    fn mul(self, c: f32) -> Luma {
        Luma {
            luma: self.luma * c,
            alpha: self.alpha * c,
        }
    }
}

impl Div<Luma> for Luma {
    type Output = Luma;

    fn div(self, other: Luma) -> Luma {
        Luma {
            luma: self.luma / other.luma,
            alpha: self.alpha / other.alpha,
        }
    }
}

impl Div<f32> for Luma {
    type Output = Luma;

    fn div(self, c: f32) -> Luma {
        Luma {
            luma: self.luma / c,
            alpha: self.alpha / c,
        }
    }
}

from_color!(to Luma from Rgb, Xyz, Lab, Lch, Hsv, Hsl);

impl From<Rgb> for Luma {
    fn from(rgb: Rgb) -> Luma {
        Luma {
            luma: rgb.red * 0.2126 + rgb.green * 0.7152 + rgb.blue * 0.0722,
            alpha: rgb.alpha
        }
    }
}

impl From<Xyz> for Luma {
    fn from(xyz: Xyz) -> Luma {
        Luma {
            luma: xyz.y,
            alpha: xyz.alpha
        }
    }
}

impl From<Lab> for Luma {
    fn from(lab: Lab) -> Luma {
        Xyz::from(lab).into()
    }
}

impl From<Lch> for Luma {
    fn from(lch: Lch) -> Luma {
        Xyz::from(lch).into()
    }
}

impl From<Hsv> for Luma {
    fn from(hsv: Hsv) -> Luma {
        Rgb::from(hsv).into()
    }
}

impl From<Hsl> for Luma {
    fn from(hsl: Hsl) -> Luma {
        Rgb::from(hsl).into()
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use basedir::default_config_dir;
use opts;
use resource_files::resources_dir_path;
use rustc_serialize::json::{Json, ToJson};
use std::borrow::ToOwned;
use std::collections::HashMap;
use std::fs::File;
use std::io::{Read, Write, stderr};
use std::path::PathBuf;
use std::sync::{Arc, Mutex};

lazy_static! {
    pub static ref PREFS: Preferences = {
        let prefs = read_prefs().unwrap_or_else(|_| HashMap::new());
        Preferences(Arc::new(Mutex::new(prefs)))
    };
}

#[derive(PartialEq, Clone, Debug)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
pub enum PrefValue {
    Boolean(bool),
    String(String),
    Number(f64),
    Missing
}

impl PrefValue {
    pub fn from_json(data: Json) -> Result<PrefValue, ()> {
        let value = match data {
            Json::Boolean(x) => PrefValue::Boolean(x),
            Json::String(x) => PrefValue::String(x),
            Json::F64(x) => PrefValue::Number(x),
            Json::I64(x) => PrefValue::Number(x as f64),
            Json::U64(x) => PrefValue::Number(x as f64),
            _ => return Err(())
        };
        Ok(value)
    }

    pub fn as_boolean(&self) -> Option<bool> {
        match *self {
            PrefValue::Boolean(value) => {
                Some(value)
            },
            _ => None
        }
    }

    pub fn as_string(&self) -> Option<&str> {
        match *self {
            PrefValue::String(ref value) => {
                Some(&value)
            },
            _ => None
        }
    }

    pub fn as_i64(&self) -> Option<i64> {
        match *self {
            PrefValue::Number(x) => Some(x as i64),
            _ => None,
        }
    }

    pub fn as_u64(&self) -> Option<u64> {
        match *self {
            PrefValue::Number(x) => Some(x as u64),
            _ => None,
        }
    }
}

impl ToJson for PrefValue {
    fn to_json(&self) -> Json {
        match *self {
            PrefValue::Boolean(x) => {
                Json::Boolean(x)
            },
            PrefValue::String(ref x) => {
                Json::String(x.clone())
            },
            PrefValue::Number(x) => {
                Json::F64(x)
            },
            PrefValue::Missing => Json::Null
        }
    }
}

#[derive(Clone, Debug)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
pub enum Pref {
    NoDefault(Arc<PrefValue>),
    WithDefault(Arc<PrefValue>, Option<Arc<PrefValue>>)
}

impl Pref {
    pub fn new(value: PrefValue) -> Pref {
        Pref::NoDefault(Arc::new(value))
    }

    fn new_default(value: PrefValue) -> Pref {
        Pref::WithDefault(Arc::new(value), None)
    }

    fn from_json(data: Json) -> Result<Pref, ()> {
        let value = try!(PrefValue::from_json(data));
        Ok(Pref::new_default(value))
    }

    pub fn value(&self) -> &Arc<PrefValue> {
        match *self {
            Pref::NoDefault(ref x) => x,
            Pref::WithDefault(ref default, ref override_value) => {
                match *override_value {
                    Some(ref x) => x,
                    None => default
                }
            }
        }
    }

    fn set(&mut self, value: PrefValue) {
        // TODO - this should error if we try to override a pref of one type
        // with a value of a different type
        match *self {
            Pref::NoDefault(ref mut pref_value) => {
                *pref_value = Arc::new(value)
            },
            Pref::WithDefault(_, ref mut override_value) => {
                *override_value = Some(Arc::new(value))
            }
        }
    }
}

impl ToJson for Pref {
    fn to_json(&self) -> Json {
        self.value().to_json()
    }
}

pub fn read_prefs_from_file<T>(mut file: T)
    -> Result<HashMap<String, Pref>, ()> where T: Read {
    let json = try!(Json::from_reader(&mut file).or_else(|e| {
        println!("Ignoring invalid JSON in preferences: {:?}.", e);
        Err(())
    }));

    let mut prefs = HashMap::new();
    if let Json::Object(obj) = json {
        for (name, value) in obj.into_iter() {
            match Pref::from_json(value) {
                Ok(x) => {
                    prefs.insert(name, x);
                },
                Err(_) => println!("Ignoring non-boolean/string/i64 preference value for {:?}", name),
            }
        }
    }
    Ok(prefs)
}

pub fn add_user_prefs() {
    match opts::get().config_dir {
        Some(ref config_path) => {
            let mut path = PathBuf::from(config_path);
            init_user_prefs(&mut path);
        }
        None => {
            let mut path = default_config_dir().unwrap();
            if path.join("prefs.json").exists() {
                init_user_prefs(&mut path);
            }
        }
    }
}

fn init_user_prefs(path: &mut PathBuf) {
    path.push("prefs.json");
    if let Ok(file) = File::open(path) {
        if let Ok(prefs) = read_prefs_from_file(file) {
            PREFS.extend(prefs);
        }
    } else {
    writeln!(&mut stderr(), "Error opening prefs.json from config directory")
        .expect("failed printing to stderr");
    }
}

fn read_prefs() -> Result<HashMap<String, Pref>, ()> {
    let mut path = resources_dir_path();
    path.push("prefs.json");

    let file = try!(File::open(path).or_else(|e| {
        writeln!(&mut stderr(), "Error opening preferences: {:?}.", e)
            .expect("failed printing to stderr");
        Err(())
    }));

    read_prefs_from_file(file)
}

pub struct Preferences(Arc<Mutex<HashMap<String, Pref>>>);

impl Preferences {
    pub fn get(&self, name: &str) -> Arc<PrefValue> {
        self.0.lock().unwrap().get(name).map_or(Arc::new(PrefValue::Missing), |x| x.value().clone())
    }

    pub fn cloned(&self) -> HashMap<String, Pref> {
        self.0.lock().unwrap().clone()
    }

    pub fn is_mozbrowser_enabled(&self) -> bool {
        self.get("dom.mozbrowser.enabled").as_boolean().unwrap_or(false)
    }

    pub fn set(&self, name: &str, value: PrefValue) {
        let mut prefs = self.0.lock().unwrap();
        if let Some(pref) = prefs.get_mut(name) {
            pref.set(value);
            return;
        }
        prefs.insert(name.to_owned(), Pref::new(value));
    }

    pub fn reset(&self, name: &str) -> Arc<PrefValue> {
        let mut prefs = self.0.lock().unwrap();
        let result = match prefs.get_mut(name) {
            None => return Arc::new(PrefValue::Missing),
            Some(&mut Pref::NoDefault(_)) => Arc::new(PrefValue::Missing),
            Some(&mut Pref::WithDefault(ref default, ref mut set_value)) => {
                *set_value = None;
                default.clone()
            },
        };
        if *result == PrefValue::Missing {
            prefs.remove(name);
        }
        result
    }

    pub fn reset_all(&self) {
        let names = {
            self.0.lock().unwrap().keys().cloned().collect::<Vec<String>>()
        };
        for name in names.iter() {
            self.reset(name);
        }
    }

    pub fn extend(&self, extension: HashMap<String, Pref>) {
        self.0.lock().unwrap().extend(extension);
    }
}
<commit_msg>prefs: Make the preferences be guarded by a RwLock instead of a Mutex<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use basedir::default_config_dir;
use opts;
use resource_files::resources_dir_path;
use rustc_serialize::json::{Json, ToJson};
use std::borrow::ToOwned;
use std::collections::HashMap;
use std::fs::File;
use std::io::{Read, Write, stderr};
use std::path::PathBuf;
use std::sync::{Arc, RwLock};

lazy_static! {
    pub static ref PREFS: Preferences = {
        let prefs = read_prefs().ok().unwrap_or_else(HashMap::new);
        Preferences(Arc::new(RwLock::new(prefs)))
    };
}

#[derive(PartialEq, Clone, Debug)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
pub enum PrefValue {
    Boolean(bool),
    String(String),
    Number(f64),
    Missing
}

impl PrefValue {
    pub fn from_json(data: Json) -> Result<PrefValue, ()> {
        let value = match data {
            Json::Boolean(x) => PrefValue::Boolean(x),
            Json::String(x) => PrefValue::String(x),
            Json::F64(x) => PrefValue::Number(x),
            Json::I64(x) => PrefValue::Number(x as f64),
            Json::U64(x) => PrefValue::Number(x as f64),
            _ => return Err(())
        };
        Ok(value)
    }

    pub fn as_boolean(&self) -> Option<bool> {
        match *self {
            PrefValue::Boolean(value) => {
                Some(value)
            },
            _ => None
        }
    }

    pub fn as_string(&self) -> Option<&str> {
        match *self {
            PrefValue::String(ref value) => {
                Some(&value)
            },
            _ => None
        }
    }

    pub fn as_i64(&self) -> Option<i64> {
        match *self {
            PrefValue::Number(x) => Some(x as i64),
            _ => None,
        }
    }

    pub fn as_u64(&self) -> Option<u64> {
        match *self {
            PrefValue::Number(x) => Some(x as u64),
            _ => None,
        }
    }
}

impl ToJson for PrefValue {
    fn to_json(&self) -> Json {
        match *self {
            PrefValue::Boolean(x) => {
                Json::Boolean(x)
            },
            PrefValue::String(ref x) => {
                Json::String(x.clone())
            },
            PrefValue::Number(x) => {
                Json::F64(x)
            },
            PrefValue::Missing => Json::Null
        }
    }
}

#[derive(Clone, Debug)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
pub enum Pref {
    NoDefault(Arc<PrefValue>),
    WithDefault(Arc<PrefValue>, Option<Arc<PrefValue>>)
}

impl Pref {
    pub fn new(value: PrefValue) -> Pref {
        Pref::NoDefault(Arc::new(value))
    }

    fn new_default(value: PrefValue) -> Pref {
        Pref::WithDefault(Arc::new(value), None)
    }

    fn from_json(data: Json) -> Result<Pref, ()> {
        let value = try!(PrefValue::from_json(data));
        Ok(Pref::new_default(value))
    }

    pub fn value(&self) -> &Arc<PrefValue> {
        match *self {
            Pref::NoDefault(ref x) => x,
            Pref::WithDefault(ref default, ref override_value) => {
                match *override_value {
                    Some(ref x) => x,
                    None => default
                }
            }
        }
    }

    fn set(&mut self, value: PrefValue) {
        // TODO - this should error if we try to override a pref of one type
        // with a value of a different type
        match *self {
            Pref::NoDefault(ref mut pref_value) => {
                *pref_value = Arc::new(value)
            },
            Pref::WithDefault(_, ref mut override_value) => {
                *override_value = Some(Arc::new(value))
            }
        }
    }
}

impl ToJson for Pref {
    fn to_json(&self) -> Json {
        self.value().to_json()
    }
}

pub fn read_prefs_from_file<T>(mut file: T)
    -> Result<HashMap<String, Pref>, ()> where T: Read {
    let json = try!(Json::from_reader(&mut file).or_else(|e| {
        println!("Ignoring invalid JSON in preferences: {:?}.", e);
        Err(())
    }));

    let mut prefs = HashMap::new();
    if let Json::Object(obj) = json {
        for (name, value) in obj.into_iter() {
            match Pref::from_json(value) {
                Ok(x) => {
                    prefs.insert(name, x);
                },
                Err(_) => println!("Ignoring non-boolean/string/i64 preference value for {:?}", name),
            }
        }
    }
    Ok(prefs)
}

pub fn add_user_prefs() {
    match opts::get().config_dir {
        Some(ref config_path) => {
            let mut path = PathBuf::from(config_path);
            init_user_prefs(&mut path);
        }
        None => {
            let mut path = default_config_dir().unwrap();
            if path.join("prefs.json").exists() {
                init_user_prefs(&mut path);
            }
        }
    }
}

fn init_user_prefs(path: &mut PathBuf) {
    path.push("prefs.json");
    if let Ok(file) = File::open(path) {
        if let Ok(prefs) = read_prefs_from_file(file) {
            PREFS.extend(prefs);
        }
    } else {
    writeln!(&mut stderr(), "Error opening prefs.json from config directory")
        .expect("failed printing to stderr");
    }
}

fn read_prefs() -> Result<HashMap<String, Pref>, ()> {
    let mut path = resources_dir_path();
    path.push("prefs.json");

    let file = try!(File::open(path).or_else(|e| {
        writeln!(&mut stderr(), "Error opening preferences: {:?}.", e)
            .expect("failed printing to stderr");
        Err(())
    }));

    read_prefs_from_file(file)
}

pub struct Preferences(Arc<RwLock<HashMap<String, Pref>>>);

impl Preferences {
    pub fn get(&self, name: &str) -> Arc<PrefValue> {
        self.0.read().unwrap().get(name).map_or(Arc::new(PrefValue::Missing), |x| x.value().clone())
    }

    pub fn cloned(&self) -> HashMap<String, Pref> {
        self.0.read().unwrap().clone()
    }

    pub fn is_mozbrowser_enabled(&self) -> bool {
        self.get("dom.mozbrowser.enabled").as_boolean().unwrap_or(false)
    }

    pub fn set(&self, name: &str, value: PrefValue) {
        let mut prefs = self.0.write().unwrap();
        if let Some(pref) = prefs.get_mut(name) {
            pref.set(value);
            return;
        }
        prefs.insert(name.to_owned(), Pref::new(value));
    }

    pub fn reset(&self, name: &str) -> Arc<PrefValue> {
        let mut prefs = self.0.write().unwrap();
        let result = match prefs.get_mut(name) {
            None => return Arc::new(PrefValue::Missing),
            Some(&mut Pref::NoDefault(_)) => Arc::new(PrefValue::Missing),
            Some(&mut Pref::WithDefault(ref default, ref mut set_value)) => {
                *set_value = None;
                default.clone()
            },
        };
        if *result == PrefValue::Missing {
            prefs.remove(name);
        }
        result
    }

    pub fn reset_all(&self) {
        let names = {
            self.0.read().unwrap().keys().cloned().collect::<Vec<String>>()
        };
        for name in names.iter() {
            self.reset(name);
        }
    }

    pub fn extend(&self, extension: HashMap<String, Pref>) {
        self.0.write().unwrap().extend(extension);
    }
}
<|endoftext|>


<commit_before>//! This module contains everything needed to instantiate an interpreter.
//! This separation exists to ensure that no fancy miri features like
//! interpreting common C functions leak into CTFE.

use std::borrow::{Borrow, Cow};
use std::hash::Hash;

use rustc::hir::def_id::DefId;
use rustc::mir;
use rustc::ty::{self, Ty, TyCtxt};
use syntax_pos::Span;

use super::{
    Allocation, AllocId, InterpResult, Scalar, AllocationExtra,
    InterpCx, PlaceTy, OpTy, ImmTy, MemoryKind, Pointer, Memory,
    Frame, Operand,
};

/// Data returned by Machine::stack_pop,
/// to provide further control over the popping of the stack frame
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub enum StackPopInfo {
    /// Indicates that we have just started unwinding
    /// as the result of panic
    StartUnwinding,

    /// Indicates that we performed a normal return
    Normal,

    /// Indicates that we should stop unwinding,
    /// as we've reached a catch frame
    StopUnwinding
}

/// Whether this kind of memory is allowed to leak
pub trait MayLeak: Copy {
    fn may_leak(self) -> bool;
}

/// The functionality needed by memory to manage its allocations
pub trait AllocMap<K: Hash + Eq, V> {
    /// Tests if the map contains the given key.
    /// Deliberately takes `&mut` because that is sufficient, and some implementations
    /// can be more efficient then (using `RefCell::get_mut`).
    fn contains_key<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> bool
        where K: Borrow<Q>;

    /// Inserts a new entry into the map.
    fn insert(&mut self, k: K, v: V) -> Option<V>;

    /// Removes an entry from the map.
    fn remove<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> Option<V>
        where K: Borrow<Q>;

    /// Returns data based the keys and values in the map.
    fn filter_map_collect<T>(&self, f: impl FnMut(&K, &V) -> Option<T>) -> Vec<T>;

    /// Returns a reference to entry `k`. If no such entry exists, call
    /// `vacant` and either forward its error, or add its result to the map
    /// and return a reference to *that*.
    fn get_or<E>(
        &self,
        k: K,
        vacant: impl FnOnce() -> Result<V, E>
    ) -> Result<&V, E>;

    /// Returns a mutable reference to entry `k`. If no such entry exists, call
    /// `vacant` and either forward its error, or add its result to the map
    /// and return a reference to *that*.
    fn get_mut_or<E>(
        &mut self,
        k: K,
        vacant: impl FnOnce() -> Result<V, E>
    ) -> Result<&mut V, E>;

    /// Read-only lookup.
    fn get(&self, k: K) -> Option<&V> {
        self.get_or(k, || Err(())).ok()
    }

    /// Mutable lookup.
    fn get_mut(&mut self, k: K) -> Option<&mut V> {
        self.get_mut_or(k, || Err(())).ok()
    }
}

/// Methods of this trait signifies a point where CTFE evaluation would fail
/// and some use case dependent behaviour can instead be applied.
pub trait Machine<'mir, 'tcx>: Sized {
    /// Additional memory kinds a machine wishes to distinguish from the builtin ones
    type MemoryKinds: ::std::fmt::Debug + MayLeak + Eq + 'static;

    /// Tag tracked alongside every pointer. This is used to implement "Stacked Borrows"
    /// <https://www.ralfj.de/blog/2018/08/07/stacked-borrows.html>.
    /// The `default()` is used for pointers to consts, statics, vtables and functions.
    type PointerTag: ::std::fmt::Debug + Copy + Eq + Hash + 'static;

    /// Machines can define extra (non-instance) things that represent values of function pointers.
    /// For example, Miri uses this to return a fucntion pointer from `dlsym`
    /// that can later be called to execute the right thing.
    type ExtraFnVal: ::std::fmt::Debug + Copy;

    /// Extra data stored in every call frame.
    type FrameExtra;

    /// Extra data stored in memory. A reference to this is available when `AllocExtra`
    /// gets initialized, so you can e.g., have an `Rc` here if there is global state you
    /// need access to in the `AllocExtra` hooks.
    type MemoryExtra;

    /// Extra data stored in every allocation.
    type AllocExtra: AllocationExtra<Self::PointerTag> + 'static;

    /// Memory's allocation map
    type MemoryMap:
        AllocMap<
            AllocId,
            (MemoryKind<Self::MemoryKinds>, Allocation<Self::PointerTag, Self::AllocExtra>)
        > +
        Default +
        Clone;

    /// The memory kind to use for copied statics -- or None if statics should not be mutated
    /// and thus any such attempt will cause a `ModifiedStatic` error to be raised.
    /// Statics are copied under two circumstances: When they are mutated, and when
    /// `tag_allocation` or `find_foreign_static` (see below) returns an owned allocation
    /// that is added to the memory so that the work is not done twice.
    const STATIC_KIND: Option<Self::MemoryKinds>;

    /// Whether memory accesses should be alignment-checked.
    const CHECK_ALIGN: bool;

    /// Whether to enforce the validity invariant
    fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;

    /// Called before a basic block terminator is executed.
    /// You can use this to detect endlessly running programs.
    fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx>;

    /// Entry point to all function calls.
    ///
    /// Returns either the mir to use for the call, or `None` if execution should
    /// just proceed (which usually means this hook did all the work that the
    /// called function should usually have done). In the latter case, it is
    /// this hook's responsibility to call `goto_block(ret)` to advance the instruction pointer!
    /// (This is to support functions like `__rust_maybe_catch_panic` that neither find a MIR
    /// nor just jump to `ret`, but instead push their own stack frame.)
    /// Passing `dest`and `ret` in the same `Option` proved very annoying when only one of them
    /// was used.
    fn find_fn(
        ecx: &mut InterpCx<'mir, 'tcx, Self>,
        instance: ty::Instance<'tcx>,
        args: &[OpTy<'tcx, Self::PointerTag>],
        dest: Option<PlaceTy<'tcx, Self::PointerTag>>,
        ret: Option<mir::BasicBlock>,
        unwind: Option<mir::BasicBlock>
    ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>>;

    /// Execute `fn_val`.  it is the hook's responsibility to advance the instruction
    /// pointer as appropriate.
    fn call_extra_fn(
        ecx: &mut InterpCx<'mir, 'tcx, Self>,
        fn_val: Self::ExtraFnVal,
        args: &[OpTy<'tcx, Self::PointerTag>],
        dest: Option<PlaceTy<'tcx, Self::PointerTag>>,
        ret: Option<mir::BasicBlock>,
    ) -> InterpResult<'tcx>;

    /// Directly process an intrinsic without pushing a stack frame.
    /// If this returns successfully, the engine will take care of jumping to the next block.
    fn call_intrinsic(
        ecx: &mut InterpCx<'mir, 'tcx, Self>,
        span: Span,
        instance: ty::Instance<'tcx>,
        args: &[OpTy<'tcx, Self::PointerTag>],
        dest: Option<PlaceTy<'tcx, Self::PointerTag>>,
    ) -> InterpResult<'tcx>;

    /// Called for read access to a foreign static item.
    ///
    /// This will only be called once per static and machine; the result is cached in
    /// the machine memory. (This relies on `AllocMap::get_or` being able to add the
    /// owned allocation to the map even when the map is shared.)
    ///
    /// This allocation will then be fed to `tag_allocation` to initialize the "extra" state.
    fn find_foreign_static(
        tcx: TyCtxt<'tcx>,
        def_id: DefId,
    ) -> InterpResult<'tcx, Cow<'tcx, Allocation>>;

    /// Called for all binary operations where the LHS has pointer type.
    ///
    /// Returns a (value, overflowed) pair if the operation succeeded
    fn binary_ptr_op(
        ecx: &InterpCx<'mir, 'tcx, Self>,
        bin_op: mir::BinOp,
        left: ImmTy<'tcx, Self::PointerTag>,
        right: ImmTy<'tcx, Self::PointerTag>,
    ) -> InterpResult<'tcx, (Scalar<Self::PointerTag>, bool, Ty<'tcx>)>;

    /// Heap allocations via the `box` keyword.
    fn box_alloc(
        ecx: &mut InterpCx<'mir, 'tcx, Self>,
        dest: PlaceTy<'tcx, Self::PointerTag>,
    ) -> InterpResult<'tcx>;

    /// Called to read the specified `local` from the `frame`.
    fn access_local(
        _ecx: &InterpCx<'mir, 'tcx, Self>,
        frame: &Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>,
        local: mir::Local,
    ) -> InterpResult<'tcx, Operand<Self::PointerTag>> {
        frame.locals[local].access()
    }

    /// Called before a `StaticKind::Static` value is accessed.
    fn before_access_static(
        _allocation: &Allocation,
    ) -> InterpResult<'tcx> {
        Ok(())
    }

    /// Called to initialize the "extra" state of an allocation and make the pointers
    /// it contains (in relocations) tagged.  The way we construct allocations is
    /// to always first construct it without extra and then add the extra.
    /// This keeps uniform code paths for handling both allocations created by CTFE
    /// for statics, and allocations ceated by Miri during evaluation.
    ///
    /// `kind` is the kind of the allocation being tagged; it can be `None` when
    /// it's a static and `STATIC_KIND` is `None`.
    ///
    /// This should avoid copying if no work has to be done! If this returns an owned
    /// allocation (because a copy had to be done to add tags or metadata), machine memory will
    /// cache the result. (This relies on `AllocMap::get_or` being able to add the
    /// owned allocation to the map even when the map is shared.)
    ///
    /// For static allocations, the tag returned must be the same as the one returned by
    /// `tag_static_base_pointer`.
    fn tag_allocation<'b>(
        memory_extra: &Self::MemoryExtra,
        id: AllocId,
        alloc: Cow<'b, Allocation>,
        kind: Option<MemoryKind<Self::MemoryKinds>>,
    ) -> (Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>>, Self::PointerTag);

    /// Return the "base" tag for the given static allocation: the one that is used for direct
    /// accesses to this static/const/fn allocation.
    ///
    /// Be aware that requesting the `Allocation` for that `id` will lead to cycles
    /// for cyclic statics!
    fn tag_static_base_pointer(
        memory_extra: &Self::MemoryExtra,
        id: AllocId,
    ) -> Self::PointerTag;

    /// Executes a retagging operation
    #[inline]
    fn retag(
        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
        _kind: mir::RetagKind,
        _place: PlaceTy<'tcx, Self::PointerTag>,
    ) -> InterpResult<'tcx> {
        Ok(())
    }

    /// Called immediately before a new stack frame got pushed
    fn stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx, Self::FrameExtra>;

    /// Called immediately after a stack frame gets popped
    fn stack_pop(
        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
        _extra: Self::FrameExtra,
        _unwinding: bool
    ) -> InterpResult<'tcx, StackPopInfo> {
        // By default, we do not support unwinding from panics
        Ok(StackPopInfo::Normal)
    }

    fn int_to_ptr(
        _mem: &Memory<'mir, 'tcx, Self>,
        int: u64,
    ) -> InterpResult<'tcx, Pointer<Self::PointerTag>> {
        Err((if int == 0 {
            err_unsup!(InvalidNullPointerUsage)
        } else {
            err_unsup!(ReadBytesAsPointer)
        }).into())
    }

    fn ptr_to_int(
        _mem: &Memory<'mir, 'tcx, Self>,
        _ptr: Pointer<Self::PointerTag>,
    ) -> InterpResult<'tcx, u64>;
}
<commit_msg>Make doc comment more accurate<commit_after>//! This module contains everything needed to instantiate an interpreter.
//! This separation exists to ensure that no fancy miri features like
//! interpreting common C functions leak into CTFE.

use std::borrow::{Borrow, Cow};
use std::hash::Hash;

use rustc::hir::def_id::DefId;
use rustc::mir;
use rustc::ty::{self, Ty, TyCtxt};
use syntax_pos::Span;

use super::{
    Allocation, AllocId, InterpResult, Scalar, AllocationExtra,
    InterpCx, PlaceTy, OpTy, ImmTy, MemoryKind, Pointer, Memory,
    Frame, Operand,
};

/// Data returned by Machine::stack_pop,
/// to provide further control over the popping of the stack frame
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub enum StackPopInfo {
    /// Indicates that we have just started unwinding
    /// as the result of panic
    StartUnwinding,

    /// Indicates that no special handling should be
    /// done - we'll either return normally or unwind
    /// based on the terminator for the function
    /// we're leaving.
    Normal,

    /// Indicates that we should stop unwinding,
    /// as we've reached a catch frame
    StopUnwinding
}

/// Whether this kind of memory is allowed to leak
pub trait MayLeak: Copy {
    fn may_leak(self) -> bool;
}

/// The functionality needed by memory to manage its allocations
pub trait AllocMap<K: Hash + Eq, V> {
    /// Tests if the map contains the given key.
    /// Deliberately takes `&mut` because that is sufficient, and some implementations
    /// can be more efficient then (using `RefCell::get_mut`).
    fn contains_key<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> bool
        where K: Borrow<Q>;

    /// Inserts a new entry into the map.
    fn insert(&mut self, k: K, v: V) -> Option<V>;

    /// Removes an entry from the map.
    fn remove<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> Option<V>
        where K: Borrow<Q>;

    /// Returns data based the keys and values in the map.
    fn filter_map_collect<T>(&self, f: impl FnMut(&K, &V) -> Option<T>) -> Vec<T>;

    /// Returns a reference to entry `k`. If no such entry exists, call
    /// `vacant` and either forward its error, or add its result to the map
    /// and return a reference to *that*.
    fn get_or<E>(
        &self,
        k: K,
        vacant: impl FnOnce() -> Result<V, E>
    ) -> Result<&V, E>;

    /// Returns a mutable reference to entry `k`. If no such entry exists, call
    /// `vacant` and either forward its error, or add its result to the map
    /// and return a reference to *that*.
    fn get_mut_or<E>(
        &mut self,
        k: K,
        vacant: impl FnOnce() -> Result<V, E>
    ) -> Result<&mut V, E>;

    /// Read-only lookup.
    fn get(&self, k: K) -> Option<&V> {
        self.get_or(k, || Err(())).ok()
    }

    /// Mutable lookup.
    fn get_mut(&mut self, k: K) -> Option<&mut V> {
        self.get_mut_or(k, || Err(())).ok()
    }
}

/// Methods of this trait signifies a point where CTFE evaluation would fail
/// and some use case dependent behaviour can instead be applied.
pub trait Machine<'mir, 'tcx>: Sized {
    /// Additional memory kinds a machine wishes to distinguish from the builtin ones
    type MemoryKinds: ::std::fmt::Debug + MayLeak + Eq + 'static;

    /// Tag tracked alongside every pointer. This is used to implement "Stacked Borrows"
    /// <https://www.ralfj.de/blog/2018/08/07/stacked-borrows.html>.
    /// The `default()` is used for pointers to consts, statics, vtables and functions.
    type PointerTag: ::std::fmt::Debug + Copy + Eq + Hash + 'static;

    /// Machines can define extra (non-instance) things that represent values of function pointers.
    /// For example, Miri uses this to return a fucntion pointer from `dlsym`
    /// that can later be called to execute the right thing.
    type ExtraFnVal: ::std::fmt::Debug + Copy;

    /// Extra data stored in every call frame.
    type FrameExtra;

    /// Extra data stored in memory. A reference to this is available when `AllocExtra`
    /// gets initialized, so you can e.g., have an `Rc` here if there is global state you
    /// need access to in the `AllocExtra` hooks.
    type MemoryExtra;

    /// Extra data stored in every allocation.
    type AllocExtra: AllocationExtra<Self::PointerTag> + 'static;

    /// Memory's allocation map
    type MemoryMap:
        AllocMap<
            AllocId,
            (MemoryKind<Self::MemoryKinds>, Allocation<Self::PointerTag, Self::AllocExtra>)
        > +
        Default +
        Clone;

    /// The memory kind to use for copied statics -- or None if statics should not be mutated
    /// and thus any such attempt will cause a `ModifiedStatic` error to be raised.
    /// Statics are copied under two circumstances: When they are mutated, and when
    /// `tag_allocation` or `find_foreign_static` (see below) returns an owned allocation
    /// that is added to the memory so that the work is not done twice.
    const STATIC_KIND: Option<Self::MemoryKinds>;

    /// Whether memory accesses should be alignment-checked.
    const CHECK_ALIGN: bool;

    /// Whether to enforce the validity invariant
    fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;

    /// Called before a basic block terminator is executed.
    /// You can use this to detect endlessly running programs.
    fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx>;

    /// Entry point to all function calls.
    ///
    /// Returns either the mir to use for the call, or `None` if execution should
    /// just proceed (which usually means this hook did all the work that the
    /// called function should usually have done). In the latter case, it is
    /// this hook's responsibility to call `goto_block(ret)` to advance the instruction pointer!
    /// (This is to support functions like `__rust_maybe_catch_panic` that neither find a MIR
    /// nor just jump to `ret`, but instead push their own stack frame.)
    /// Passing `dest`and `ret` in the same `Option` proved very annoying when only one of them
    /// was used.
    fn find_fn(
        ecx: &mut InterpCx<'mir, 'tcx, Self>,
        instance: ty::Instance<'tcx>,
        args: &[OpTy<'tcx, Self::PointerTag>],
        dest: Option<PlaceTy<'tcx, Self::PointerTag>>,
        ret: Option<mir::BasicBlock>,
        unwind: Option<mir::BasicBlock>
    ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>>;

    /// Execute `fn_val`.  it is the hook's responsibility to advance the instruction
    /// pointer as appropriate.
    fn call_extra_fn(
        ecx: &mut InterpCx<'mir, 'tcx, Self>,
        fn_val: Self::ExtraFnVal,
        args: &[OpTy<'tcx, Self::PointerTag>],
        dest: Option<PlaceTy<'tcx, Self::PointerTag>>,
        ret: Option<mir::BasicBlock>,
    ) -> InterpResult<'tcx>;

    /// Directly process an intrinsic without pushing a stack frame.
    /// If this returns successfully, the engine will take care of jumping to the next block.
    fn call_intrinsic(
        ecx: &mut InterpCx<'mir, 'tcx, Self>,
        span: Span,
        instance: ty::Instance<'tcx>,
        args: &[OpTy<'tcx, Self::PointerTag>],
        dest: Option<PlaceTy<'tcx, Self::PointerTag>>,
    ) -> InterpResult<'tcx>;

    /// Called for read access to a foreign static item.
    ///
    /// This will only be called once per static and machine; the result is cached in
    /// the machine memory. (This relies on `AllocMap::get_or` being able to add the
    /// owned allocation to the map even when the map is shared.)
    ///
    /// This allocation will then be fed to `tag_allocation` to initialize the "extra" state.
    fn find_foreign_static(
        tcx: TyCtxt<'tcx>,
        def_id: DefId,
    ) -> InterpResult<'tcx, Cow<'tcx, Allocation>>;

    /// Called for all binary operations where the LHS has pointer type.
    ///
    /// Returns a (value, overflowed) pair if the operation succeeded
    fn binary_ptr_op(
        ecx: &InterpCx<'mir, 'tcx, Self>,
        bin_op: mir::BinOp,
        left: ImmTy<'tcx, Self::PointerTag>,
        right: ImmTy<'tcx, Self::PointerTag>,
    ) -> InterpResult<'tcx, (Scalar<Self::PointerTag>, bool, Ty<'tcx>)>;

    /// Heap allocations via the `box` keyword.
    fn box_alloc(
        ecx: &mut InterpCx<'mir, 'tcx, Self>,
        dest: PlaceTy<'tcx, Self::PointerTag>,
    ) -> InterpResult<'tcx>;

    /// Called to read the specified `local` from the `frame`.
    fn access_local(
        _ecx: &InterpCx<'mir, 'tcx, Self>,
        frame: &Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>,
        local: mir::Local,
    ) -> InterpResult<'tcx, Operand<Self::PointerTag>> {
        frame.locals[local].access()
    }

    /// Called before a `StaticKind::Static` value is accessed.
    fn before_access_static(
        _allocation: &Allocation,
    ) -> InterpResult<'tcx> {
        Ok(())
    }

    /// Called to initialize the "extra" state of an allocation and make the pointers
    /// it contains (in relocations) tagged.  The way we construct allocations is
    /// to always first construct it without extra and then add the extra.
    /// This keeps uniform code paths for handling both allocations created by CTFE
    /// for statics, and allocations ceated by Miri during evaluation.
    ///
    /// `kind` is the kind of the allocation being tagged; it can be `None` when
    /// it's a static and `STATIC_KIND` is `None`.
    ///
    /// This should avoid copying if no work has to be done! If this returns an owned
    /// allocation (because a copy had to be done to add tags or metadata), machine memory will
    /// cache the result. (This relies on `AllocMap::get_or` being able to add the
    /// owned allocation to the map even when the map is shared.)
    ///
    /// For static allocations, the tag returned must be the same as the one returned by
    /// `tag_static_base_pointer`.
    fn tag_allocation<'b>(
        memory_extra: &Self::MemoryExtra,
        id: AllocId,
        alloc: Cow<'b, Allocation>,
        kind: Option<MemoryKind<Self::MemoryKinds>>,
    ) -> (Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>>, Self::PointerTag);

    /// Return the "base" tag for the given static allocation: the one that is used for direct
    /// accesses to this static/const/fn allocation.
    ///
    /// Be aware that requesting the `Allocation` for that `id` will lead to cycles
    /// for cyclic statics!
    fn tag_static_base_pointer(
        memory_extra: &Self::MemoryExtra,
        id: AllocId,
    ) -> Self::PointerTag;

    /// Executes a retagging operation
    #[inline]
    fn retag(
        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
        _kind: mir::RetagKind,
        _place: PlaceTy<'tcx, Self::PointerTag>,
    ) -> InterpResult<'tcx> {
        Ok(())
    }

    /// Called immediately before a new stack frame got pushed
    fn stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx, Self::FrameExtra>;

    /// Called immediately after a stack frame gets popped
    fn stack_pop(
        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
        _extra: Self::FrameExtra,
        _unwinding: bool
    ) -> InterpResult<'tcx, StackPopInfo> {
        // By default, we do not support unwinding from panics
        Ok(StackPopInfo::Normal)
    }

    fn int_to_ptr(
        _mem: &Memory<'mir, 'tcx, Self>,
        int: u64,
    ) -> InterpResult<'tcx, Pointer<Self::PointerTag>> {
        Err((if int == 0 {
            err_unsup!(InvalidNullPointerUsage)
        } else {
            err_unsup!(ReadBytesAsPointer)
        }).into())
    }

    fn ptr_to_int(
        _mem: &Memory<'mir, 'tcx, Self>,
        _ptr: Pointer<Self::PointerTag>,
    ) -> InterpResult<'tcx, u64>;
}
<|endoftext|>