<commit_before>//! An abstract input state object that gets fed user
//! events and updates itself based on a set of key
//! bindings.
//!
//! The goals are:
//!
//! * Have a layer of abstract key bindings rather than
//! looking at concrete event types
//! * Use this to be able to abstract away differences
//! between keyboards, joysticks and game controllers
//! (rather based on Unity3D),
//! * Do some tweening of input axes and stuff just for
//! fun.
//! * Take ggez's event-based input API, and present event- or
//! state-based API so you can do whichever you want.

// TODO: Handle mice, game pads, joysticks

use std::hash::Hash;
use std::collections::HashMap;
use ggez::event::*;

// Okay, but how does it actually work?
// Basically we have to bind input events to buttons and axes.
// Input events can be keys, mouse buttons/motion, or eventually
// joystick/controller inputs.  Mouse delta can be mapped to axes too.
//
// https://docs.unity3d.com/Manual/ConventionalGameInput.html has useful
// descriptions of the exact behavior of axes.
//
// So to think about this more clearly, here are the default bindings:
//
// W, ↑: +Y axis
// A, ←: -X axis
// S, ↓: -Y axis
// D, →: +X axis
// Enter, z, LMB: Button 1
// Shift, x, MMB: Button 2
// Ctrl,  c, RMB: Button 3
//
// Easy way?  Hash map of event -> axis/button bindings.

#[derive(Debug, Hash, Eq, PartialEq, Copy, Clone)]
enum InputType {
    KeyEvent(Keycode), // MouseButtonEvent,
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum InputEffect<Axes, Buttons>
    where Axes: Eq + Hash + Clone,
          Buttons: Eq + Hash + Clone
{
    Axis {
        axis: Axes,
        positive: bool,
        started: bool,
    },
    Button {
        button: Buttons,
        started: bool,
    },
}

#[derive(Debug, Copy, Clone)]
struct AxisState {
    // Where the axis currently is, in [-1, 1]
    position: f64,
    // Where the axis is moving towards.  Possible
    // values are -1, 0, +1
    // (or a continuous range for analog devices I guess)
    direction: f64,
    // Speed in units per second that the axis
    // moves towards the target value.
    acceleration: f64,
    // Speed in units per second that the axis will
    // fall back toward 0 if the input stops.
    gravity: f64,
}

impl Default for AxisState {
    fn default() -> Self {
        AxisState {
            position: 0.0,
            direction: 0.0,
            acceleration: 4.0,
            gravity: 3.0,
        }
    }
}

#[derive(Debug, Copy, Clone, Default)]
struct ButtonState {
    pressed: bool,
    pressed_last_frame: bool,
}

/// A struct that contains a mapping from physical input events
/// (currently just `Keycode`s) to whatever your logical Axis/Button
/// types are.
pub struct InputBinding<Axes, Buttons>
    where Axes: Hash + Eq + Clone,
          Buttons: Hash + Eq + Clone
{
    // Once EnumSet is stable it should be used for these
    // instead of BTreeMap. ♥?
    // Binding of keys to input values.
    bindings: HashMap<InputType, InputEffect<Axes, Buttons>>,
}

impl<Axes, Buttons> InputBinding<Axes, Buttons>
    where Axes: Hash + Eq + Clone,
          Buttons: Hash + Eq + Clone
{
    pub fn new() -> Self {
        InputBinding { bindings: HashMap::new() }
    }

    /// Adds a key binding connecting the given keycode to the given
    /// logical axis.
    pub fn bind_key_to_axis(mut self, keycode: Keycode, axis: Axes, positive: bool) -> Self {

        self.bindings.insert(InputType::KeyEvent(keycode),
                             InputEffect::Axis { axis: axis.clone(), positive: positive, started: false });
        self
    }

    /// Adds a key binding connecting the given keycode to the given
    /// logical button.
    pub fn bind_key_to_button(mut self, keycode: Keycode, button: Buttons) -> Self {
        self.bindings.insert(InputType::KeyEvent(keycode),
                             InputEffect::Button { button: button.clone(), started: false });
        self
    }

    /// Takes an physical input type and turns it into a logical input type (keycode -> axis/button).
    pub fn resolve(&self, keycode: Keycode) -> Option<InputEffect<Axes, Buttons>> {
        self.bindings.get(&InputType::KeyEvent(keycode)).cloned()
    }
}

#[derive(Debug)]
pub struct InputState<Axes, Buttons>
    where Axes: Hash + Eq + Clone,
          Buttons: Hash + Eq + Clone
{
    // Input state for axes
    axes: HashMap<Axes, AxisState>,
    // Input states for buttons
    buttons: HashMap<Buttons, ButtonState>,
}

impl<Axes, Buttons> InputState<Axes, Buttons>
    where Axes: Eq + Hash + Clone,
          Buttons: Eq + Hash + Clone
{
    pub fn new() -> Self {
        InputState {
            axes: HashMap::new(),
            buttons: HashMap::new(),
        }
    }

    /// Updates the logical input state based on the actual
    /// physical input state.  Should be called in your update()
    /// handler.
    /// So, it will do things like move the axes and so on.
    pub fn update(&mut self, dt: f64) {
        for (_axis, axis_status) in self.axes.iter_mut() {
            if axis_status.direction != 0.0 {
                // Accelerate the axis towards the
                // input'ed direction.
                let abs_dx = f64::min(axis_status.acceleration * dt,
                                      1.0 - f64::abs(axis_status.position));
                let dx = if axis_status.direction > 0.0 {
                    abs_dx
                } else {
                    -abs_dx
                };
                axis_status.position += dx;
            } else {
                // Gravitate back towards 0.
                let abs_dx = f64::min(axis_status.gravity * dt, f64::abs(axis_status.position));
                let dx = if axis_status.position > 0.0 {
                    -abs_dx
                } else {
                    abs_dx
                };
                axis_status.position += dx;
            }
        }
        for (_button, button_status) in self.buttons.iter_mut() {
            button_status.pressed_last_frame = button_status.pressed;
        }
    }

    /// This method should get called by your key_down_event handler.
    pub fn update_button_down(&mut self, button: Buttons) {
        self.update_effect(InputEffect::Button { button, started: true });
    }

    /// This method should get called by your key_up_event handler.
    pub fn update_button_up(&mut self, button: Buttons) {
        self.update_effect(InputEffect::Button { button, started: false });
    }

    /// This method should get called by your key_up_event handler.
    pub fn update_axis_start(&mut self, axis: Axes, positive: bool) {
        self.update_effect(InputEffect::Axis { axis: axis, positive: positive, started: true });
    }

    pub fn update_axis_stop(&mut self, axis: Axes, positive: bool) {
        self.update_effect(InputEffect::Axis { axis: axis, positive: positive, started: false });
    }

    /// Takes an InputEffect and actually applies it.
    pub fn update_effect(&mut self, effect: InputEffect<Axes, Buttons>) {
        match effect {
            InputEffect::Axis { axis, positive, started } => {
                let f = || AxisState::default();
                let axis_status = self.axes.entry(axis).or_insert_with(f);
                if started {
                    let direction_float = if positive { 1.0 } else { -1.0 };
                    axis_status.direction = direction_float;
                } else {
                    axis_status.direction = 0.0;
                }
            }
            InputEffect::Button { button, started } => {
                let f = || ButtonState::default();
                let button_status = self.buttons.entry(button).or_insert_with(f);
                button_status.pressed = started;
            }
        }
    }

    pub fn get_axis(&self, axis: Axes) -> f64 {
        let d = AxisState::default();
        let axis_status = self.axes.get(&axis).unwrap_or(&d);
        axis_status.position
    }

    pub fn get_axis_raw(&self, axis: Axes) -> f64 {
        let d = AxisState::default();
        let axis_status = self.axes.get(&axis).unwrap_or(&d);
        axis_status.direction
    }

    fn get_button(&self, button: Buttons) -> ButtonState {
        let d = ButtonState::default();
        let button_status = self.buttons.get(&button).unwrap_or(&d);
        *button_status
    }

    pub fn get_button_down(&self, axis: Buttons) -> bool {
        self.get_button(axis).pressed
    }

    pub fn get_button_up(&self, axis: Buttons) -> bool {
        !self.get_button(axis).pressed
    }

    /// Returns whether or not the button was pressed this frame,
    /// only returning true if the press happened this frame.
    ///
    /// Basically, `get_button_down()` and `get_button_up()` are level
    /// triggers, this and `get_button_released()` are edge triggered.
    pub fn get_button_pressed(&self, axis: Buttons) -> bool {
        let b = self.get_button(axis);
        b.pressed && !b.pressed_last_frame
    }

    pub fn get_button_released(&self, axis: Buttons) -> bool {
        let b = self.get_button(axis);
        !b.pressed && b.pressed_last_frame
    }

    pub fn mouse_position() {
        unimplemented!()
    }

    pub fn mouse_scroll_delta() {
        unimplemented!()
    }

    pub fn get_mouse_button() {
        unimplemented!()
    }

    pub fn get_mouse_button_down() {
        unimplemented!()
    }

    pub fn get_mouse_button_up() {
        unimplemented!()
    }

    pub fn reset_input_state(&mut self) {
        for (_axis, axis_status) in self.axes.iter_mut() {
            axis_status.position = 0.0;
            axis_status.direction = 0.0;
        }

        for (_button, button_status) in self.buttons.iter_mut() {
            button_status.pressed = false;
            button_status.pressed_last_frame = false;
        }
    }
}

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

    #[derive(Hash, Eq, PartialEq, Copy, Clone, Debug)]
    enum Buttons {
        A,
        B,
        Select,
        Start,
    }

    #[derive(Hash, Eq, PartialEq, Copy, Clone, Debug)]
    enum Axes {
        Horz,
        Vert,
    }

    fn make_input_binding() -> InputBinding<Axes, Buttons> {
        let ib = InputBinding::<Axes, Buttons>::new()
            .bind_key_to_button(Keycode::Z, Buttons::A)
            .bind_key_to_button(Keycode::X, Buttons::B)
            .bind_key_to_button(Keycode::Return, Buttons::Start)
            .bind_key_to_button(Keycode::RShift, Buttons::Select)
            .bind_key_to_button(Keycode::LShift, Buttons::Select)
            .bind_key_to_axis(Keycode::Up, Axes::Vert, true)
            .bind_key_to_axis(Keycode::Down, Axes::Vert, false)
            .bind_key_to_axis(Keycode::Left, Axes::Horz, false)
            .bind_key_to_axis(Keycode::Right, Axes::Horz, true);
        ib
    }

    #[test]
    fn test_input_bindings() {
        let ib = make_input_binding();
        assert_eq!(ib.resolve(Keycode::Z),
                   Some(InputEffect::Button{button: Buttons::A, started: false}));
        assert_eq!(ib.resolve(Keycode::X),
                   Some(InputEffect::Button{button: Buttons::B, started: false}));
        assert_eq!(ib.resolve(Keycode::Return),
                   Some(InputEffect::Button{button: Buttons::Start, started: false}));
        assert_eq!(ib.resolve(Keycode::RShift),
                   Some(InputEffect::Button{button: Buttons::Select, started: false}));
        assert_eq!(ib.resolve(Keycode::LShift),
                   Some(InputEffect::Button{button: Buttons::Select, started: false}));

        assert_eq!(ib.resolve(Keycode::Up),
                   Some(InputEffect::Axis{axis: Axes::Vert, positive: true, started: false}));
        assert_eq!(ib.resolve(Keycode::Down),
                   Some(InputEffect::Axis{axis: Axes::Vert, positive: false, started: false}));
        assert_eq!(ib.resolve(Keycode::Left),
                   Some(InputEffect::Axis{axis: Axes::Horz, positive: false, started: false}));
        assert_eq!(ib.resolve(Keycode::Right),
                   Some(InputEffect::Axis{axis: Axes::Horz, positive: true, started: false}));

        assert_eq!(ib.resolve(Keycode::Q), None);
        assert_eq!(ib.resolve(Keycode::W), None);
    }

    #[test]
    fn test_input_events() {
        let mut im = InputState::new();
        im.update_button_down(Buttons::A);
        assert!(im.get_button_down(Buttons::A));
        im.update_button_up(Buttons::A);
        assert!(!im.get_button_down(Buttons::A));
        assert!(im.get_button_up(Buttons::A));

        // Push the 'up' button, watch the axis
        // increase to 1.0 but not beyond
        im.update_axis_start(Axes::Vert, true);
        assert!(im.get_axis_raw(Axes::Vert) > 0.0);
        while im.get_axis(Axes::Vert) < 0.99 {
            im.update(0.16);
            assert!(im.get_axis(Axes::Vert) >= 0.0);
            assert!(im.get_axis(Axes::Vert) <= 1.0);
        }
        // Release it, watch it wind down
        im.update_axis_stop(Axes::Vert, true);
        while im.get_axis(Axes::Vert) > 0.01 {
            im.update(0.16);
            assert!(im.get_axis(Axes::Vert) >= 0.0)
        }

        // Do the same with the 'down' button.
        im.update_axis_start(Axes::Vert, false);
        while im.get_axis(Axes::Vert) > -0.99 {
            im.update(0.16);
            assert!(im.get_axis(Axes::Vert) <= 0.0);
            assert!(im.get_axis(Axes::Vert) >= -1.0);
        }
    }

    #[test]
    fn test_button_edge_transitions() {
        let mut im: InputState<Axis, Buttons> = InputState::new();

        // Push a key, confirm it's transitioned.
        assert!(!im.get_button_down(Buttons::A));
        im.update_button_down(Buttons::A);
        assert!(im.get_button_down(Buttons::A));
        assert!(im.get_button_pressed(Buttons::A));
        assert!(!im.get_button_released(Buttons::A));

        // Update, confirm it's still down but
        // wasn't pressed this frame
        im.update(0.1);
        assert!(im.get_button_down(Buttons::A));
        assert!(!im.get_button_pressed(Buttons::A));
        assert!(!im.get_button_released(Buttons::A));

        // Release it
        im.update_button_up(Buttons::A);
        assert!(im.get_button_up(Buttons::A));
        assert!(!im.get_button_pressed(Buttons::A));
        assert!(im.get_button_released(Buttons::A));
        im.update(0.1);
        assert!(im.get_button_up(Buttons::A));
        assert!(!im.get_button_pressed(Buttons::A));
        assert!(!im.get_button_released(Buttons::A));
    }
}
<commit_msg>Replace f64 with f32 in input<commit_after>//! An abstract input state object that gets fed user
//! events and updates itself based on a set of key
//! bindings.
//!
//! The goals are:
//!
//! * Have a layer of abstract key bindings rather than
//! looking at concrete event types
//! * Use this to be able to abstract away differences
//! between keyboards, joysticks and game controllers
//! (rather based on Unity3D),
//! * Do some tweening of input axes and stuff just for
//! fun.
//! * Take ggez's event-based input API, and present event- or
//! state-based API so you can do whichever you want.

// TODO: Handle mice, game pads, joysticks

use std::hash::Hash;
use std::collections::HashMap;
use ggez::event::*;

// Okay, but how does it actually work?
// Basically we have to bind input events to buttons and axes.
// Input events can be keys, mouse buttons/motion, or eventually
// joystick/controller inputs.  Mouse delta can be mapped to axes too.
//
// https://docs.unity3d.com/Manual/ConventionalGameInput.html has useful
// descriptions of the exact behavior of axes.
//
// So to think about this more clearly, here are the default bindings:
//
// W, ↑: +Y axis
// A, ←: -X axis
// S, ↓: -Y axis
// D, →: +X axis
// Enter, z, LMB: Button 1
// Shift, x, MMB: Button 2
// Ctrl,  c, RMB: Button 3
//
// Easy way?  Hash map of event -> axis/button bindings.

#[derive(Debug, Hash, Eq, PartialEq, Copy, Clone)]
enum InputType {
    KeyEvent(Keycode), // MouseButtonEvent,
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum InputEffect<Axes, Buttons>
    where Axes: Eq + Hash + Clone,
          Buttons: Eq + Hash + Clone
{
    Axis {
        axis: Axes,
        positive: bool,
        started: bool,
    },
    Button {
        button: Buttons,
        started: bool,
    },
}

#[derive(Debug, Copy, Clone)]
struct AxisState {
    // Where the axis currently is, in [-1, 1]
    position: f32,
    // Where the axis is moving towards.  Possible
    // values are -1, 0, +1
    // (or a continuous range for analog devices I guess)
    direction: f32,
    // Speed in units per second that the axis
    // moves towards the target value.
    acceleration: f32,
    // Speed in units per second that the axis will
    // fall back toward 0 if the input stops.
    gravity: f32,
}

impl Default for AxisState {
    fn default() -> Self {
        AxisState {
            position: 0.0,
            direction: 0.0,
            acceleration: 4.0,
            gravity: 3.0,
        }
    }
}

#[derive(Debug, Copy, Clone, Default)]
struct ButtonState {
    pressed: bool,
    pressed_last_frame: bool,
}

/// A struct that contains a mapping from physical input events
/// (currently just `Keycode`s) to whatever your logical Axis/Button
/// types are.
pub struct InputBinding<Axes, Buttons>
    where Axes: Hash + Eq + Clone,
          Buttons: Hash + Eq + Clone
{
    // Once EnumSet is stable it should be used for these
    // instead of BTreeMap. ♥?
    // Binding of keys to input values.
    bindings: HashMap<InputType, InputEffect<Axes, Buttons>>,
}

impl<Axes, Buttons> InputBinding<Axes, Buttons>
    where Axes: Hash + Eq + Clone,
          Buttons: Hash + Eq + Clone
{
    pub fn new() -> Self {
        InputBinding { bindings: HashMap::new() }
    }

    /// Adds a key binding connecting the given keycode to the given
    /// logical axis.
    pub fn bind_key_to_axis(mut self, keycode: Keycode, axis: Axes, positive: bool) -> Self {

        self.bindings.insert(InputType::KeyEvent(keycode),
                             InputEffect::Axis { axis: axis.clone(), positive: positive, started: false });
        self
    }

    /// Adds a key binding connecting the given keycode to the given
    /// logical button.
    pub fn bind_key_to_button(mut self, keycode: Keycode, button: Buttons) -> Self {
        self.bindings.insert(InputType::KeyEvent(keycode),
                             InputEffect::Button { button: button.clone(), started: false });
        self
    }

    /// Takes an physical input type and turns it into a logical input type (keycode -> axis/button).
    pub fn resolve(&self, keycode: Keycode) -> Option<InputEffect<Axes, Buttons>> {
        self.bindings.get(&InputType::KeyEvent(keycode)).cloned()
    }
}

#[derive(Debug)]
pub struct InputState<Axes, Buttons>
    where Axes: Hash + Eq + Clone,
          Buttons: Hash + Eq + Clone
{
    // Input state for axes
    axes: HashMap<Axes, AxisState>,
    // Input states for buttons
    buttons: HashMap<Buttons, ButtonState>,
}

impl<Axes, Buttons> InputState<Axes, Buttons>
    where Axes: Eq + Hash + Clone,
          Buttons: Eq + Hash + Clone
{
    pub fn new() -> Self {
        InputState {
            axes: HashMap::new(),
            buttons: HashMap::new(),
        }
    }

    /// Updates the logical input state based on the actual
    /// physical input state.  Should be called in your update()
    /// handler.
    /// So, it will do things like move the axes and so on.
    pub fn update(&mut self, dt: f32) {
        for (_axis, axis_status) in self.axes.iter_mut() {
            if axis_status.direction != 0.0 {
                // Accelerate the axis towards the
                // input'ed direction.
                let abs_dx = f32::min(axis_status.acceleration * dt,
                                      1.0 - f32::abs(axis_status.position));
                let dx = if axis_status.direction > 0.0 {
                    abs_dx
                } else {
                    -abs_dx
                };
                axis_status.position += dx;
            } else {
                // Gravitate back towards 0.
                let abs_dx = f32::min(axis_status.gravity * dt, f32::abs(axis_status.position));
                let dx = if axis_status.position > 0.0 {
                    -abs_dx
                } else {
                    abs_dx
                };
                axis_status.position += dx;
            }
        }
        for (_button, button_status) in self.buttons.iter_mut() {
            button_status.pressed_last_frame = button_status.pressed;
        }
    }

    /// This method should get called by your key_down_event handler.
    pub fn update_button_down(&mut self, button: Buttons) {
        self.update_effect(InputEffect::Button { button, started: true });
    }

    /// This method should get called by your key_up_event handler.
    pub fn update_button_up(&mut self, button: Buttons) {
        self.update_effect(InputEffect::Button { button, started: false });
    }

    /// This method should get called by your key_up_event handler.
    pub fn update_axis_start(&mut self, axis: Axes, positive: bool) {
        self.update_effect(InputEffect::Axis { axis: axis, positive: positive, started: true });
    }

    pub fn update_axis_stop(&mut self, axis: Axes, positive: bool) {
        self.update_effect(InputEffect::Axis { axis: axis, positive: positive, started: false });
    }

    /// Takes an InputEffect and actually applies it.
    pub fn update_effect(&mut self, effect: InputEffect<Axes, Buttons>) {
        match effect {
            InputEffect::Axis { axis, positive, started } => {
                let f = || AxisState::default();
                let axis_status = self.axes.entry(axis).or_insert_with(f);
                if started {
                    let direction_float = if positive { 1.0 } else { -1.0 };
                    axis_status.direction = direction_float;
                } else {
                    axis_status.direction = 0.0;
                }
            }
            InputEffect::Button { button, started } => {
                let f = || ButtonState::default();
                let button_status = self.buttons.entry(button).or_insert_with(f);
                button_status.pressed = started;
            }
        }
    }

    pub fn get_axis(&self, axis: Axes) -> f32 {
        let d = AxisState::default();
        let axis_status = self.axes.get(&axis).unwrap_or(&d);
        axis_status.position
    }

    pub fn get_axis_raw(&self, axis: Axes) -> f32 {
        let d = AxisState::default();
        let axis_status = self.axes.get(&axis).unwrap_or(&d);
        axis_status.direction
    }

    fn get_button(&self, button: Buttons) -> ButtonState {
        let d = ButtonState::default();
        let button_status = self.buttons.get(&button).unwrap_or(&d);
        *button_status
    }

    pub fn get_button_down(&self, axis: Buttons) -> bool {
        self.get_button(axis).pressed
    }

    pub fn get_button_up(&self, axis: Buttons) -> bool {
        !self.get_button(axis).pressed
    }

    /// Returns whether or not the button was pressed this frame,
    /// only returning true if the press happened this frame.
    ///
    /// Basically, `get_button_down()` and `get_button_up()` are level
    /// triggers, this and `get_button_released()` are edge triggered.
    pub fn get_button_pressed(&self, axis: Buttons) -> bool {
        let b = self.get_button(axis);
        b.pressed && !b.pressed_last_frame
    }

    pub fn get_button_released(&self, axis: Buttons) -> bool {
        let b = self.get_button(axis);
        !b.pressed && b.pressed_last_frame
    }

    pub fn mouse_position() {
        unimplemented!()
    }

    pub fn mouse_scroll_delta() {
        unimplemented!()
    }

    pub fn get_mouse_button() {
        unimplemented!()
    }

    pub fn get_mouse_button_down() {
        unimplemented!()
    }

    pub fn get_mouse_button_up() {
        unimplemented!()
    }

    pub fn reset_input_state(&mut self) {
        for (_axis, axis_status) in self.axes.iter_mut() {
            axis_status.position = 0.0;
            axis_status.direction = 0.0;
        }

        for (_button, button_status) in self.buttons.iter_mut() {
            button_status.pressed = false;
            button_status.pressed_last_frame = false;
        }
    }
}

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

    #[derive(Hash, Eq, PartialEq, Copy, Clone, Debug)]
    enum Buttons {
        A,
        B,
        Select,
        Start,
    }

    #[derive(Hash, Eq, PartialEq, Copy, Clone, Debug)]
    enum Axes {
        Horz,
        Vert,
    }

    fn make_input_binding() -> InputBinding<Axes, Buttons> {
        let ib = InputBinding::<Axes, Buttons>::new()
            .bind_key_to_button(Keycode::Z, Buttons::A)
            .bind_key_to_button(Keycode::X, Buttons::B)
            .bind_key_to_button(Keycode::Return, Buttons::Start)
            .bind_key_to_button(Keycode::RShift, Buttons::Select)
            .bind_key_to_button(Keycode::LShift, Buttons::Select)
            .bind_key_to_axis(Keycode::Up, Axes::Vert, true)
            .bind_key_to_axis(Keycode::Down, Axes::Vert, false)
            .bind_key_to_axis(Keycode::Left, Axes::Horz, false)
            .bind_key_to_axis(Keycode::Right, Axes::Horz, true);
        ib
    }

    #[test]
    fn test_input_bindings() {
        let ib = make_input_binding();
        assert_eq!(ib.resolve(Keycode::Z),
                   Some(InputEffect::Button{button: Buttons::A, started: false}));
        assert_eq!(ib.resolve(Keycode::X),
                   Some(InputEffect::Button{button: Buttons::B, started: false}));
        assert_eq!(ib.resolve(Keycode::Return),
                   Some(InputEffect::Button{button: Buttons::Start, started: false}));
        assert_eq!(ib.resolve(Keycode::RShift),
                   Some(InputEffect::Button{button: Buttons::Select, started: false}));
        assert_eq!(ib.resolve(Keycode::LShift),
                   Some(InputEffect::Button{button: Buttons::Select, started: false}));

        assert_eq!(ib.resolve(Keycode::Up),
                   Some(InputEffect::Axis{axis: Axes::Vert, positive: true, started: false}));
        assert_eq!(ib.resolve(Keycode::Down),
                   Some(InputEffect::Axis{axis: Axes::Vert, positive: false, started: false}));
        assert_eq!(ib.resolve(Keycode::Left),
                   Some(InputEffect::Axis{axis: Axes::Horz, positive: false, started: false}));
        assert_eq!(ib.resolve(Keycode::Right),
                   Some(InputEffect::Axis{axis: Axes::Horz, positive: true, started: false}));

        assert_eq!(ib.resolve(Keycode::Q), None);
        assert_eq!(ib.resolve(Keycode::W), None);
    }

    #[test]
    fn test_input_events() {
        let mut im = InputState::new();
        im.update_button_down(Buttons::A);
        assert!(im.get_button_down(Buttons::A));
        im.update_button_up(Buttons::A);
        assert!(!im.get_button_down(Buttons::A));
        assert!(im.get_button_up(Buttons::A));

        // Push the 'up' button, watch the axis
        // increase to 1.0 but not beyond
        im.update_axis_start(Axes::Vert, true);
        assert!(im.get_axis_raw(Axes::Vert) > 0.0);
        while im.get_axis(Axes::Vert) < 0.99 {
            im.update(0.16);
            assert!(im.get_axis(Axes::Vert) >= 0.0);
            assert!(im.get_axis(Axes::Vert) <= 1.0);
        }
        // Release it, watch it wind down
        im.update_axis_stop(Axes::Vert, true);
        while im.get_axis(Axes::Vert) > 0.01 {
            im.update(0.16);
            assert!(im.get_axis(Axes::Vert) >= 0.0)
        }

        // Do the same with the 'down' button.
        im.update_axis_start(Axes::Vert, false);
        while im.get_axis(Axes::Vert) > -0.99 {
            im.update(0.16);
            assert!(im.get_axis(Axes::Vert) <= 0.0);
            assert!(im.get_axis(Axes::Vert) >= -1.0);
        }
    }

    #[test]
    fn test_button_edge_transitions() {
        let mut im: InputState<Axis, Buttons> = InputState::new();

        // Push a key, confirm it's transitioned.
        assert!(!im.get_button_down(Buttons::A));
        im.update_button_down(Buttons::A);
        assert!(im.get_button_down(Buttons::A));
        assert!(im.get_button_pressed(Buttons::A));
        assert!(!im.get_button_released(Buttons::A));

        // Update, confirm it's still down but
        // wasn't pressed this frame
        im.update(0.1);
        assert!(im.get_button_down(Buttons::A));
        assert!(!im.get_button_pressed(Buttons::A));
        assert!(!im.get_button_released(Buttons::A));

        // Release it
        im.update_button_up(Buttons::A);
        assert!(im.get_button_up(Buttons::A));
        assert!(!im.get_button_pressed(Buttons::A));
        assert!(im.get_button_released(Buttons::A));
        im.update(0.1);
        assert!(im.get_button_up(Buttons::A));
        assert!(!im.get_button_pressed(Buttons::A));
        assert!(!im.get_button_released(Buttons::A));
    }
}
<|endoftext|>


<commit_before>use std::fs;
use std::path::Path;
use std::path::PathBuf;

#[derive(Debug, Clone, Copy)]
pub enum InputTypes {
    Matroska,
    Mpeg4,
    Avi,
    DgIndex,
    DgAvc,
    Other,
}

pub fn get_list_of_files(path: &Path, recursive: bool) -> Result<Vec<PathBuf>, String> {
    if path.is_file() {
        return Ok(vec![path.to_owned()]);
    }
    if !path.is_dir() {
        return Err(
            "Cannot handle file, perhaps it's a symlink or you don't have proper \
             permissions?"
                .to_owned(),
        );
    }
    let mut files: Vec<PathBuf> = vec![];
    get_recursive_files(path, &mut files, recursive);
    Ok(files)
}

fn get_recursive_files(path: &Path, mut files: &mut Vec<PathBuf>, recursive: bool) {
    let paths = fs::read_dir(path).unwrap();
    for path in paths {
        let next = path.unwrap().path();
        if next.is_file() {
            files.push(next.clone());
        }
        if recursive && next.is_dir() {
            get_recursive_files(next.as_ref(), &mut files, recursive);
        }
    }
}

pub fn determine_input_type(path: &Path) -> Option<InputTypes> {
    // This is simplistic and assumes that the extension is a source of truth
    // TODO: Make this look at the container headers instead
    let extension = path.extension().unwrap().to_str().unwrap().to_lowercase();
    match extension.as_ref() {
        "mkv" => Some(InputTypes::Matroska),
        "mp4" => Some(InputTypes::Mpeg4),
        "avi" => Some(InputTypes::Avi),
        "d2v" => Some(InputTypes::DgIndex),
        "dga" => Some(InputTypes::DgAvc),
        "mpeg" | "mpg" | "wmv" | "mov" | "flv" | "webm" => Some(InputTypes::Other),
        _ => None,
    }
}
<commit_msg>Add ivf input detection<commit_after>use std::fs;
use std::path::Path;
use std::path::PathBuf;

#[derive(Debug, Clone, Copy)]
pub enum InputTypes {
    Matroska,
    Mpeg4,
    Avi,
    DgIndex,
    DgAvc,
    Other,
}

pub fn get_list_of_files(path: &Path, recursive: bool) -> Result<Vec<PathBuf>, String> {
    if path.is_file() {
        return Ok(vec![path.to_owned()]);
    }
    if !path.is_dir() {
        return Err(
            "Cannot handle file, perhaps it's a symlink or you don't have proper \
             permissions?"
                .to_owned(),
        );
    }
    let mut files: Vec<PathBuf> = vec![];
    get_recursive_files(path, &mut files, recursive);
    Ok(files)
}

fn get_recursive_files(path: &Path, mut files: &mut Vec<PathBuf>, recursive: bool) {
    let paths = fs::read_dir(path).unwrap();
    for path in paths {
        let next = path.unwrap().path();
        if next.is_file() {
            files.push(next.clone());
        }
        if recursive && next.is_dir() {
            get_recursive_files(next.as_ref(), &mut files, recursive);
        }
    }
}

pub fn determine_input_type(path: &Path) -> Option<InputTypes> {
    // This is simplistic and assumes that the extension is a source of truth
    // TODO: Make this look at the container headers instead
    let extension = path.extension().unwrap().to_str().unwrap().to_lowercase();
    match extension.as_ref() {
        "mkv" => Some(InputTypes::Matroska),
        "mp4" => Some(InputTypes::Mpeg4),
        "avi" => Some(InputTypes::Avi),
        "d2v" => Some(InputTypes::DgIndex),
        "dga" => Some(InputTypes::DgAvc),
        "mpeg" | "mpg" | "wmv" | "mov" | "flv" | "webm" | "ivf" => Some(InputTypes::Other),
        _ => None,
    }
}
<|endoftext|>


<commit_before>//  K8055.rs is a library for controlling the Vellemann K8055 USB IO card from rust.
//  Copyright (C) 2014 Falco Hirschenberger <falco.hirschenberger@gmail.com>
//
//  This program is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation; either version 2 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License along
//  with this program; if not, write to the Free Software Foundation, Inc.,
//  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

//! Driver library for controlling the *Vellemann K8055(N)* USB digital and analog IO-cards.
//!
//! See the Vellemann [Homepage](http://www.velleman.eu/products/view/?id=351346) for the
//! hardware specification.

#![crate_type = "lib"]
extern crate libc;
extern crate usb;
extern crate serialize;

use std::iter::range_inclusive;
use std::fmt::{Show, Formatter, Error};
use std::default::Default;
use usb::libusb;

/// Analog values in the range (0-255).
#[deriving(PartialEq, PartialOrd, Show)]
pub enum AnalogChannel {
      A1(u8),
      A2(u8)
}

bitflags!(
#[doc = "
The digital channel values.

Can be combined with bitoperations.

    let dc = D1 & D2 & D3;

See the bitflags documentation for more information.
"]
  flags DigitalChannel: u8 {
#[doc = "All flags set to `off`"]
    const DZERO = 0,
    const D1 = 1,
    const D2 = 2,
    const D3 = 4,
    const D4 = 8,
    const D5 = 16,
    const D6 = 32,
    const D7 = 64,
    const D8 = 128,
#[doc = "All flags set to `on`"]
    const DALL = 255
  }
)

bitflags!(
#[doc = "
Adresses of the different cards that can be controlled.

See the jumper setting on your card for the correct address.
"]
    flags CardAddress: uint {
#[doc = "Use card `0x5500` (see jumper settings)"]
        const CARD_1 = 0x5500,
#[doc = "Use card `0x5501` (see jumper settings)"]
        const CARD_2 = 0x5501,
#[doc = "Use card `0x5502` (see jumper settings)"]
        const CARD_3 = 0x5502,
#[doc = "Use card `0x5503` (see jumper settings)"]
        const CARD_4 = 0x5503,
#[doc = "Automatically selects the first card found on the system"]
        const CARD_ANY = 0x0
    }
)

static VENDOR_ID: uint = 0x10cfu;

#[deriving(Show)]
enum Packet {
    Reset,
    SetAnalogDigital(u8, u8, u8),
    Status(u8, u8, u8, u8)
}

#[deriving(Default)]
struct State {
    dig: u8,
    ana1: u8,
    ana2: u8
}

/// Object controlling one Vellemann K8055 card.
pub struct K8055 {
    dev: usb::Device,
    hd: Option<usb::DeviceHandle>,
    state: State
}

impl K8055 {
    /// Create a new K8055 instance with the first card found on the system.
    ///
    /// May return `None` if no card was found connected to the system.
    pub fn new() -> Option<K8055> {
        K8055::new_addr(CARD_ANY)
    }

    /// Create a new K8055 instance with a specific card address.
    ///
    /// See the hardware jumpers on the card for your card's address. May return `None` if no card
    /// with the address `addr` can be found connected to the system.
    pub fn new_addr(addr: CardAddress) -> Option<K8055> {
        let c = usb::Context::new();
        let d = if addr == CARD_ANY {
            K8055::find_any_k8055(&c)
        } else {
            c.find_by_vid_pid(VENDOR_ID, addr.bits)
        };

        if d.is_some() {
            return Some(K8055{ dev: d.unwrap(), hd: None, state: Default::default() })
        } else {
            return None
        }
    }

    /// Open the device for starting IO operations.
    ///
    /// Returns `true` if the device was successfully opened or is already open. Returns `false`
    /// if the device can't be opened.
    pub fn open(&mut self) -> bool {
      // device already open
      if self.hd.is_some() { return true }
      match self.dev.open() {
          Ok(h) => {
              self.hd = Some(h);
              return true
          }
          Err(_) => return false
      }
    }

    /// Set all analog and digital values to zero.
    pub fn reset(&mut self) -> bool {
        self.write(&Packet::SetAnalogDigital(0u8, 0u8, 0u8))
    }

// digital

    /// Write the digital value `d` to the outports.
    ///
    /// Leaves the analog values untouched. Returns `false` on failure.
    pub fn write_digital_out(&mut self, d: DigitalChannel) -> bool {
        let p = &Packet::SetAnalogDigital(d.bits, self.state.ana1, self.state.ana2);
        self.write(p)
    }

    /// Write the masked digital value `d` to the outports.
    ///
    /// Masks `d` with `mask` to only affect bits which are `on` in the mask.
    /// Leaves the analog values untouched. Returns `false` on failure.
    pub fn write_digital_out_mask(&mut self, d: DigitalChannel, mask: DigitalChannel) -> bool {
        self.write_digital_out(d & mask)
    }

    /// Return the bits that are currently set on the digital out channel.
    pub fn get_digital_out(&mut self) -> DigitalChannel {
        DigitalChannel::from_bits(self.state.dig).unwrap()
    }

    /// Return the bits that are currently set on the digital out channel, masked with `mask`.
    pub fn get_digital_out_mask(&mut self, d: DigitalChannel) -> DigitalChannel {
        DigitalChannel::from_bits(self.state.dig).unwrap() & d
    }

    /// Read the digital in channel.
    ///
    /// Returns `None` on failure
    pub fn read_digital_in(&mut self) -> Option<DigitalChannel> {
        match self.read() {
            Some(Packet::Status(dig, _, _, _)) => Some(DigitalChannel::from_bits(dig).unwrap()),
            _ => None
        }
    }

    /// Read the digital in channel masked with `mask`.
    ///
    /// Returns `None` on failure
    pub fn read_digital_in_mask(&mut self, mask: DigitalChannel) -> Option<DigitalChannel> {
        match self.read_digital_in() {
            Some(c) => Some(c & mask),
            _ => None
        }
    }

// analog
    /// Write the analog value `a` to the given outport.
    ///
    /// Leaves the digital values untouched. Returns `false` on failure.
    pub fn write_analog_out(&mut self, a: AnalogChannel) -> bool {
      let p = match a {
          AnalogChannel::A1(v) => Packet::SetAnalogDigital(self.state.dig, v, self.state.ana2),
          AnalogChannel::A2(v) => Packet::SetAnalogDigital(self.state.dig, self.state.ana1, v)
      };
      self.write(&p)
    }

    /// Return the analog channel 1 out value
    pub fn get_analog_out1(&mut self) -> AnalogChannel {
        AnalogChannel::A1(self.state.ana1)
    }

    /// Return the analog channel 2 out value
    pub fn get_analog_out2(&mut self) -> AnalogChannel {
        AnalogChannel::A2(self.state.ana2)
    }

    /// Read the analog channel 1 input value.
    ///
    /// Returns `None` on failure.
    pub fn read_analog_in1(&mut self) -> Option<AnalogChannel> {
        match self.read() {
            Some(Packet::Status(_, _, a1, _)) => Some(AnalogChannel::A1(a1)),
            _ => None
        }
    }

    /// Read the analog channel 2 input value.
    ///
    /// Returns `None` on failure.
    pub fn read_analog_in2(&mut self) -> Option<AnalogChannel> {
        match self.read() {
            Some(Packet::Status(_, _, _, a2)) => Some(AnalogChannel::A2(a2)),
            _ => None
        }
    }

// private
    fn find_any_k8055(c: &usb::Context) -> Option<usb::Device> {
        for pid in range_inclusive(CARD_1.bits, CARD_4.bits) {
          let d = c.find_by_vid_pid(VENDOR_ID, pid);
          if d.is_some() { return d }
        }
        None
    }

    fn write(&mut self, p: &Packet) -> bool {
        match self.hd {
          Some(ref hd) => {
              K8055::detach_and_claim(hd);
              let data = match K8055::encode(p) {
                  Some(d) => d,
                  None => return false
              };

              match hd.write(0x1, libusb::LIBUSB_TRANSFER_TYPE_INTERRUPT, &data) {
                  Ok(_) => {
                      // update the internal state on output changes
                      match *p {
                          Packet::SetAnalogDigital(d, a1, a2) => {
                              self.state = State{dig: d, ana1: a1, ana2: a2};
                          }
                          _ => ()
                      }
                      return true
                  }
                  Err(_) => return false
              }
          }
          None => return false
        }
    }

    fn read(&mut self) -> Option<Packet> {
        match self.hd {
          Some(ref hd) => {
            K8055::detach_and_claim(hd);
            match hd.read(0x81, libusb::LIBUSB_TRANSFER_TYPE_INTERRUPT, 8) {
              Ok(data) => K8055::decode(data.as_slice()),
              Err(_) => None
            }
          }
          None => None
        }
    }

    fn encode(p: &Packet) -> Option<[u8, ..8]> {
      match *p {
          Packet::Reset => Some([0u8, ..8]),
          Packet::SetAnalogDigital(dig, ana1, ana2) => Some([5u8, dig, ana1, ana2,
                                                             0u8, 0u8, 0u8, 0u8]),
          _ => None
      }
    }

    fn decode(d: &[u8]) -> Option<Packet> {
       match d {
          [dig, st, ana1, ana2, _, _, _, _] => Some(Packet::Status(dig, st, ana1, ana2)),
          _ => None
       }
    }

    fn detach_and_claim(hd: &usb::DeviceHandle ) {
      unsafe {
        if libusb::libusb_kernel_driver_active(hd.ptr(), 0) == 1 {
          if libusb::libusb_detach_kernel_driver(hd.ptr(), 0) != 0 {
            panic!("Can't detach usb kernel driver");
          }
        }
      }
      hd.claim_interface(0u);
    }

}

impl Show for K8055 {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
      write!(f, "K8055( bus: {}, address: {} )", self.dev.bus(), self.dev.address())
    }
}

#[test()]
fn find_and_open() {
  let k = K8055::new();
  assert!(k.is_some());
  let mut k = k.unwrap();
  assert!(k.open());
  assert!(K8055::new_addr(CARD_2).is_none());
  assert!(K8055::new_addr(CARD_3).is_none());
  assert!(K8055::new_addr(CARD_4).is_none());
}

#[test()]
fn write_and_read_digital() {
  use std::io::timer::sleep;
  use std::time::duration::Duration;

  let k = K8055::new();
  assert!(k.is_some());
  let mut k = k.unwrap();
  assert!(k.open());
  assert!(k.get_digital_out() == DZERO);
  for i in range(0u, 8) {
    assert!(k.write_digital_out(DigitalChannel::from_bits(1u8<<i).unwrap()));
    assert!(k.get_digital_out() == DigitalChannel::from_bits(1u8<<i).unwrap());
    sleep(Duration::milliseconds(100));
  }
  assert!(k.reset());
  assert!(k.get_digital_out() == DZERO);

  assert!(k.write_digital_out_mask(D1 | D2 | D3, D2));
  assert!(k.get_digital_out() == D2);
  assert!(k.reset());
  sleep(Duration::milliseconds(1000));
}

#[test()]
fn write_and_read_analog() {
  use std::io::timer::sleep;
  use std::time::duration::Duration;

  let k = K8055::new();
  assert!(k.is_some());
  let mut k = k.unwrap();
  assert!(k.open());
  assert!(k.get_analog_out1() == AnalogChannel::A1(0u8));
  assert!(k.get_analog_out2() == AnalogChannel::A2(0u8));
  for i in range(0u8, 255) {
    assert!(k.write_analog_out(AnalogChannel::A1(i)));
    assert!(k.write_analog_out(AnalogChannel::A2(255-i)));
    sleep(Duration::milliseconds(10));
  }
  assert!(k.reset());
  sleep(Duration::milliseconds(1000));
}
<commit_msg>Add Copy trait<commit_after>//  K8055.rs is a library for controlling the Vellemann K8055 USB IO card from rust.
//  Copyright (C) 2014 Falco Hirschenberger <falco.hirschenberger@gmail.com>
//
//  This program is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation; either version 2 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License along
//  with this program; if not, write to the Free Software Foundation, Inc.,
//  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

//! Driver library for controlling the *Vellemann K8055(N)* USB digital and analog IO-cards.
//!
//! See the Vellemann [Homepage](http://www.velleman.eu/products/view/?id=351346) for the
//! hardware specification.

#![crate_type = "lib"]
extern crate libc;
extern crate usb;
extern crate serialize;

use std::iter::range_inclusive;
use std::fmt::{Show, Formatter, Error};
use std::default::Default;
use usb::libusb;

/// Analog values in the range (0-255).
#[deriving(PartialEq, PartialOrd, Show, Copy)]
pub enum AnalogChannel {
      A1(u8),
      A2(u8)
}

bitflags!(
#[doc = "
The digital channel values.

Can be combined with bitoperations.

    let dc = D1 & D2 & D3;

See the bitflags documentation for more information.
"]
  flags DigitalChannel: u8 {
#[doc = "All flags set to `off`"]
    const DZERO = 0,
    const D1 = 1,
    const D2 = 2,
    const D3 = 4,
    const D4 = 8,
    const D5 = 16,
    const D6 = 32,
    const D7 = 64,
    const D8 = 128,
#[doc = "All flags set to `on`"]
    const DALL = 255
  }
)

bitflags!(
#[doc = "
Adresses of the different cards that can be controlled.

See the jumper setting on your card for the correct address.
"]
    flags CardAddress: uint {
#[doc = "Use card `0x5500` (see jumper settings)"]
        const CARD_1 = 0x5500,
#[doc = "Use card `0x5501` (see jumper settings)"]
        const CARD_2 = 0x5501,
#[doc = "Use card `0x5502` (see jumper settings)"]
        const CARD_3 = 0x5502,
#[doc = "Use card `0x5503` (see jumper settings)"]
        const CARD_4 = 0x5503,
#[doc = "Automatically selects the first card found on the system"]
        const CARD_ANY = 0x0
    }
)

static VENDOR_ID: uint = 0x10cfu;

#[deriving(Show)]
enum Packet {
    Reset,
    SetAnalogDigital(u8, u8, u8),
    Status(u8, u8, u8, u8)
}

#[deriving(Default)]
struct State {
    dig: u8,
    ana1: u8,
    ana2: u8
}

/// Object controlling one Vellemann K8055 card.
pub struct K8055 {
    dev: usb::Device,
    hd: Option<usb::DeviceHandle>,
    state: State
}

impl K8055 {
    /// Create a new K8055 instance with the first card found on the system.
    ///
    /// May return `None` if no card was found connected to the system.
    pub fn new() -> Option<K8055> {
        K8055::new_addr(CARD_ANY)
    }

    /// Create a new K8055 instance with a specific card address.
    ///
    /// See the hardware jumpers on the card for your card's address. May return `None` if no card
    /// with the address `addr` can be found connected to the system.
    pub fn new_addr(addr: CardAddress) -> Option<K8055> {
        let c = usb::Context::new();
        let d = if addr == CARD_ANY {
            K8055::find_any_k8055(&c)
        } else {
            c.find_by_vid_pid(VENDOR_ID, addr.bits)
        };

        if d.is_some() {
            return Some(K8055{ dev: d.unwrap(), hd: None, state: Default::default() })
        } else {
            return None
        }
    }

    /// Open the device for starting IO operations.
    ///
    /// Returns `true` if the device was successfully opened or is already open. Returns `false`
    /// if the device can't be opened.
    pub fn open(&mut self) -> bool {
      // device already open
      if self.hd.is_some() { return true }
      match self.dev.open() {
          Ok(h) => {
              self.hd = Some(h);
              return true
          }
          Err(_) => return false
      }
    }

    /// Set all analog and digital values to zero.
    pub fn reset(&mut self) -> bool {
        self.write(&Packet::SetAnalogDigital(0u8, 0u8, 0u8))
    }

// digital

    /// Write the digital value `d` to the outports.
    ///
    /// Leaves the analog values untouched. Returns `false` on failure.
    pub fn write_digital_out(&mut self, d: DigitalChannel) -> bool {
        let p = &Packet::SetAnalogDigital(d.bits, self.state.ana1, self.state.ana2);
        self.write(p)
    }

    /// Write the masked digital value `d` to the outports.
    ///
    /// Masks `d` with `mask` to only affect bits which are `on` in the mask.
    /// Leaves the analog values untouched. Returns `false` on failure.
    pub fn write_digital_out_mask(&mut self, d: DigitalChannel, mask: DigitalChannel) -> bool {
        self.write_digital_out(d & mask)
    }

    /// Return the bits that are currently set on the digital out channel.
    pub fn get_digital_out(&mut self) -> DigitalChannel {
        DigitalChannel::from_bits(self.state.dig).unwrap()
    }

    /// Return the bits that are currently set on the digital out channel, masked with `mask`.
    pub fn get_digital_out_mask(&mut self, d: DigitalChannel) -> DigitalChannel {
        DigitalChannel::from_bits(self.state.dig).unwrap() & d
    }

    /// Read the digital in channel.
    ///
    /// Returns `None` on failure
    pub fn read_digital_in(&mut self) -> Option<DigitalChannel> {
        match self.read() {
            Some(Packet::Status(dig, _, _, _)) => Some(DigitalChannel::from_bits(dig).unwrap()),
            _ => None
        }
    }

    /// Read the digital in channel masked with `mask`.
    ///
    /// Returns `None` on failure
    pub fn read_digital_in_mask(&mut self, mask: DigitalChannel) -> Option<DigitalChannel> {
        match self.read_digital_in() {
            Some(c) => Some(c & mask),
            _ => None
        }
    }

// analog
    /// Write the analog value `a` to the given outport.
    ///
    /// Leaves the digital values untouched. Returns `false` on failure.
    pub fn write_analog_out(&mut self, a: AnalogChannel) -> bool {
      let p = match a {
          AnalogChannel::A1(v) => Packet::SetAnalogDigital(self.state.dig, v, self.state.ana2),
          AnalogChannel::A2(v) => Packet::SetAnalogDigital(self.state.dig, self.state.ana1, v)
      };
      self.write(&p)
    }

    /// Return the analog channel 1 out value
    pub fn get_analog_out1(&mut self) -> AnalogChannel {
        AnalogChannel::A1(self.state.ana1)
    }

    /// Return the analog channel 2 out value
    pub fn get_analog_out2(&mut self) -> AnalogChannel {
        AnalogChannel::A2(self.state.ana2)
    }

    /// Read the analog channel 1 input value.
    ///
    /// Returns `None` on failure.
    pub fn read_analog_in1(&mut self) -> Option<AnalogChannel> {
        match self.read() {
            Some(Packet::Status(_, _, a1, _)) => Some(AnalogChannel::A1(a1)),
            _ => None
        }
    }

    /// Read the analog channel 2 input value.
    ///
    /// Returns `None` on failure.
    pub fn read_analog_in2(&mut self) -> Option<AnalogChannel> {
        match self.read() {
            Some(Packet::Status(_, _, _, a2)) => Some(AnalogChannel::A2(a2)),
            _ => None
        }
    }

// private
    fn find_any_k8055(c: &usb::Context) -> Option<usb::Device> {
        for pid in range_inclusive(CARD_1.bits, CARD_4.bits) {
          let d = c.find_by_vid_pid(VENDOR_ID, pid);
          if d.is_some() { return d }
        }
        None
    }

    fn write(&mut self, p: &Packet) -> bool {
        match self.hd {
          Some(ref hd) => {
              K8055::detach_and_claim(hd);
              let data = match K8055::encode(p) {
                  Some(d) => d,
                  None => return false
              };

              match hd.write(0x1, libusb::LIBUSB_TRANSFER_TYPE_INTERRUPT, &data) {
                  Ok(_) => {
                      // update the internal state on output changes
                      match *p {
                          Packet::SetAnalogDigital(d, a1, a2) => {
                              self.state = State{dig: d, ana1: a1, ana2: a2};
                          }
                          _ => ()
                      }
                      return true
                  }
                  Err(_) => return false
              }
          }
          None => return false
        }
    }

    fn read(&mut self) -> Option<Packet> {
        match self.hd {
          Some(ref hd) => {
            K8055::detach_and_claim(hd);
            match hd.read(0x81, libusb::LIBUSB_TRANSFER_TYPE_INTERRUPT, 8) {
              Ok(data) => K8055::decode(data.as_slice()),
              Err(_) => None
            }
          }
          None => None
        }
    }

    fn encode(p: &Packet) -> Option<[u8, ..8]> {
      match *p {
          Packet::Reset => Some([0u8, ..8]),
          Packet::SetAnalogDigital(dig, ana1, ana2) => Some([5u8, dig, ana1, ana2,
                                                             0u8, 0u8, 0u8, 0u8]),
          _ => None
      }
    }

    fn decode(d: &[u8]) -> Option<Packet> {
       match d {
          [dig, st, ana1, ana2, _, _, _, _] => Some(Packet::Status(dig, st, ana1, ana2)),
          _ => None
       }
    }

    fn detach_and_claim(hd: &usb::DeviceHandle ) {
      unsafe {
        if libusb::libusb_kernel_driver_active(hd.ptr(), 0) == 1 {
          if libusb::libusb_detach_kernel_driver(hd.ptr(), 0) != 0 {
            panic!("Can't detach usb kernel driver");
          }
        }
      }
      hd.claim_interface(0u);
    }

}

impl Show for K8055 {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
      write!(f, "K8055( bus: {}, address: {} )", self.dev.bus(), self.dev.address())
    }
}

#[test()]
fn find_and_open() {
  let k = K8055::new();
  assert!(k.is_some());
  let mut k = k.unwrap();
  assert!(k.open());
  assert!(K8055::new_addr(CARD_2).is_none());
  assert!(K8055::new_addr(CARD_3).is_none());
  assert!(K8055::new_addr(CARD_4).is_none());
}

#[test()]
fn write_and_read_digital() {
  use std::io::timer::sleep;
  use std::time::duration::Duration;

  let k = K8055::new();
  assert!(k.is_some());
  let mut k = k.unwrap();
  assert!(k.open());
  assert!(k.get_digital_out() == DZERO);
  for i in range(0u, 8) {
    assert!(k.write_digital_out(DigitalChannel::from_bits(1u8<<i).unwrap()));
    assert!(k.get_digital_out() == DigitalChannel::from_bits(1u8<<i).unwrap());
    sleep(Duration::milliseconds(100));
  }
  assert!(k.reset());
  assert!(k.get_digital_out() == DZERO);

  assert!(k.write_digital_out_mask(D1 | D2 | D3, D2));
  assert!(k.get_digital_out() == D2);
  assert!(k.reset());
  sleep(Duration::milliseconds(1000));
}

#[test()]
fn write_and_read_analog() {
  use std::io::timer::sleep;
  use std::time::duration::Duration;

  let k = K8055::new();
  assert!(k.is_some());
  let mut k = k.unwrap();
  assert!(k.open());
  assert!(k.get_analog_out1() == AnalogChannel::A1(0u8));
  assert!(k.get_analog_out2() == AnalogChannel::A2(0u8));
  for i in range(0u8, 255) {
    assert!(k.write_analog_out(AnalogChannel::A1(i)));
    assert!(k.write_analog_out(AnalogChannel::A2(255-i)));
    sleep(Duration::milliseconds(10));
  }
  assert!(k.reset());
  sleep(Duration::milliseconds(1000));
}
<|endoftext|>


<commit_before>use tile::Tile;
use util::Grid;
use std::ops::{Index};
use na::Vec2;

pub struct Level {
    tiles: Grid<Option<Tile>>,
}

impl Level {
    pub fn new(width: usize, height: usize) -> Level {
        Level{
            tiles: Grid::new_filled_with(Some(Tile::Void) ,width, height),
        }
    }

    pub fn new_filled_with(tile: Option<Tile>, width: usize, height: usize) -> Level {
        Level{
            tiles: Grid::new_filled_with(tile, width, height),
        }
    }

    pub fn fill_with(&mut self, tile: Tile) {
        let width = self.tiles.get_width();
        let height = self.tiles.get_height();

        for x in 0..width {
            for y in 0..height {
                self.tiles[(x, y)] = Some(tile.clone());
            }
        }
    }

    pub fn get_width(&self) -> usize {
        self.tiles.get_width()
    }

    pub fn get_height(&self) -> usize {
        self.tiles.get_height()
    }

    pub fn get_mut_tile(&mut self, x: usize, y: usize) -> Option<&mut Tile> {
        if x < self.get_width() && y < self.get_height() {
            self.tiles[(x, y)].as_mut()
        } else {
            None
        }
    }

    pub fn get_mut_tile_with_vec(&mut self, pos: &Vec2<usize>) -> Option<&mut Tile> {
        self.get_mut_tile(pos.x, pos.y)
    }

    pub fn apply<F>(&mut self, gen: F) -> &mut Level where F: FnOnce(&mut Level) {
        gen(self);
        self
    }

}

static NONE: Option<Tile> = None;

impl Index<(usize, usize)> for Level {
    type Output= Option<Tile>;

    fn index(&self, (x, y): (usize, usize)) -> &Option<Tile>{
        if x < self.get_width() && y < self.get_height() {
            &self.tiles[(x, y)]
        } else {
            &NONE
        }
    }
}

impl Index<Vec2<usize>> for Level {
    type Output= Option<Tile>;

    fn index(&self, vec: Vec2<usize>) -> &Option<Tile>{
        if vec.x < self.get_width() && vec.y < self.get_height() {
            &self.tiles[(vec.x, vec.y)]
        } else {
            &NONE
        }
    }
}

pub fn fill_dead_end_tiles(level: &mut Level) -> bool {
    let mut deadends = Vec::new();
    for y in 0..level.get_height() {
        for x in 0..level.get_width() {
            if let Some(ref n) = level[(x,y)] {
                if let &Tile::Floor = n {
                    if is_deadend(level, x, y) {
                        deadends.push((x,y));
                    }
                }
            }
        }
    }
    let mut filled_deadend = false;
    for &(x,y) in &deadends {
        if let Some(tile) = level.get_mut_tile(x, y) {
            *tile = Tile::Wall;
            filled_deadend = true;
        }
    }
    filled_deadend
}

pub fn is_deadend(level: &Level, x: usize, y: usize) -> bool {
    use util::Direction;
    let mut paths = 0;
    for dir in Direction::get_orthogonal_dirs() {
        let vector = dir.get_vec();
        let coord = match (add_isize_to_usize(vector.x, x), add_isize_to_usize(vector.y, y)) {
            (Some(x), Some(y)) => (x,y),
            _ => continue,
        };

        if let Some(Tile::Floor) = level[coord] {
            paths += 1;
        }
	}
    paths < 2
}

fn add_isize_to_usize(i: isize, mut u: usize,) -> Option<usize> {
    if i < 0 && u != 0 {
        u -= (-i) as usize;
    } else if i >= 0 && u < usize::max_value() {
        u += i as usize;
    } else {
        return None
    }
    Some(u)
}
<commit_msg>started making level generic<commit_after>use tile::Tile;
use util::Grid;
use std::ops::{Index};
use na::Vec2;

pub struct Level<T> {
    tiles: Grid<Option<T>>,
}

impl<T> Level<T> {
    pub fn new(width: usize, height: usize) -> Level<T> {
        Level{
            tiles: Grid::new_filled_with(None ,width, height),
        }
    }

    pub fn new_filled_with(tile: Option<T>, width: usize, height: usize) -> Level {
        Level{
            tiles: Grid::new_filled_with(tile, width, height),
        }
    }

    pub fn fill_with(&mut self, tile: T) {
        let width = self.tiles.get_width();
        let height = self.tiles.get_height();

        for x in 0..width {
            for y in 0..height {
                self.tiles[(x, y)] = Some(tile.clone());
            }
        }
    }

    pub fn get_width(&self) -> usize {
        self.tiles.get_width()
    }

    pub fn get_height(&self) -> usize {
        self.tiles.get_height()
    }

    pub fn get_mut_tile(&mut self, x: usize, y: usize) -> Option<&mut T> {
        if x < self.get_width() && y < self.get_height() {
            self.tiles[(x, y)].as_mut()
        } else {
            None
        }
    }

    pub fn get_mut_tile_with_vec(&mut self, pos: &Vec2<usize>) -> Option<&mut T> {
        self.get_mut_tile(pos.x, pos.y)
    }

    pub fn apply<F>(&mut self, gen: F) -> &mut Level<T> where F: FnOnce(&mut Level<T>) {
        gen(self);
        self
    }

}

static NONE: Option<Tile> = None;

impl Index<(usize, usize)> for Level<T> {
    type Output= Option<T>;

    fn index(&self, (x, y): (usize, usize)) -> &Option<Tile>{
        if x < self.get_width() && y < self.get_height() {
            &self.tiles[(x, y)]
        } else {
            &NONE
        }
    }
}

impl Index<Vec2<usize>> for Level {
    type Output= Option<Tile>;

    fn index(&self, vec: Vec2<usize>) -> &Option<Tile>{
        if vec.x < self.get_width() && vec.y < self.get_height() {
            &self.tiles[(vec.x, vec.y)]
        } else {
            &NONE
        }
    }
}

pub fn fill_dead_end_tiles(level: &mut Level) -> bool {
    let mut deadends = Vec::new();
    for y in 0..level.get_height() {
        for x in 0..level.get_width() {
            if let Some(ref n) = level[(x,y)] {
                if let &Tile::Floor = n {
                    if is_deadend(level, x, y) {
                        deadends.push((x,y));
                    }
                }
            }
        }
    }
    let mut filled_deadend = false;
    for &(x,y) in &deadends {
        if let Some(tile) = level.get_mut_tile(x, y) {
            *tile = Tile::Wall;
            filled_deadend = true;
        }
    }
    filled_deadend
}

pub fn is_deadend(level: &Level, x: usize, y: usize) -> bool {
    use util::Direction;
    let mut paths = 0;
    for dir in Direction::get_orthogonal_dirs() {
        let vector = dir.get_vec();
        let coord = match (add_isize_to_usize(vector.x, x), add_isize_to_usize(vector.y, y)) {
            (Some(x), Some(y)) => (x,y),
            _ => continue,
        };

        if let Some(Tile::Floor) = level[coord] {
            paths += 1;
        }
	}
    paths < 2
}

fn add_isize_to_usize(i: isize, mut u: usize,) -> Option<usize> {
    if i < 0 && u != 0 {
        u -= (-i) as usize;
    } else if i >= 0 && u < usize::max_value() {
        u += i as usize;
    } else {
        return None
    }
    Some(u)
}
<|endoftext|>


<commit_before>use cpu::common_defs::OpcodeExecInfo;
use cpu::CpuState;
use cpu::DecodeRegister;
use cpu::common_defs::address_mode::AddressMode;
use cpu::common_defs::opcode_class::OpcodeClass;
use memory::Memory;

macro_rules! set_zs {
    ($cpu_state:expr,$val:expr) => ($cpu_state.Z = $val == 0;$cpu_state.S = $val >= 0x80 );
}

macro_rules! stack_push8 {
    ($cpu_state:expr,$mem:expr,$val:expr) => (try!($mem.write8(0x0100 | $cpu_state.sp,$val)); $cpu_state.sp-=1;);
}
macro_rules! stack_push16 {
    ($cpu_state:expr,$mem:expr,$val:expr) => (try!($mem.write16(0x0100 as u16 | $cpu_state.sp as u16 -1,$val)); $cpu_state.sp-=2;);
}
macro_rules! stack_pull8 {
    ($cpu_state:expr,$mem:expr) => {
        {
            $cpu_state.pc+=1;
            $mem.read8(0x0100 | $cpu_state.sp;)
        }
    }
}
macro_rules! stack_pull16 {
    ($cpu_state:expr,$mem:expr) => {
        {
            $cpu_state.pc+=2;
            $mem.read16(0x0100 as u16 | $cpu_state.sp as u16 -1)
        }
    }
}

#[derive(Debug)]
pub enum ExecutionError {
  MemoryError(::memory::MemoryError),
  UnexpectedOpcode(String),
  UnexpectedAddressMode(String)
}
impl From<::memory::MemoryError> for ExecutionError {
    fn from(err: ::memory::MemoryError) -> ExecutionError {
        ExecutionError::MemoryError(err)
    }
}

pub struct CpuExecutor {
    op_table: Vec<OpcodeExecInfo>,
}

impl CpuExecutor {
	/// Construct a new CpuExecutor.
    pub fn new(opcodes: Vec<OpcodeExecInfo> ) -> CpuExecutor {
        CpuExecutor {
            op_table:  opcodes,
        }
    }

	/// Reset the given cpu_state.
    pub fn power_on(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) {
        self.reset(cpu_state,mem);
    }
	/// Reset the given cpu_state.
    pub fn reset(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) {
        cpu_state.pc = mem.read16(0xFFFC).unwrap();
        cpu_state.sp = 0xFD;
        cpu_state.pack_flags(0x24);
    }

    /// Execute a single instruction in the given memory and cpu_state context.
    pub fn step(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) -> Result<(),ExecutionError> {
        try!(self.fetch_and_decode(cpu_state,mem));
        try!(self.execute(cpu_state,mem));
        Ok(())
    }

	/// Fetch the next instruction and perform address resolution.
    pub fn fetch_and_decode(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) -> Result<(),ExecutionError> {
        cpu_state.instruction_register = mem.read8(cpu_state.pc).unwrap();
        cpu_state.decode_register = try!(self.decode(cpu_state,mem));
        cpu_state.pc = cpu_state.pc+1;
        Ok(())
    }

    /// Perform address resolution, returning the info in a DecodeRegister.
    fn decode(self: &CpuExecutor, cpu_state: &CpuState, mem: &Memory) -> Result<DecodeRegister,ExecutionError> {
        let mut dr = DecodeRegister {
            info : self.op_table[cpu_state.instruction_register as usize].clone(),
            ..Default::default()
        };
        match dr.info.address_mode {
            // no explicit addresses for the following modes
            AddressMode::Accumulator  => { },
            AddressMode::Implied      => { },

            // explicit addresses from here on out
            AddressMode::Absolute => {
                dr.addr_final  = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteX       => {
                dr.addr_final  = Some( ((mem.read16(cpu_state.pc+1).unwrap() as u32 + cpu_state.x as u32) % 65536) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteY       => {
                dr.addr_final  = Some( ((mem.read16(cpu_state.pc+1).unwrap() as u32 + cpu_state.y as u32) % 65536) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Immediate       => {
                dr.addr_final  = Some(cpu_state.pc+1);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Indirect        => {
                dr.addr_intermediate = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap());
            },
            AddressMode::IndexedIndirect => {
                dr.addr_intermediate = Some( (mem.read8(cpu_state.pc+1).unwrap() + cpu_state.x) as u16);
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap());
                dr.value_final       = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::IndirectIndexed => {
                dr.addr_init         = Some(mem.read8(cpu_state.pc+1).unwrap() as u16);
                dr.addr_intermediate = Some(mem.read16(dr.addr_init.unwrap()).unwrap());
                dr.addr_final        = Some( ((dr.addr_intermediate.unwrap() as u32 + cpu_state.y as u32) % 65536) as u16);
                dr.value_final       = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Relative        => {
                dr.value_final = Some(mem.read8(cpu_state.pc+1).unwrap());

                // NOTE: relative is from the end of the current instruction and relative
                // instructions are 2 bytes long, so we add 2 before adding in the specified offset
                //
                if dr.value_final.unwrap() < 0x80 { dr.addr_final  = Some(cpu_state.pc + 2 + dr.value_final.unwrap() as u16); }
                else                              { dr.addr_final  = Some(cpu_state.pc + 2 + dr.value_final.unwrap() as u16 - 0x100);}
            },
            AddressMode::ZeroPage        => {
                dr.addr_final  = Some(mem.read8(cpu_state.pc+1).unwrap() as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageX       => {
                dr.addr_final  = Some( (mem.read8(cpu_state.pc+1).unwrap() as u16 + cpu_state.x as u16) % 256);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageY       => {
                dr.addr_final  = Some( (mem.read8(cpu_state.pc+1).unwrap() as u16 + cpu_state.y as u16) % 256);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            _ => { return Err(ExecutionError::UnexpectedAddressMode(format!("unrecognized addressing mode '{:?}' while decoding instruction_register!",dr.info.address_mode))); }
        }

        return Ok(dr);
    }

    /// Perform the current instruction, returning the CpuState after execution.
    pub fn execute(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) -> Result<(),ExecutionError> {
    	// Figure out which opcode is being executed.
    	match cpu_state.decode_register.info.opcode_class {
    		OpcodeClass::ASL => {
				cpu_state.a = cpu_state.a << 1;
				cpu_state.C = (128 & cpu_state.a) > 0;
    			if cpu_state.a == 0 { cpu_state.Z = true; }

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::BCC => {
                if !cpu_state.C { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else            { cpu_state.pc += cpu_state.decode_register.info.len as u16-1;  }
    		},
    		OpcodeClass::BCS => {
                if cpu_state.C { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else           { cpu_state.pc += cpu_state.decode_register.info.len as u16-1;  }
    		},
    		OpcodeClass::BEQ => {
                if cpu_state.Z { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else           { cpu_state.pc += cpu_state.decode_register.info.len as u16-1;  }
    		},
    		OpcodeClass::BNE => {
                if !cpu_state.Z { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else            { cpu_state.pc += cpu_state.decode_register.info.len as u16-1;  }
    		},
    		OpcodeClass::CLC => {
                cpu_state.C = false;
    		},
    		OpcodeClass::LDA => {
    			cpu_state.a = cpu_state.decode_register.value_final.unwrap();
                set_zs!(cpu_state,cpu_state.a);

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::LDX => {
    			cpu_state.x = cpu_state.decode_register.value_final.unwrap();
                set_zs!(cpu_state,cpu_state.x);

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::LDY => {
    			cpu_state.y = cpu_state.decode_register.value_final.unwrap();
                set_zs!(cpu_state,cpu_state.y);

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::LSR => {
    			cpu_state.a = cpu_state.a >> 1;
    			cpu_state.C = 1 & cpu_state.a > 0;
    			if cpu_state.a == 0 { cpu_state.Z = true; }

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::JMP => {
    			cpu_state.pc = cpu_state.decode_register.addr_final.unwrap();
    		},
    		OpcodeClass::JSR => {
                stack_push16!(cpu_state,mem,cpu_state.pc-1);
    			cpu_state.pc = cpu_state.decode_register.addr_final.unwrap();
    		},
    		OpcodeClass::NOP => {
            },
    		OpcodeClass::SEC => {
                cpu_state.C = true;
    		},
    		OpcodeClass::STX => {
                try!(mem.write8(cpu_state.decode_register.addr_final.unwrap(),cpu_state.decode_register.value_final.unwrap()));
                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},

			_ => { return Err(ExecutionError::UnexpectedOpcode(format!("Unrecognised opcode class: {:?}", cpu_state.decode_register.info.opcode_class)));}

    	}
        Ok(())
    }
}

<commit_msg>implemented STA opcode<commit_after>use cpu::common_defs::OpcodeExecInfo;
use cpu::CpuState;
use cpu::DecodeRegister;
use cpu::common_defs::address_mode::AddressMode;
use cpu::common_defs::opcode_class::OpcodeClass;
use memory::Memory;

macro_rules! set_zs {
    ($cpu_state:expr,$val:expr) => ($cpu_state.Z = $val == 0;$cpu_state.S = $val >= 0x80 );
}

macro_rules! stack_push8 {
    ($cpu_state:expr,$mem:expr,$val:expr) => (try!($mem.write8(0x0100 | $cpu_state.sp,$val)); $cpu_state.sp-=1;);
}
macro_rules! stack_push16 {
    ($cpu_state:expr,$mem:expr,$val:expr) => (try!($mem.write16(0x0100 as u16 | $cpu_state.sp as u16 -1,$val)); $cpu_state.sp-=2;);
}
macro_rules! stack_pull8 {
    ($cpu_state:expr,$mem:expr) => {
        {
            $cpu_state.pc+=1;
            $mem.read8(0x0100 | $cpu_state.sp;)
        }
    }
}
macro_rules! stack_pull16 {
    ($cpu_state:expr,$mem:expr) => {
        {
            $cpu_state.pc+=2;
            $mem.read16(0x0100 as u16 | $cpu_state.sp as u16 -1)
        }
    }
}

#[derive(Debug)]
pub enum ExecutionError {
  MemoryError(::memory::MemoryError),
  UnexpectedOpcode(String),
  UnexpectedAddressMode(String)
}
impl From<::memory::MemoryError> for ExecutionError {
    fn from(err: ::memory::MemoryError) -> ExecutionError {
        ExecutionError::MemoryError(err)
    }
}

pub struct CpuExecutor {
    op_table: Vec<OpcodeExecInfo>,
}

impl CpuExecutor {
	/// Construct a new CpuExecutor.
    pub fn new(opcodes: Vec<OpcodeExecInfo> ) -> CpuExecutor {
        CpuExecutor {
            op_table:  opcodes,
        }
    }

	/// Reset the given cpu_state.
    pub fn power_on(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) {
        self.reset(cpu_state,mem);
    }
	/// Reset the given cpu_state.
    pub fn reset(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) {
        cpu_state.pc = mem.read16(0xFFFC).unwrap();
        cpu_state.sp = 0xFD;
        cpu_state.pack_flags(0x24);
    }

    /// Execute a single instruction in the given memory and cpu_state context.
    pub fn step(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) -> Result<(),ExecutionError> {
        try!(self.fetch_and_decode(cpu_state,mem));
        try!(self.execute(cpu_state,mem));
        Ok(())
    }

	/// Fetch the next instruction and perform address resolution.
    pub fn fetch_and_decode(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) -> Result<(),ExecutionError> {
        cpu_state.instruction_register = mem.read8(cpu_state.pc).unwrap();
        cpu_state.decode_register = try!(self.decode(cpu_state,mem));
        cpu_state.pc = cpu_state.pc+1;
        Ok(())
    }

    /// Perform address resolution, returning the info in a DecodeRegister.
    fn decode(self: &CpuExecutor, cpu_state: &CpuState, mem: &Memory) -> Result<DecodeRegister,ExecutionError> {
        let mut dr = DecodeRegister {
            info : self.op_table[cpu_state.instruction_register as usize].clone(),
            ..Default::default()
        };
        match dr.info.address_mode {
            // no explicit addresses for the following modes
            AddressMode::Accumulator  => { },
            AddressMode::Implied      => { },

            // explicit addresses from here on out
            AddressMode::Absolute => {
                dr.addr_final  = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteX       => {
                dr.addr_final  = Some( ((mem.read16(cpu_state.pc+1).unwrap() as u32 + cpu_state.x as u32) % 65536) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteY       => {
                dr.addr_final  = Some( ((mem.read16(cpu_state.pc+1).unwrap() as u32 + cpu_state.y as u32) % 65536) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Immediate       => {
                dr.addr_final  = Some(cpu_state.pc+1);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Indirect        => {
                dr.addr_intermediate = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap());
            },
            AddressMode::IndexedIndirect => {
                dr.addr_intermediate = Some( (mem.read8(cpu_state.pc+1).unwrap() + cpu_state.x) as u16);
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap());
                dr.value_final       = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::IndirectIndexed => {
                dr.addr_init         = Some(mem.read8(cpu_state.pc+1).unwrap() as u16);
                dr.addr_intermediate = Some(mem.read16(dr.addr_init.unwrap()).unwrap());
                dr.addr_final        = Some( ((dr.addr_intermediate.unwrap() as u32 + cpu_state.y as u32) % 65536) as u16);
                dr.value_final       = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Relative        => {
                dr.value_final = Some(mem.read8(cpu_state.pc+1).unwrap());

                // NOTE: relative is from the end of the current instruction and relative
                // instructions are 2 bytes long, so we add 2 before adding in the specified offset
                //
                if dr.value_final.unwrap() < 0x80 { dr.addr_final  = Some(cpu_state.pc + 2 + dr.value_final.unwrap() as u16); }
                else                              { dr.addr_final  = Some(cpu_state.pc + 2 + dr.value_final.unwrap() as u16 - 0x100);}
            },
            AddressMode::ZeroPage        => {
                dr.addr_final  = Some(mem.read8(cpu_state.pc+1).unwrap() as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageX       => {
                dr.addr_final  = Some( (mem.read8(cpu_state.pc+1).unwrap() as u16 + cpu_state.x as u16) % 256);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageY       => {
                dr.addr_final  = Some( (mem.read8(cpu_state.pc+1).unwrap() as u16 + cpu_state.y as u16) % 256);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            _ => { return Err(ExecutionError::UnexpectedAddressMode(format!("unrecognized addressing mode '{:?}' while decoding instruction_register!",dr.info.address_mode))); }
        }

        return Ok(dr);
    }

    /// Perform the current instruction, returning the CpuState after execution.
    pub fn execute(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) -> Result<(),ExecutionError> {
    	// Figure out which opcode is being executed.
    	match cpu_state.decode_register.info.opcode_class {
    		OpcodeClass::ASL => {
				cpu_state.a = cpu_state.a << 1;
				cpu_state.C = (128 & cpu_state.a) > 0;
    			if cpu_state.a == 0 { cpu_state.Z = true; }

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::BCC => {
                if !cpu_state.C { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else            { cpu_state.pc += cpu_state.decode_register.info.len as u16-1;  }
    		},
    		OpcodeClass::BCS => {
                if cpu_state.C { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else           { cpu_state.pc += cpu_state.decode_register.info.len as u16-1;  }
    		},
    		OpcodeClass::BEQ => {
                if cpu_state.Z { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else           { cpu_state.pc += cpu_state.decode_register.info.len as u16-1;  }
    		},
    		OpcodeClass::BNE => {
                if !cpu_state.Z { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else            { cpu_state.pc += cpu_state.decode_register.info.len as u16-1;  }
    		},
    		OpcodeClass::CLC => {
                cpu_state.C = false;
    		},
    		OpcodeClass::LDA => {
    			cpu_state.a = cpu_state.decode_register.value_final.unwrap();
                set_zs!(cpu_state,cpu_state.a);

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::LDX => {
    			cpu_state.x = cpu_state.decode_register.value_final.unwrap();
                set_zs!(cpu_state,cpu_state.x);

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::LDY => {
    			cpu_state.y = cpu_state.decode_register.value_final.unwrap();
                set_zs!(cpu_state,cpu_state.y);

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::LSR => {
    			cpu_state.a = cpu_state.a >> 1;
    			cpu_state.C = 1 & cpu_state.a > 0;
    			if cpu_state.a == 0 { cpu_state.Z = true; }

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::JMP => {
    			cpu_state.pc = cpu_state.decode_register.addr_final.unwrap();
    		},
    		OpcodeClass::JSR => {
                stack_push16!(cpu_state,mem,cpu_state.pc-1);
    			cpu_state.pc = cpu_state.decode_register.addr_final.unwrap();
    		},
    		OpcodeClass::NOP => {
            },
    		OpcodeClass::SEC => {
                cpu_state.C = true;
    		},
    		OpcodeClass::STA => {
                try!(mem.write8(cpu_state.decode_register.addr_final.unwrap(),cpu_state.a));
                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::STX => {
                try!(mem.write8(cpu_state.decode_register.addr_final.unwrap(),cpu_state.decode_register.value_final.unwrap()));
                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},

			_ => { return Err(ExecutionError::UnexpectedOpcode(format!("Unrecognised opcode class: {:?}", cpu_state.decode_register.info.opcode_class)));}

    	}
        Ok(())
    }
}

<|endoftext|>