<commit_before>//! Keyboard utility functions; allow querying state of keyboard keys and modifiers.
//!
//! Example:
//!
//! ```rust, compile
//! use ggez::event::{EventHandler, KeyCode, KeyMods};
//! use ggez::{graphics, nalgebra as na, timer};
//! use ggez::input::keyboard;
//! use ggez::{Context, GameResult};
//!
//! struct MainState {
//!     position_x: f32,
//! }
//!
//! impl EventHandler for MainState {
//!     fn update(&mut self, ctx: &mut Context) -> GameResult {
//!         // Increase or decrease `position_x` by 0.5, or by 5.0 if Shift is held.
//!         if keyboard::is_key_pressed(ctx, KeyCode::Right) {
//!             if keyboard::is_mod_active(ctx, KeyMods::SHIFT) {
//!                 self.position_x += 4.5;
//!             }
//!             self.position_x += 0.5;
//!         } else if keyboard::is_key_pressed(ctx, KeyCode::Left) {
//!             if keyboard::is_mod_active(ctx, KeyMods::SHIFT) {
//!                 self.position_x -= 4.5;
//!             }
//!             self.position_x -= 0.5;
//!         }
//!         Ok(())
//!     }
//!
//!     fn draw(&mut self, ctx: &mut Context) -> GameResult {
//!         graphics::clear(ctx, [0.1, 0.2, 0.3, 1.0].into());
//!         // Create a circle at `position_x` and draw
//!         let circle = graphics::Mesh::new_circle(
//!             ctx,
//!             graphics::DrawMode::Fill,
//!             na::Point2::new(self.position_x, 380.0),
//!             100.0,
//!             2.0,
//!             graphics::WHITE,
//!         )?;
//!         graphics::draw(ctx, &circle, graphics::DrawParam::default())?;
//!         graphics::present(ctx)?;
//!         timer::yield_now();
//!         Ok(())
//!     }
//!
//!     fn key_down_event(&mut self, ctx: &mut Context, key: KeyCode, mods: KeyMods, _: bool) {
//!         match key {
//!             // Quit if Shift+Ctrl+Q is pressed.
//!             KeyCode::Q => {
//!                 if mods.contains(KeyMods::SHIFT & KeyMods::CTRL) {
//!                     println!("Terminating!");
//!                     ggez::quit(ctx);
//!                 } else if mods.contains(KeyMods::SHIFT) || mods.contains(KeyMods::CTRL) {
//!                     println!("You need to hold both Shift and Control to quit.");
//!                 } else {
//!                     println!("Now you're not even trying!");
//!                 }
//!             }
//!             _ => (),
//!         }
//!     }
//! }
//! ```

use crate::context::Context;

use std::collections::HashSet;
use winit::ModifiersState;
/// A key code.
pub use winit::VirtualKeyCode as KeyCode;

bitflags! {
    /// Bitflags describing the state of keyboard modifiers, such as `Control` or `Shift`.
    #[derive(Default)]
    pub struct KeyMods: u8 {
        /// No modifiers; equivalent to `KeyMods::default()` and
        /// [`KeyMods::empty()`](struct.KeyMods.html#method.empty).
        const NONE  = 0b0000_0000;
        /// Left or right Shift key.
        const SHIFT = 0b0000_0001;
        /// Left or right Control key.
        const CTRL  = 0b0000_0010;
        /// Left or right Alt key.
        const ALT   = 0b0000_0100;
        /// Left or right Win/Cmd/equivalent key.
        const LOGO  = 0b0000_1000;
    }
}

impl From<ModifiersState> for KeyMods {
    fn from(state: ModifiersState) -> Self {
        let mut keymod = KeyMods::empty();
        if state.shift {
            keymod |= Self::SHIFT;
        }
        if state.ctrl {
            keymod |= Self::CTRL;
        }
        if state.alt {
            keymod |= Self::ALT;
        }
        if state.logo {
            keymod |= Self::LOGO;
        }
        keymod
    }
}

/// Tracks held down keyboard keys, active keyboard modifiers,
/// and figures out if the system is sending repeat keystrokes.
#[derive(Clone, Debug)]
pub struct KeyboardContext {
    active_modifiers: KeyMods,
    /// A simple mapping of which key code has been pressed.
    /// We COULD use a `Vec<bool>` but turning Rust enums to and from
    /// integers is unsafe and a set really is what we want anyway.
    pressed_keys_set: HashSet<KeyCode>,

    // These two are necessary for tracking key-repeat.
    last_pressed: Option<KeyCode>,
    current_pressed: Option<KeyCode>,
}

impl KeyboardContext {
    pub(crate) fn new() -> Self {
        Self {
            active_modifiers: KeyMods::empty(),
            // We just use 256 as a number Big Enough For Keyboard Keys to try to avoid resizing.
            pressed_keys_set: HashSet::with_capacity(256),
            last_pressed: None,
            current_pressed: None,
        }
    }

    // TODO: Set modifiers correctly
    // and in general cmake sure this is hooked up correctly
    // from Context::process_event().
    // Looks like it is, but, not 100% sure.
    pub(crate) fn set_key(&mut self, key: KeyCode, pressed: bool) {
        if pressed {
            let _ = self.pressed_keys_set.insert(key);
            self.last_pressed = self.current_pressed;
            self.current_pressed = Some(key);
        } else {
            let _ = self.pressed_keys_set.remove(&key);
            self.current_pressed = None;
            // Double check that this edge handling is necessary;
            // winit sounds like it should do this for us,
            // see https://docs.rs/winit/0.16.1/winit/struct.KeyboardInput.html#structfield.modifiers
            match key {
                KeyCode::LShift | KeyCode::RShift => self.active_modifiers -= KeyMods::SHIFT,
                KeyCode::LControl | KeyCode::RControl => self.active_modifiers -= KeyMods::CTRL,
                KeyCode::LAlt | KeyCode::RAlt => self.active_modifiers -= KeyMods::ALT,
                KeyCode::LWin | KeyCode::RWin => self.active_modifiers -= KeyMods::LOGO,
                _ => (),
            }
        }
    }

    // TODO: Merge into set_key?
    pub(crate) fn set_modifiers(&mut self, keymods: KeyMods) {
        self.active_modifiers = keymods;
    }

    pub(crate) fn is_key_pressed(&self, key: KeyCode) -> bool {
        self.pressed_keys_set.contains(&key)
    }

    pub(crate) fn is_key_repeated(&self) -> bool {
        if self.last_pressed.is_some() {
            self.last_pressed == self.current_pressed
        } else {
            false
        }
    }

    pub(crate) fn pressed_keys(&self) -> &HashSet<KeyCode> {
        &self.pressed_keys_set
    }

    pub(crate) fn active_mods(&self) -> KeyMods {
        self.active_modifiers
    }
}

impl Default for KeyboardContext {
    fn default() -> Self {
        Self::new()
    }
}

/// Checks if a key is currently pressed down.
pub fn is_key_pressed(ctx: &Context, key: KeyCode) -> bool {
    ctx.keyboard_context.is_key_pressed(key)
}

/// Checks if the last keystroke sent by the system is repeated,
/// like when a key is held down for a period of time.
pub fn is_key_repeated(ctx: &Context) -> bool {
    ctx.keyboard_context.is_key_repeated()
}

/// Returns a `HashSet` with currently pressed keys.
pub fn pressed_keys(ctx: &Context) -> &HashSet<KeyCode> {
    ctx.keyboard_context.pressed_keys()
}

/// Checks if keyboard modifier (or several) is active.
pub fn is_mod_active(ctx: &Context, keymods: KeyMods) -> bool {
    ctx.keyboard_context.active_mods().contains(keymods)
}

/// Returns currently active keyboard modifiers.
pub fn active_mods(ctx: &Context) -> KeyMods {
    ctx.keyboard_context.active_mods()
}

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

    #[test]
    fn key_mod_conversions() {
        assert_eq!(
            KeyMods::empty(),
            KeyMods::from(ModifiersState {
                shift: false,
                ctrl: false,
                alt: false,
                logo: false,
            })
        );
        assert_eq!(
            KeyMods::SHIFT,
            KeyMods::from(ModifiersState {
                shift: true,
                ctrl: false,
                alt: false,
                logo: false,
            })
        );
        assert_eq!(
            KeyMods::SHIFT | KeyMods::ALT,
            KeyMods::from(ModifiersState {
                shift: true,
                ctrl: false,
                alt: true,
                logo: false,
            })
        );
        assert_eq!(
            KeyMods::SHIFT | KeyMods::ALT | KeyMods::CTRL,
            KeyMods::from(ModifiersState {
                shift: true,
                ctrl: true,
                alt: true,
                logo: false,
            })
        );
        assert_eq!(
            KeyMods::SHIFT - KeyMods::ALT,
            KeyMods::from(ModifiersState {
                shift: true,
                ctrl: false,
                alt: false,
                logo: false,
            })
        );
        assert_eq!(
            (KeyMods::SHIFT | KeyMods::ALT) - KeyMods::ALT,
            KeyMods::from(ModifiersState {
                shift: true,
                ctrl: false,
                alt: false,
                logo: false,
            })
        );
        assert_eq!(
            KeyMods::SHIFT - (KeyMods::ALT | KeyMods::SHIFT),
            KeyMods::from(ModifiersState {
                shift: false,
                ctrl: false,
                alt: false,
                logo: false,
            })
        );
    }

    #[test]
    fn pressed_keys_tracking() {
        let mut keyboard = KeyboardContext::new();
        assert_eq!(keyboard.pressed_keys(), &[]);
        assert!(!keyboard.is_key_pressed(KeyCode::A));
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.pressed_keys(), &[KeyCode::A]);
        assert!(keyboard.is_key_pressed(KeyCode::A));
        keyboard.set_key(KeyCode::A, false);
        assert_eq!(keyboard.pressed_keys(), &[]);
        assert!(!keyboard.is_key_pressed(KeyCode::A));
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.pressed_keys(), &[KeyCode::A]);
        assert!(keyboard.is_key_pressed(KeyCode::A));
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.pressed_keys(), &[KeyCode::A]);
        keyboard.set_key(KeyCode::B, true);
        assert_eq!(keyboard.pressed_keys(), &[KeyCode::A, KeyCode::B]);
        keyboard.set_key(KeyCode::B, true);
        assert_eq!(keyboard.pressed_keys(), &[KeyCode::A, KeyCode::B]);
        keyboard.set_key(KeyCode::A, false);
        assert_eq!(keyboard.pressed_keys(), &[KeyCode::B]);
        keyboard.set_key(KeyCode::A, false);
        assert_eq!(keyboard.pressed_keys(), &[KeyCode::B]);
        keyboard.set_key(KeyCode::B, false);
        assert_eq!(keyboard.pressed_keys(), &[]);
    }

    #[test]
    fn keyboard_modifiers() {
        let mut keyboard = KeyboardContext::new();

        // this test is mostly useless and is primarily for code coverage
        assert_eq!(keyboard.active_mods(), KeyMods::default());
        keyboard.set_modifiers(KeyMods::from(ModifiersState {
            shift: true,
            ctrl: true,
            alt: true,
            logo: true,
        }));

        // these test the workaround for https://github.com/tomaka/winit/issues/600
        assert_eq!(
            keyboard.active_mods(),
            KeyMods::SHIFT | KeyMods::CTRL | KeyMods::ALT | KeyMods::LOGO
        );
        keyboard.set_key(KeyCode::LControl, false);
        assert_eq!(
            keyboard.active_mods(),
            KeyMods::SHIFT | KeyMods::ALT | KeyMods::LOGO
        );
        keyboard.set_key(KeyCode::RAlt, false);
        assert_eq!(keyboard.active_mods(), KeyMods::SHIFT | KeyMods::LOGO);
        keyboard.set_key(KeyCode::LWin, false);
        assert_eq!(keyboard.active_mods(), KeyMods::SHIFT);
    }

    #[test]
    fn repeated_keys_tracking() {
        let mut keyboard = KeyboardContext::new();
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::A, false);
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.is_key_repeated(), true);
        keyboard.set_key(KeyCode::A, false);
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::B, true);
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.is_key_repeated(), true);
        keyboard.set_key(KeyCode::B, true);
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::B, true);
        assert_eq!(keyboard.is_key_repeated(), true);
    }
}
<commit_msg>Updating unit tests.<commit_after>//! Keyboard utility functions; allow querying state of keyboard keys and modifiers.
//!
//! Example:
//!
//! ```rust, compile
//! use ggez::event::{EventHandler, KeyCode, KeyMods};
//! use ggez::{graphics, nalgebra as na, timer};
//! use ggez::input::keyboard;
//! use ggez::{Context, GameResult};
//!
//! struct MainState {
//!     position_x: f32,
//! }
//!
//! impl EventHandler for MainState {
//!     fn update(&mut self, ctx: &mut Context) -> GameResult {
//!         // Increase or decrease `position_x` by 0.5, or by 5.0 if Shift is held.
//!         if keyboard::is_key_pressed(ctx, KeyCode::Right) {
//!             if keyboard::is_mod_active(ctx, KeyMods::SHIFT) {
//!                 self.position_x += 4.5;
//!             }
//!             self.position_x += 0.5;
//!         } else if keyboard::is_key_pressed(ctx, KeyCode::Left) {
//!             if keyboard::is_mod_active(ctx, KeyMods::SHIFT) {
//!                 self.position_x -= 4.5;
//!             }
//!             self.position_x -= 0.5;
//!         }
//!         Ok(())
//!     }
//!
//!     fn draw(&mut self, ctx: &mut Context) -> GameResult {
//!         graphics::clear(ctx, [0.1, 0.2, 0.3, 1.0].into());
//!         // Create a circle at `position_x` and draw
//!         let circle = graphics::Mesh::new_circle(
//!             ctx,
//!             graphics::DrawMode::Fill,
//!             na::Point2::new(self.position_x, 380.0),
//!             100.0,
//!             2.0,
//!             graphics::WHITE,
//!         )?;
//!         graphics::draw(ctx, &circle, graphics::DrawParam::default())?;
//!         graphics::present(ctx)?;
//!         timer::yield_now();
//!         Ok(())
//!     }
//!
//!     fn key_down_event(&mut self, ctx: &mut Context, key: KeyCode, mods: KeyMods, _: bool) {
//!         match key {
//!             // Quit if Shift+Ctrl+Q is pressed.
//!             KeyCode::Q => {
//!                 if mods.contains(KeyMods::SHIFT & KeyMods::CTRL) {
//!                     println!("Terminating!");
//!                     ggez::quit(ctx);
//!                 } else if mods.contains(KeyMods::SHIFT) || mods.contains(KeyMods::CTRL) {
//!                     println!("You need to hold both Shift and Control to quit.");
//!                 } else {
//!                     println!("Now you're not even trying!");
//!                 }
//!             }
//!             _ => (),
//!         }
//!     }
//! }
//! ```

use crate::context::Context;

use std::collections::HashSet;
use winit::ModifiersState;
/// A key code.
pub use winit::VirtualKeyCode as KeyCode;

bitflags! {
    /// Bitflags describing the state of keyboard modifiers, such as `Control` or `Shift`.
    #[derive(Default)]
    pub struct KeyMods: u8 {
        /// No modifiers; equivalent to `KeyMods::default()` and
        /// [`KeyMods::empty()`](struct.KeyMods.html#method.empty).
        const NONE  = 0b0000_0000;
        /// Left or right Shift key.
        const SHIFT = 0b0000_0001;
        /// Left or right Control key.
        const CTRL  = 0b0000_0010;
        /// Left or right Alt key.
        const ALT   = 0b0000_0100;
        /// Left or right Win/Cmd/equivalent key.
        const LOGO  = 0b0000_1000;
    }
}

impl From<ModifiersState> for KeyMods {
    fn from(state: ModifiersState) -> Self {
        let mut keymod = KeyMods::empty();
        if state.shift {
            keymod |= Self::SHIFT;
        }
        if state.ctrl {
            keymod |= Self::CTRL;
        }
        if state.alt {
            keymod |= Self::ALT;
        }
        if state.logo {
            keymod |= Self::LOGO;
        }
        keymod
    }
}

/// Tracks held down keyboard keys, active keyboard modifiers,
/// and figures out if the system is sending repeat keystrokes.
#[derive(Clone, Debug)]
pub struct KeyboardContext {
    active_modifiers: KeyMods,
    /// A simple mapping of which key code has been pressed.
    /// We COULD use a `Vec<bool>` but turning Rust enums to and from
    /// integers is unsafe and a set really is what we want anyway.
    pressed_keys_set: HashSet<KeyCode>,

    // These two are necessary for tracking key-repeat.
    last_pressed: Option<KeyCode>,
    current_pressed: Option<KeyCode>,
}

impl KeyboardContext {
    pub(crate) fn new() -> Self {
        Self {
            active_modifiers: KeyMods::empty(),
            // We just use 256 as a number Big Enough For Keyboard Keys to try to avoid resizing.
            pressed_keys_set: HashSet::with_capacity(256),
            last_pressed: None,
            current_pressed: None,
        }
    }

    // TODO: Set modifiers correctly
    // and in general cmake sure this is hooked up correctly
    // from Context::process_event().
    // Looks like it is, but, not 100% sure.
    pub(crate) fn set_key(&mut self, key: KeyCode, pressed: bool) {
        if pressed {
            let _ = self.pressed_keys_set.insert(key);
            self.last_pressed = self.current_pressed;
            self.current_pressed = Some(key);
        } else {
            let _ = self.pressed_keys_set.remove(&key);
            self.current_pressed = None;
            // Double check that this edge handling is necessary;
            // winit sounds like it should do this for us,
            // see https://docs.rs/winit/0.16.1/winit/struct.KeyboardInput.html#structfield.modifiers
            match key {
                KeyCode::LShift | KeyCode::RShift => self.active_modifiers -= KeyMods::SHIFT,
                KeyCode::LControl | KeyCode::RControl => self.active_modifiers -= KeyMods::CTRL,
                KeyCode::LAlt | KeyCode::RAlt => self.active_modifiers -= KeyMods::ALT,
                KeyCode::LWin | KeyCode::RWin => self.active_modifiers -= KeyMods::LOGO,
                _ => (),
            }
        }
    }

    // TODO: Merge into set_key?
    pub(crate) fn set_modifiers(&mut self, keymods: KeyMods) {
        self.active_modifiers = keymods;
    }

    pub(crate) fn is_key_pressed(&self, key: KeyCode) -> bool {
        self.pressed_keys_set.contains(&key)
    }

    pub(crate) fn is_key_repeated(&self) -> bool {
        if self.last_pressed.is_some() {
            self.last_pressed == self.current_pressed
        } else {
            false
        }
    }

    pub(crate) fn pressed_keys(&self) -> &HashSet<KeyCode> {
        &self.pressed_keys_set
    }

    pub(crate) fn active_mods(&self) -> KeyMods {
        self.active_modifiers
    }
}

impl Default for KeyboardContext {
    fn default() -> Self {
        Self::new()
    }
}

/// Checks if a key is currently pressed down.
pub fn is_key_pressed(ctx: &Context, key: KeyCode) -> bool {
    ctx.keyboard_context.is_key_pressed(key)
}

/// Checks if the last keystroke sent by the system is repeated,
/// like when a key is held down for a period of time.
pub fn is_key_repeated(ctx: &Context) -> bool {
    ctx.keyboard_context.is_key_repeated()
}

/// Returns a `HashSet` with currently pressed keys.
pub fn pressed_keys(ctx: &Context) -> &HashSet<KeyCode> {
    ctx.keyboard_context.pressed_keys()
}

/// Checks if keyboard modifier (or several) is active.
pub fn is_mod_active(ctx: &Context, keymods: KeyMods) -> bool {
    ctx.keyboard_context.active_mods().contains(keymods)
}

/// Returns currently active keyboard modifiers.
pub fn active_mods(ctx: &Context) -> KeyMods {
    ctx.keyboard_context.active_mods()
}

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

    #[test]
    fn key_mod_conversions() {
        assert_eq!(
            KeyMods::empty(),
            KeyMods::from(ModifiersState {
                shift: false,
                ctrl: false,
                alt: false,
                logo: false,
            })
        );
        assert_eq!(
            KeyMods::SHIFT,
            KeyMods::from(ModifiersState {
                shift: true,
                ctrl: false,
                alt: false,
                logo: false,
            })
        );
        assert_eq!(
            KeyMods::SHIFT | KeyMods::ALT,
            KeyMods::from(ModifiersState {
                shift: true,
                ctrl: false,
                alt: true,
                logo: false,
            })
        );
        assert_eq!(
            KeyMods::SHIFT | KeyMods::ALT | KeyMods::CTRL,
            KeyMods::from(ModifiersState {
                shift: true,
                ctrl: true,
                alt: true,
                logo: false,
            })
        );
        assert_eq!(
            KeyMods::SHIFT - KeyMods::ALT,
            KeyMods::from(ModifiersState {
                shift: true,
                ctrl: false,
                alt: false,
                logo: false,
            })
        );
        assert_eq!(
            (KeyMods::SHIFT | KeyMods::ALT) - KeyMods::ALT,
            KeyMods::from(ModifiersState {
                shift: true,
                ctrl: false,
                alt: false,
                logo: false,
            })
        );
        assert_eq!(
            KeyMods::SHIFT - (KeyMods::ALT | KeyMods::SHIFT),
            KeyMods::from(ModifiersState {
                shift: false,
                ctrl: false,
                alt: false,
                logo: false,
            })
        );
    }

    #[test]
    fn pressed_keys_tracking() {
        let mut keyboard = KeyboardContext::new();
        assert_eq!(keyboard.pressed_keys(), &[].iter().cloned().collect());
        assert!(!keyboard.is_key_pressed(KeyCode::A));
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.pressed_keys(), &[KeyCode::A].iter().cloned().collect());
        assert!(keyboard.is_key_pressed(KeyCode::A));
        keyboard.set_key(KeyCode::A, false);
        assert_eq!(keyboard.pressed_keys(), &[].iter().cloned().collect());
        assert!(!keyboard.is_key_pressed(KeyCode::A));
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.pressed_keys(), &[KeyCode::A].iter().cloned().collect());
        assert!(keyboard.is_key_pressed(KeyCode::A));
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.pressed_keys(), &[KeyCode::A].iter().cloned().collect());
        keyboard.set_key(KeyCode::B, true);
        assert_eq!(keyboard.pressed_keys(), &[KeyCode::A, KeyCode::B].iter().cloned().collect());
        keyboard.set_key(KeyCode::B, true);
        assert_eq!(keyboard.pressed_keys(), &[KeyCode::A, KeyCode::B].iter().cloned().collect());
        keyboard.set_key(KeyCode::A, false);
        assert_eq!(keyboard.pressed_keys(), &[KeyCode::B].iter().cloned().collect());
        keyboard.set_key(KeyCode::A, false);
        assert_eq!(keyboard.pressed_keys(), &[KeyCode::B].iter().cloned().collect());
        keyboard.set_key(KeyCode::B, false);
        assert_eq!(keyboard.pressed_keys(), &[].iter().cloned().collect());
    }

    #[test]
    fn keyboard_modifiers() {
        let mut keyboard = KeyboardContext::new();

        // this test is mostly useless and is primarily for code coverage
        assert_eq!(keyboard.active_mods(), KeyMods::default());
        keyboard.set_modifiers(KeyMods::from(ModifiersState {
            shift: true,
            ctrl: true,
            alt: true,
            logo: true,
        }));

        // these test the workaround for https://github.com/tomaka/winit/issues/600
        assert_eq!(
            keyboard.active_mods(),
            KeyMods::SHIFT | KeyMods::CTRL | KeyMods::ALT | KeyMods::LOGO
        );
        keyboard.set_key(KeyCode::LControl, false);
        assert_eq!(
            keyboard.active_mods(),
            KeyMods::SHIFT | KeyMods::ALT | KeyMods::LOGO
        );
        keyboard.set_key(KeyCode::RAlt, false);
        assert_eq!(keyboard.active_mods(), KeyMods::SHIFT | KeyMods::LOGO);
        keyboard.set_key(KeyCode::LWin, false);
        assert_eq!(keyboard.active_mods(), KeyMods::SHIFT);
    }

    #[test]
    fn repeated_keys_tracking() {
        let mut keyboard = KeyboardContext::new();
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::A, false);
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.is_key_repeated(), true);
        keyboard.set_key(KeyCode::A, false);
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::B, true);
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.is_key_repeated(), true);
        keyboard.set_key(KeyCode::B, true);
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::B, true);
        assert_eq!(keyboard.is_key_repeated(), true);
    }
}
<|endoftext|>


<commit_before>use askama::Template;

#[derive(Template)]
#[template(path = "for.html")]
struct ForTemplate<'a> {
    strings: Vec<&'a str>,
    tuple_strings: Vec<(&'a str, &'a str)>,
}

#[test]
fn test_for() {
    let s = ForTemplate {
        strings: vec!["A", "alfa", "1"],
        tuple_strings: vec![("B", "beta")],
    };
    assert_eq!(
        s.render().unwrap(),
        "0. A (first)\n1. alfa\n2. 1\n\n0. B,beta (first)\n"
    );
}

#[derive(Template)]
#[template(path = "nested-for.html")]
struct NestedForTemplate<'a> {
    seqs: Vec<&'a [&'a str]>,
}

#[test]
fn test_nested_for() {
    let alpha = vec!["a", "b", "c"];
    let numbers = vec!["one", "two"];
    let s = NestedForTemplate {
        seqs: vec![&alpha, &numbers],
    };
    assert_eq!(s.render().unwrap(), "1\n  0a1b2c2\n  0one1two");
}

#[derive(Template)]
#[template(path = "precedence-for.html")]
struct PrecedenceTemplate<'a> {
    strings: Vec<&'a str>,
}

#[test]
fn test_precedence_for() {
    let s = PrecedenceTemplate {
        strings: vec!["A", "alfa", "1"],
    };
    assert_eq!(
        s.render().unwrap(),
        "0. A2 (first)\n1. alfa4\n2. 16 (last)\n"
    );
}

#[derive(Template)]
#[template(path = "for-range.html")]
struct ForRangeTemplate {
    init: i32,
    end: i32,
}

#[test]
fn test_for_range() {
    let s = ForRangeTemplate { init: -1, end: 1 };
    assert_eq!(
        s.render().unwrap(),
        "foo (first)\nfoo (last)\nbar\nbar\nfoo\nbar\nbar\n"
    );
}
<commit_msg>Added more loop tests<commit_after>use askama::Template;

#[derive(Template)]
#[template(path = "for.html")]
struct ForTemplate<'a> {
    strings: Vec<&'a str>,
    tuple_strings: Vec<(&'a str, &'a str)>,
}

#[test]
fn test_for() {
    let s = ForTemplate {
        strings: vec!["A", "alfa", "1"],
        tuple_strings: vec![("B", "beta")],
    };
    assert_eq!(
        s.render().unwrap(),
        "0. A (first)\n1. alfa\n2. 1\n\n0. B,beta (first)\n"
    );
}

#[derive(Template)]
#[template(path = "nested-for.html")]
struct NestedForTemplate<'a> {
    seqs: Vec<&'a [&'a str]>,
}

#[test]
fn test_nested_for() {
    let alpha = vec!["a", "b", "c"];
    let numbers = vec!["one", "two"];
    let s = NestedForTemplate {
        seqs: vec![&alpha, &numbers],
    };
    assert_eq!(s.render().unwrap(), "1\n  0a1b2c2\n  0one1two");
}

#[derive(Template)]
#[template(path = "precedence-for.html")]
struct PrecedenceTemplate<'a> {
    strings: Vec<&'a str>,
}

#[test]
fn test_precedence_for() {
    let s = PrecedenceTemplate {
        strings: vec!["A", "alfa", "1"],
    };
    assert_eq!(
        s.render().unwrap(),
        "0. A2 (first)\n1. alfa4\n2. 16 (last)\n"
    );
}

#[derive(Template)]
#[template(path = "for-range.html")]
struct ForRangeTemplate {
    init: i32,
    end: i32,
}

#[test]
fn test_for_range() {
    let s = ForRangeTemplate { init: -1, end: 1 };
    assert_eq!(
        s.render().unwrap(),
        "foo (first)\nfoo (last)\nbar\nbar\nfoo\nbar\nbar\n"
    );
}

#[derive(Template)]
#[template(source = "{% for i in [1, 2, 3] %}{{ i }}{% endfor %}", ext = "txt")]
struct ForArrayTemplate {}

#[test]
fn test_for_array() {
    let t = ForArrayTemplate {};
    assert_eq!(t.render().unwrap(), "123");
}

#[derive(Template)]
#[template(
    source = "{% for i in [1, 2, 3].iter() %}{{ i }}{% endfor %}",
    ext = "txt"
)]
struct ForMethodCallTemplate {}

#[test]
fn test_for_method_call() {
    let t = ForMethodCallTemplate {};
    assert_eq!(t.render().unwrap(), "123");
}

#[derive(Template)]
#[template(
    source = "{% for i in [1, 2, 3, 4, 5][3..] %}{{ i }}{% endfor %}",
    ext = "txt"
)]
struct ForIndexTemplate {}

#[test]
fn test_for_index() {
    let t = ForIndexTemplate {};
    assert_eq!(t.render().unwrap(), "45");
}
<|endoftext|>


<commit_before>use hook::result::HookResult;
use store::FileLockEntry;
use storeid::StoreId;

pub trait StoreIdAccessor : Send + Sync {
    fn access(&self, &StoreId) -> HookResult<()>;
}

pub trait MutableHookDataAccessor : Send + Sync {
    fn access_mut(&self, &mut FileLockEntry) -> HookResult<()>;
}

pub trait NonMutableHookDataAccessor : Send + Sync {
    fn access(&self, &FileLockEntry) -> HookResult<()>;
}

pub enum HookDataAccessor {
    StoreIdAccess(Box<StoreIdAccessor>),
    MutableAccess(Box<MutableHookDataAccessor>),
    NonMutableAccess(Box<NonMutableHookDataAccessor>),
}

pub trait HookDataAccessorProvider {
    fn accessor(&self) -> Box<HookDataAccessor>;
}

<commit_msg>We do not need boxes here<commit_after>use hook::result::HookResult;
use store::FileLockEntry;
use storeid::StoreId;

pub trait StoreIdAccessor : Send + Sync {
    fn access(&self, &StoreId) -> HookResult<()>;
}

pub trait MutableHookDataAccessor : Send + Sync {
    fn access_mut(&self, &mut FileLockEntry) -> HookResult<()>;
}

pub trait NonMutableHookDataAccessor : Send + Sync {
    fn access(&self, &FileLockEntry) -> HookResult<()>;
}

pub enum HookDataAccessor<'a> {
    StoreIdAccess(&'a StoreIdAccessor),
    MutableAccess(&'a MutableHookDataAccessor),
    NonMutableAccess(&'a NonMutableHookDataAccessor),
}

pub trait HookDataAccessorProvider {
    fn accessor(&self) -> HookDataAccessor;
}

<|endoftext|>


<commit_before>use card_strategy::CardStrategy;

use card::Card;
use game_status::GameStatus;
use player::PlayerName;

use std::collections::BTreeMap;

#[derive(Debug)]
pub struct DefensiveCardStrategy;

/*
    Play 2 of clubs if in hand.
    If going to win a deal, do so with highest ranking card.
    Need strategy for winning negetive penalty hands
*/
impl DefensiveCardStrategy {
    fn score_card<'a>(card: &'a Card, game_status: &'a GameStatus, player_name: &PlayerName) -> (i32, i32, i32, i32) {
        let card_penalty_to_me = Self::card_penalty_to_me(card, game_status, player_name);
        let card_penalty = 0 - Self::card_penalty(card, game_status);
        let trouble = Self::trouble_score(card, game_status);
        let card_rank = 0 - (u32::from(card.rank) as i32);
        (card_penalty_to_me, card_penalty, trouble, card_rank)
    }

    fn card_penalty(card: &Card, game_status: &GameStatus) -> i32 {
        game_status.round_parameters.card_points.get(card)
            .map(|penalty| *penalty)
            .unwrap_or_default()
    }

    fn card_penalty_to_me(card: &Card, game_status: &GameStatus, player_name: &PlayerName) -> i32 {
        if Self::will_win_deal(card, game_status) {
            Self::card_penalty(card, game_status)
        } else {
            0
        }
    }

    fn trouble_score(card: &Card, game_status: &GameStatus) -> i32 {
        if Self::will_win_deal(card, game_status) {
            u32::from(card.rank) as i32
        } else {
            0
        }
    }

    fn will_win_deal(card: &Card, game_status: &GameStatus) -> bool {
        game_status.my_in_progress_deal.as_ref().and_then(|deal|
            deal.suit.and_then(|suit|
                deal.deal_cards.iter()
                    .map(|deal_card| deal_card.card)
                    .filter(|card| card.suit == suit)
                    .max()
                    .map(|winning_card| card.suit == suit && card.rank > winning_card.rank))).unwrap_or(true)
    }
}

impl CardStrategy for DefensiveCardStrategy {

    fn pass_cards<'a>(&mut self, game_status: &'a GameStatus) -> Vec<&'a Card> {
        // Need to order cards by potential to win lowest penalty hands
        let mut initial_hand = game_status.my_initial_hand.iter().collect::<Vec<&Card>>();
        initial_hand.reverse();
        initial_hand.into_iter().take(3).collect()
    }

    fn play_card<'a>(&mut self, game_status: &'a GameStatus, player_name: &PlayerName) -> &'a Card {
        let current_suit = game_status.my_in_progress_deal.as_ref().and_then(|deal| deal.suit);
        let mut valid_cards = game_status.my_current_hand.iter()
            .filter(|card| Some(card.suit) == current_suit)
            .collect::<Vec<&Card>>();

        if valid_cards.is_empty() {
            valid_cards.extend(&game_status.my_current_hand);
        }

        valid_cards.into_iter()
            .map(|card| ((Self::score_card(card, game_status, player_name), card), card))
            .collect::<BTreeMap<((i32, i32, i32, i32), &Card), &Card>>()
            .values()
            .next()
            .expect("No valid cards to play!")
    }

}<commit_msg>try to win negative points<commit_after>use card_strategy::CardStrategy;

use card::Card;
use game_status::GameStatus;
use player::PlayerName;

use std::collections::BTreeMap;

#[derive(Debug)]
pub struct DefensiveCardStrategy;

/*
    Play 2 of clubs if in hand.
    If going to win a deal, do so with highest ranking card.
*/
impl DefensiveCardStrategy {
    fn score_card<'a>(card: &'a Card, game_status: &'a GameStatus) -> (i32, i32, i32, i32) {
        let card_penalty_to_me = Self::card_penalty_to_me(card, game_status);
        let card_penalty = 0 - Self::card_penalty(card, game_status);
        let trouble = Self::trouble_score(card, game_status);
        let card_rank = 0 - (u32::from(card.rank) as i32);
        (card_penalty_to_me, card_penalty, trouble, card_rank)
    }

    fn card_penalty(card: &Card, game_status: &GameStatus) -> i32 {
        game_status.round_parameters.card_points.get(card)
            .map(|penalty| *penalty)
            .unwrap_or_default()
    }

    fn card_penalty_to_me(card: &Card, game_status: &GameStatus) -> i32 {
        if Self::will_win_deal(card, game_status) {
            Self::card_penalty(card, game_status)
        } else {
            0
        }
    }

    fn trouble_score(card: &Card, game_status: &GameStatus) -> i32 {
        if Self::will_win_deal(card, game_status) {
            let trouble = u32::from(card.rank) as i32;
            if Self::card_penalty_to_me(card, game_status) < 0 {
                0 - trouble
            } else {
                trouble
            }
        } else {
            0
        }
    }

    fn will_win_deal(card: &Card, game_status: &GameStatus) -> bool {
        game_status.my_in_progress_deal.as_ref().and_then(|deal|
            deal.suit.and_then(|suit|
                deal.deal_cards.iter()
                    .map(|deal_card| deal_card.card)
                    .filter(|card| card.suit == suit)
                    .max()
                    .map(|winning_card| card.suit == suit && card.rank > winning_card.rank))).unwrap_or(true)
    }
}

impl CardStrategy for DefensiveCardStrategy {

    fn pass_cards<'a>(&mut self, game_status: &'a GameStatus) -> Vec<&'a Card> {
        // Need to order cards by potential to win lowest penalty hands
        let mut initial_hand = game_status.my_initial_hand.iter().collect::<Vec<&Card>>();
        initial_hand.reverse();
        initial_hand.into_iter().take(3).collect()
    }

    fn play_card<'a>(&mut self, game_status: &'a GameStatus, player_name: &PlayerName) -> &'a Card {
        let current_suit = game_status.my_in_progress_deal.as_ref().and_then(|deal| deal.suit);
        let mut valid_cards = game_status.my_current_hand.iter()
            .filter(|card| Some(card.suit) == current_suit)
            .collect::<Vec<&Card>>();

        if valid_cards.is_empty() {
            valid_cards.extend(&game_status.my_current_hand);
        }

        valid_cards.into_iter()
            .map(|card| ((Self::score_card(card, game_status), card), card))
            .collect::<BTreeMap<((i32, i32, i32, i32), &Card), &Card>>()
            .values()
            .next()
            .expect("No valid cards to play!")
    }

}<|endoftext|>


<commit_before>#[cfg(test)]
#[macro_export]
macro_rules! ssz_tests {
    ($type: ident) => {
        #[test]
        pub fn test_ssz_round_trip() {
            use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
            use ssz::{ssz_encode, Decodable};

            let mut rng = XorShiftRng::from_seed([42; 16]);
            let original = $type::random_for_test(&mut rng);

            let bytes = ssz_encode(&original);
            let (decoded, _): ($type, usize) = <_>::ssz_decode(&bytes, 0).unwrap();

            assert_eq!(original, decoded);
        }

        #[test]
        pub fn test_tree_hash_root() {
            use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
            use tree_hash::TreeHash;

            let mut rng = XorShiftRng::from_seed([42; 16]);
            let original = $type::random_for_test(&mut rng);

            let result = original.tree_hash_root();

            assert_eq!(result.len(), 32);
            // TODO: Add further tests
            // https://github.com/sigp/lighthouse/issues/170
        }
    };
}

#[cfg(test)]
#[macro_export]
macro_rules! cached_tree_hash_tests {
    ($type: ident) => {
        #[test]
        pub fn test_cached_tree_hash() {
            use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
            use tree_hash::TreeHash;

            let mut rng = XorShiftRng::from_seed([42; 16]);

            // Test the original hash
            let original = $type::random_for_test(&mut rng);
            let mut cache = cached_tree_hash::TreeHashCache::new(&original).unwrap();

            assert_eq!(
                cache.tree_hash_root().unwrap().to_vec(),
                original.tree_hash_root(),
                "Original hash failed."
            );

            // Test the updated hash
            let modified = $type::random_for_test(&mut rng);
            cache.update(&modified).unwrap();
            assert_eq!(
                cache.tree_hash_root().unwrap().to_vec(),
                modified.tree_hash_root(),
                "Modification hash failed"
            );

            // Produce a new cache for the modified object and compare it to the updated cache.
            let mut modified_cache = cached_tree_hash::TreeHashCache::new(&modified).unwrap();

            // Reset the caches.
            cache.reset_modifications();
            modified_cache.reset_modifications();

            // Ensure the modified cache is the same as a newly created cache. This is a sanity
            // check to make sure there are no artifacts of the original cache remaining after an
            // update.
            assert_eq!(
                modified_cache, cache,
                "The modified cache does not match a new cache."
            )
        }
    };
}
<commit_msg>Fix types ssz macro<commit_after>#[cfg(test)]
#[macro_export]
macro_rules! ssz_tests {
    ($type: ident) => {
        #[test]
        pub fn test_ssz_round_trip() {
            use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
            use ssz::{ssz_encode, Decodable};

            let mut rng = XorShiftRng::from_seed([42; 16]);
            let original = $type::random_for_test(&mut rng);

            let bytes = ssz_encode(&original);
            let decoded = $type::from_ssz_bytes(&bytes).unwrap();

            assert_eq!(original, decoded);
        }

        #[test]
        pub fn test_tree_hash_root() {
            use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
            use tree_hash::TreeHash;

            let mut rng = XorShiftRng::from_seed([42; 16]);
            let original = $type::random_for_test(&mut rng);

            let result = original.tree_hash_root();

            assert_eq!(result.len(), 32);
            // TODO: Add further tests
            // https://github.com/sigp/lighthouse/issues/170
        }
    };
}

#[cfg(test)]
#[macro_export]
macro_rules! cached_tree_hash_tests {
    ($type: ident) => {
        #[test]
        pub fn test_cached_tree_hash() {
            use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
            use tree_hash::TreeHash;

            let mut rng = XorShiftRng::from_seed([42; 16]);

            // Test the original hash
            let original = $type::random_for_test(&mut rng);
            let mut cache = cached_tree_hash::TreeHashCache::new(&original).unwrap();

            assert_eq!(
                cache.tree_hash_root().unwrap().to_vec(),
                original.tree_hash_root(),
                "Original hash failed."
            );

            // Test the updated hash
            let modified = $type::random_for_test(&mut rng);
            cache.update(&modified).unwrap();
            assert_eq!(
                cache.tree_hash_root().unwrap().to_vec(),
                modified.tree_hash_root(),
                "Modification hash failed"
            );

            // Produce a new cache for the modified object and compare it to the updated cache.
            let mut modified_cache = cached_tree_hash::TreeHashCache::new(&modified).unwrap();

            // Reset the caches.
            cache.reset_modifications();
            modified_cache.reset_modifications();

            // Ensure the modified cache is the same as a newly created cache. This is a sanity
            // check to make sure there are no artifacts of the original cache remaining after an
            // update.
            assert_eq!(
                modified_cache, cache,
                "The modified cache does not match a new cache."
            )
        }
    };
}
<|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/. */

#[doc = "

Handy functions for creating class objects and so forth.

"];

use glue::GetJSClassHookStubPointer;
use glue::{PROPERTY_STUB, STRICT_PROPERTY_STUB, ENUMERATE_STUB,
              RESOLVE_STUB, CONVERT_STUB};
use std::libc::c_uint;
use std::str::raw::from_c_str;
use std::cast::transmute;
use name_pool::*;
use std::ptr::null;
use std::ptr;
use jsapi;
use jsapi::{JSClass, JSContext, JSVal, JSFunctionSpec, JSBool, JSNativeWrapper};
use jsapi::{JS_EncodeString, JS_free, JS_ValueToString};
use JSCLASS_IS_GLOBAL;
use JSCLASS_HAS_RESERVED_SLOTS;
use JSCLASS_GLOBAL_SLOT_COUNT;
use JS_ARGV;
use JSVAL_NULL;
use JS_SET_RVAL;

pub fn basic_class(np: @mut NamePool, name: ~str) -> JSClass {
    JSClass {
        name: np.add(name),
        flags: JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + 1),
        addProperty: unsafe { GetJSClassHookStubPointer(PROPERTY_STUB) as *u8 },
        delProperty: unsafe { GetJSClassHookStubPointer(PROPERTY_STUB) as *u8 },
        getProperty: unsafe { GetJSClassHookStubPointer(PROPERTY_STUB) as *u8 },
        setProperty: unsafe { GetJSClassHookStubPointer(STRICT_PROPERTY_STUB) as *u8 },
        enumerate: unsafe { GetJSClassHookStubPointer(ENUMERATE_STUB) as *u8 },
        resolve: unsafe { GetJSClassHookStubPointer(RESOLVE_STUB) as *u8 },
        convert: unsafe { GetJSClassHookStubPointer(CONVERT_STUB) as *u8 },
        finalize: null(),
        checkAccess: null(),
        call: null(),
        hasInstance: null(),
        construct: null(),
        trace: null(),
        reserved: (null(), null(), null(), null(), null(),  // 05
                   null(), null(), null(), null(), null(),  // 10
                   null(), null(), null(), null(), null(),  // 15
                   null(), null(), null(), null(), null(),  // 20
                   null(), null(), null(), null(), null(),  // 25
                   null(), null(), null(), null(), null(),  // 30
                   null(), null(), null(), null(), null(),  // 35
                   null(), null(), null(), null(), null())  // 40
    }
}

pub fn global_class(np: @mut NamePool) -> JSClass {
    basic_class(np, ~"global")
}

pub unsafe fn jsval_to_rust_str(cx: *JSContext, vp: *jsapi::JSString) -> ~str {
    if vp.is_null() {
        ~""
    } else {
        let bytes = JS_EncodeString(cx, vp);
        let s = from_c_str(bytes);
        JS_free(cx, transmute(bytes));
        s
    }
}

pub extern fn debug(cx: *JSContext, argc: c_uint, vp: *JSVal) -> JSBool {
    unsafe {
        let argv = JS_ARGV(cx, vp);
        for i in range(0, argc as int) {
            let jsstr = JS_ValueToString(cx, *ptr::offset(argv, i));
            debug!("%s", jsval_to_rust_str(cx, jsstr));
        }
        JS_SET_RVAL(cx, vp, JSVAL_NULL);
        return 1_i32;
    }
}

pub fn debug_fns(np: @mut NamePool) -> ~[JSFunctionSpec] {
    ~[
        JSFunctionSpec {
            name: np.add(~"debug"),
            call: JSNativeWrapper {
                op: debug,
                info: null()
            },
            nargs: 0,
            flags: 0,
            selfHostedName: null()
        },
        JSFunctionSpec {
            name: null(),
            call: JSNativeWrapper {
                op: null(),
                info: null(),
            },
            nargs: 0,
            flags: 0,
            selfHostedName: null()
        }
    ]
}

<commit_msg>This adds an assert function to the JavaScript global similar to assert in Rust. This function can be used for writing tests.<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/. */

#[doc = "

Handy functions for creating class objects and so forth.

"];

use glue::GetJSClassHookStubPointer;
use glue::{PROPERTY_STUB, STRICT_PROPERTY_STUB, ENUMERATE_STUB,
              RESOLVE_STUB, CONVERT_STUB};
use std::libc::c_uint;
use std::str::raw::from_c_str;
use std::cast::transmute;
use name_pool::*;
use std::ptr::null;
use std::ptr;
use jsapi;
use jsapi::{JSClass, JSContext, JSVal, JSFunctionSpec, JSBool, JSNativeWrapper};
use jsapi::{JS_EncodeString, JS_free, JS_ValueToBoolean, JS_ValueToString};
use jsapi::{JS_ReportError, JS_ValueToSource};
use JSCLASS_IS_GLOBAL;
use JSCLASS_HAS_RESERVED_SLOTS;
use JSCLASS_GLOBAL_SLOT_COUNT;
use JS_ARGV;
use JSVAL_VOID;
use JS_SET_RVAL;

pub fn basic_class(np: @mut NamePool, name: ~str) -> JSClass {
    JSClass {
        name: np.add(name),
        flags: JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + 1),
        addProperty: unsafe { GetJSClassHookStubPointer(PROPERTY_STUB) as *u8 },
        delProperty: unsafe { GetJSClassHookStubPointer(PROPERTY_STUB) as *u8 },
        getProperty: unsafe { GetJSClassHookStubPointer(PROPERTY_STUB) as *u8 },
        setProperty: unsafe { GetJSClassHookStubPointer(STRICT_PROPERTY_STUB) as *u8 },
        enumerate: unsafe { GetJSClassHookStubPointer(ENUMERATE_STUB) as *u8 },
        resolve: unsafe { GetJSClassHookStubPointer(RESOLVE_STUB) as *u8 },
        convert: unsafe { GetJSClassHookStubPointer(CONVERT_STUB) as *u8 },
        finalize: null(),
        checkAccess: null(),
        call: null(),
        hasInstance: null(),
        construct: null(),
        trace: null(),
        reserved: (null(), null(), null(), null(), null(),  // 05
                   null(), null(), null(), null(), null(),  // 10
                   null(), null(), null(), null(), null(),  // 15
                   null(), null(), null(), null(), null(),  // 20
                   null(), null(), null(), null(), null(),  // 25
                   null(), null(), null(), null(), null(),  // 30
                   null(), null(), null(), null(), null(),  // 35
                   null(), null(), null(), null(), null())  // 40
    }
}

pub fn global_class(np: @mut NamePool) -> JSClass {
    basic_class(np, ~"global")
}

pub unsafe fn jsval_to_rust_str(cx: *JSContext, vp: *jsapi::JSString) -> ~str {
    if vp.is_null() {
        ~""
    } else {
        let bytes = JS_EncodeString(cx, vp);
        let s = from_c_str(bytes);
        JS_free(cx, transmute(bytes));
        s
    }
}

pub extern fn debug(cx: *JSContext, argc: c_uint, vp: *JSVal) -> JSBool {
    unsafe {
        let argv = JS_ARGV(cx, vp);
        for i in range(0, argc as int) {
            let jsstr = JS_ValueToString(cx, *ptr::offset(argv, i));
            debug!("%s", jsval_to_rust_str(cx, jsstr));
        }
        JS_SET_RVAL(cx, vp, JSVAL_VOID);
        return 1_i32;
    }
}

pub extern fn assert(cx: *JSContext, argc: c_uint, vp: *JSVal) -> JSBool {
    unsafe {
        let argv = JS_ARGV(cx, vp);

        let argument = match argc {
            0 => JSVAL_VOID,
            _ => *ptr::offset(argv, 0)
        };

        let result = 0;
        if JS_ValueToBoolean(cx, argument, &result) == 0 {
            return 0_i32;
        }

        if result == 0 {
            // This operation can fail, but that is not critical.
            let source = JS_ValueToSource(cx, argument);
            let msg = fmt!("JavaScript assertion failed: %s is falsy!",
                            jsval_to_rust_str(cx, source));

            debug!(msg);
            do msg.to_c_str().with_ref |buf| {
              JS_ReportError(cx, buf);
            }
            return 0_i32;
        }

        JS_SET_RVAL(cx, vp, JSVAL_VOID);
        return 1_i32;
    }
}

pub fn debug_fns(np: @mut NamePool) -> ~[JSFunctionSpec] {
    ~[
        JSFunctionSpec {
            name: np.add(~"debug"),
            call: JSNativeWrapper {
                op: debug,
                info: null()
            },
            nargs: 0,
            flags: 0,
            selfHostedName: null()
        },
        JSFunctionSpec {
            name: np.add(~"assert"),
            call: JSNativeWrapper {
                op: assert,
                info: null()
            },
            nargs: 1,
            flags: 0,
            selfHostedName: null()
        },
        JSFunctionSpec {
            name: null(),
            call: JSNativeWrapper {
                op: null(),
                info: null(),
            },
            nargs: 0,
            flags: 0,
            selfHostedName: null()
        }
    ]
}

<|endoftext|>


<commit_before>#![allow(dead_code)]

extern crate dns;

use dns::hp::{Message,Name,read_dns_message};

static NET1_RS: &'static [u8] = include_bin!("packets/net1-rs.bin");
static NET1_RQ: &'static [u8] = include_bin!("packets/net1-rq.bin");
static FB1_RS: &'static [u8] = include_bin!("packets/fb1-rs.bin");
static FB1_RQ: &'static [u8] = include_bin!("packets/fb1-rq.bin");
static COMNS1_RS: &'static [u8] = include_bin!("packets/comns1-rs.bin");

fn check_std_query_recursive(m: &Message) {
    assert_eq!(m.flags, 0x0100);
    assert_eq!(m.questions.len(), 1);
    assert_eq!(m.answers.len(), 0);
    assert_eq!(m.nameservers.len(), 0);
    assert_eq!(m.additionals.len(), 0);
}
fn check_std_query_norecurse(m: &Message) {
    assert_eq!(m.flags, 0x0000);
    assert_eq!(m.questions.len(), 1);
    assert_eq!(m.answers.len(), 0);
    assert_eq!(m.nameservers.len(), 0);
    assert_eq!(m.additionals.len(), 0);
}
fn check_std_response_recursive(m: &Message, q: uint, a: uint, n: uint, x: uint) {
    assert_eq!(m.flags, 0x8180);
    assert_eq!(m.questions.len(), q);
    assert_eq!(m.answers.len(), a);
    assert_eq!(m.nameservers.len(), n);
    assert_eq!(m.additionals.len(), x);
}
fn check_std_response_norecurse(m: &Message, q: uint, a: uint, n: uint, x: uint) {
    assert_eq!(m.flags, 0x8000);
    assert_eq!(m.questions.len(), q);
    assert_eq!(m.answers.len(), a);
    assert_eq!(m.nameservers.len(), n);
    assert_eq!(m.additionals.len(), x);
}

#[test]
fn test_parse_fb1_rq() {
    let m = match read_dns_message(FB1_RQ) {
        Ok(x) => x,
        Err(e) => { println!("err: {}",e); panic!("FAIL"); },
    };
    assert_eq!(m.id, 0x0b8d);
    check_std_query_recursive(&m);
}
#[test]
fn test_parse_fb1_rs() {
    let m = match read_dns_message(FB1_RS) {
        Ok(x) => x,
        Err(e) => { println!("err: {}",e); panic!("FAIL"); },
    };
    assert_eq!(m.id, 0x0b8d);
    check_std_response_recursive(&m, 1, 1, 0, 0);
}

#[test]
fn test_parse_comns1_rs() {
    let m = match read_dns_message(COMNS1_RS) {
        Ok(x) => x,
        Err(e) => { println!("err: {}",e); panic!("FAIL"); },
    };
    assert_eq!(m.id, 0x363a);
    check_std_response_norecurse(&m, 1, 0, 13, 14);
    let mut a_ct: uint = 0;
    for a in m.nameservers.iter() {
        assert_eq!(a.rttl, 172800);

        let n = Name::from_rdata(a).ok().unwrap().to_string();
        if n.as_slice() == "a.gtld-servers.net." { a_ct += 1; }
        if n.as_slice() == "b.gtld-servers.net." { a_ct += 1; }
        if n.as_slice() == "c.gtld-servers.net." { a_ct += 1; }
        if n.as_slice() == "d.gtld-servers.net." { a_ct += 1; }
        if n.as_slice() == "e.gtld-servers.net." { a_ct += 1; }
        if n.as_slice() == "f.gtld-servers.net." { a_ct += 1; }
        if n.as_slice() == "g.gtld-servers.net." { a_ct += 1; }
        if n.as_slice() == "h.gtld-servers.net." { a_ct += 1; }
        if n.as_slice() == "i.gtld-servers.net." { a_ct += 1; }
        if n.as_slice() == "j.gtld-servers.net." { a_ct += 1; }
        if n.as_slice() == "k.gtld-servers.net." { a_ct += 1; }
        if n.as_slice() == "l.gtld-servers.net." { a_ct += 1; }
        if n.as_slice() == "m.gtld-servers.net." { a_ct += 1; }
    }
    assert_eq!(a_ct, 13);
}

#[test]
fn test_parse_net1_rq() {
    let m = match read_dns_message(NET1_RQ) {
        Ok(x) => x,
        Err(e) => { println!("err: {}",e); panic!("FAIL"); },
    };

    assert_eq!(m.id, 0xe1c9);
    check_std_query_norecurse(&m);
}

#[test]
fn test_parse_net1_rs() {
    let m = match read_dns_message(NET1_RS) {
        Ok(x) => x,
        Err(e) => { println!("err: {}",e); panic!("FAIL"); },
    };
    assert_eq!(m.id, 0xe1c9);
    assert_eq!(m.flags, 0x8000);

    let q = m.questions[0].clone();
    assert_eq!(format!("{}",q.qname).as_slice(), "net.");
    check_std_response_norecurse(&m, 1, 0, 13, 15);
    let mut a_ct: uint = 0;
    for a in m.nameservers.iter() {
        assert_eq!(a.rttl, 172800);

        let n = Name::from_rdata(a).ok().unwrap().to_string();
        if n.as_slice() == "a.gtld-servers.net." { a_ct += 1; }
        if n.as_slice() == "b.gtld-servers.net." { a_ct += 1; }
        if n.as_slice() == "c.gtld-servers.net." { a_ct += 1; }
        if n.as_slice() == "d.gtld-servers.net." { a_ct += 1; }
        if n.as_slice() == "e.gtld-servers.net." { a_ct += 1; }
        if n.as_slice() == "f.gtld-servers.net." { a_ct += 1; }
        if n.as_slice() == "g.gtld-servers.net." { a_ct += 1; }
        if n.as_slice() == "h.gtld-servers.net." { a_ct += 1; }
        if n.as_slice() == "i.gtld-servers.net." { a_ct += 1; }
        if n.as_slice() == "j.gtld-servers.net." { a_ct += 1; }
        if n.as_slice() == "k.gtld-servers.net." { a_ct += 1; }
        if n.as_slice() == "l.gtld-servers.net." { a_ct += 1; }
        if n.as_slice() == "m.gtld-servers.net." { a_ct += 1; }
    }
    assert_eq!(a_ct, 13);
}<commit_msg>Scrub old tests.<commit_after><|endoftext|>


<commit_before>extern crate android_glue;

use libc;
use std::ffi::{CString};
use std::sync::mpsc::{Receiver, channel};
use {CreationError, Event, MouseCursor};
use CreationError::OsError;
use events::ElementState::{Pressed, Released};
use events::Event::{MouseInput, MouseMoved};
use events::MouseButton::LeftMouseButton;

use std::collections::RingBuf;

use BuilderAttribs;

pub struct Window {
    display: ffi::egl::types::EGLDisplay,
    context: ffi::egl::types::EGLContext,
    surface: ffi::egl::types::EGLSurface,
    event_rx: Receiver<android_glue::Event>,
}

pub struct MonitorID;

mod ffi;

pub fn get_available_monitors() -> RingBuf <MonitorID> {
    let mut rb = RingBuf::new();
    rb.push_back(MonitorID);
    rb
}

pub fn get_primary_monitor() -> MonitorID {
    MonitorID
}

impl MonitorID {
    pub fn get_name(&self) -> Option<String> {
        Some("Primary".to_string())
    }

    pub fn get_dimensions(&self) -> (u32, u32) {
        unimplemented!()
    }
}

#[cfg(feature = "headless")]
pub struct HeadlessContext(i32);

#[cfg(feature = "headless")]
impl HeadlessContext {
    /// See the docs in the crate root file.
    pub fn new(_builder: BuilderAttribs) -> Result<HeadlessContext, CreationError> {
        unimplemented!()
    }

    /// See the docs in the crate root file.
    pub unsafe fn make_current(&self) {
        unimplemented!()
    }

    /// See the docs in the crate root file.
    pub fn get_proc_address(&self, _addr: &str) -> *const () {
        unimplemented!()
    }

    pub fn get_api(&self) -> ::Api {
        ::Api::OpenGlEs
    }
}

#[cfg(feature = "headless")]
unsafe impl Send for HeadlessContext {}
#[cfg(feature = "headless")]
unsafe impl Sync for HeadlessContext {}

impl Window {
    pub fn new(builder: BuilderAttribs) -> Result<Window, CreationError> {
        use std::{mem, ptr};

        if builder.sharing.is_some() {
            unimplemented!()
        }

        let native_window = unsafe { android_glue::get_native_window() };
        if native_window.is_null() {
            return Err(OsError(format!("Android's native window is null")));
        }

        let display = unsafe {
            let display = ffi::egl::GetDisplay(mem::transmute(ffi::egl::DEFAULT_DISPLAY));
            if display.is_null() {
                return Err(OsError("No EGL display connection available".to_string()));
            }
            display
        };

        android_glue::write_log("eglGetDisplay succeeded");

        let (_major, _minor) = unsafe {
            let mut major: ffi::egl::types::EGLint = mem::uninitialized();
            let mut minor: ffi::egl::types::EGLint = mem::uninitialized();

            if ffi::egl::Initialize(display, &mut major, &mut minor) == 0 {
                return Err(OsError(format!("eglInitialize failed")))
            }

            (major, minor)
        };

        android_glue::write_log("eglInitialize succeeded");

        let use_gles2 = match builder.gl_version {
            Some((2, 0)) => true,
            _ => false,
        };

        let config = unsafe {
            let mut attribute_list = vec!();
            if use_gles2 {
                attribute_list.push_all(&[ffi::egl::RENDERABLE_TYPE as i32,
                                         ffi::egl::OPENGL_ES2_BIT as i32]);
            }
            attribute_list.push_all(&[ffi::egl::RED_SIZE as i32, 1]);
            attribute_list.push_all(&[ffi::egl::GREEN_SIZE as i32, 1]);
            attribute_list.push_all(&[ffi::egl::BLUE_SIZE as i32, 1]);
            attribute_list.push_all(&[ffi::egl::DEPTH_SIZE as i32, 1]);
            attribute_list.push(ffi::egl::NONE as i32);

            let mut num_config: ffi::egl::types::EGLint = mem::uninitialized();
            let mut config: ffi::egl::types::EGLConfig = mem::uninitialized();
            if ffi::egl::ChooseConfig(display, attribute_list.as_ptr(), &mut config, 1,
                &mut num_config) == 0
            {
                return Err(OsError(format!("eglChooseConfig failed")))
            }

            if num_config <= 0 {
                return Err(OsError(format!("eglChooseConfig returned no available config")))
            }

            config
        };

        android_glue::write_log("eglChooseConfig succeeded");

        let context = unsafe {
            let mut context_attributes = vec!();
            if use_gles2 {
                context_attributes.push_all(&[ffi::egl::CONTEXT_CLIENT_VERSION as i32, 2]);
            }
            context_attributes.push(ffi::egl::NONE as i32);

            let context = ffi::egl::CreateContext(display, config, ptr::null(),
                                                  context_attributes.as_ptr());
            if context.is_null() {
                return Err(OsError(format!("eglCreateContext failed")))
            }
            context
        };

        android_glue::write_log("eglCreateContext succeeded");

        let surface = unsafe {
            let surface = ffi::egl::CreateWindowSurface(display, config, native_window, ptr::null());
            if surface.is_null() {
                return Err(OsError(format!("eglCreateWindowSurface failed")))
            }
            surface
        };

        android_glue::write_log("eglCreateWindowSurface succeeded");

        let (tx, rx) = channel();
        android_glue::add_sender(tx);

        Ok(Window {
            display: display,
            context: context,
            surface: surface,
            event_rx: rx,
        })
    }

    pub fn is_closed(&self) -> bool {
        false
    }

    pub fn set_title(&self, _: &str) {
    }

    pub fn show(&self) {
    }

    pub fn hide(&self) {
    }

    pub fn get_position(&self) -> Option<(i32, i32)> {
        None
    }

    pub fn set_position(&self, _x: i32, _y: i32) {
    }

    pub fn get_inner_size(&self) -> Option<(u32, u32)> {
        let native_window = unsafe { android_glue::get_native_window() };

        if native_window.is_null() {
            None
        } else {
            Some((
                unsafe { ffi::ANativeWindow_getWidth(native_window) } as u32,
                unsafe { ffi::ANativeWindow_getHeight(native_window) } as u32
            ))
        }
    }

    pub fn get_outer_size(&self) -> Option<(u32, u32)> {
        self.get_inner_size()
    }

    pub fn set_inner_size(&self, _x: u32, _y: u32) {
    }

    pub fn create_window_proxy(&self) -> WindowProxy {
        WindowProxy
    }

    pub fn poll_events(&self) -> RingBuf<Event> {
        let mut events = RingBuf::new();
        loop {
            match self.event_rx.try_recv() {
                Ok(event) => match event {
                    android_glue::Event::EventDown => {
                        events.push_back(MouseInput(Pressed, LeftMouseButton));
                    },
                    android_glue::Event::EventUp => {
                        events.push_back(MouseInput(Released, LeftMouseButton));
                    },
                    android_glue::Event::EventMove(x, y) => {
                        events.push_back(MouseMoved((x as i32, y as i32)));
                    },
                },
                Err(_) => {
                    break;
                },
            }
        }
        events
    }

    pub fn wait_events(&self) -> RingBuf<Event> {
        use std::time::Duration;
        use std::io::timer;
        timer::sleep(Duration::milliseconds(16));
        self.poll_events()
    }

    pub fn make_current(&self) {
        unsafe {
            ffi::egl::MakeCurrent(self.display, self.surface, self.surface, self.context);
        }
    }

    pub fn get_proc_address(&self, addr: &str) -> *const () {
        let addr = CString::from_slice(addr.as_bytes()).as_slice_with_nul().as_ptr();
        unsafe {
            ffi::egl::GetProcAddress(addr) as *const ()
        }
    }

    pub fn swap_buffers(&self) {
        unsafe {
            ffi::egl::SwapBuffers(self.display, self.surface);
        }
    }

    pub fn platform_display(&self) -> *mut libc::c_void {
        self.display as *mut libc::c_void
    }

    pub fn get_api(&self) -> ::Api {
        ::Api::OpenGlEs
    }

    pub fn set_window_resize_callback(&mut self, _: Option<fn(u32, u32)>) {
    }

    pub fn set_cursor(&self, _: MouseCursor) {
    }

    pub fn hidpi_factor(&self) -> f32 {
        1.0
    }
}

unsafe impl Send for Window {}
unsafe impl Sync for Window {}

#[cfg(feature = "window")]
#[derive(Clone)]
pub struct WindowProxy;

impl WindowProxy {
    pub fn wakeup_event_loop(&self) {
        unimplemented!()
    }
}

#[unsafe_destructor]
impl Drop for Window {
    fn drop(&mut self) {
        use std::ptr;

        unsafe {
            android_glue::write_log("Destroying gl-init window");
            ffi::egl::MakeCurrent(self.display, ptr::null(), ptr::null(), ptr::null());
            ffi::egl::DestroySurface(self.display, self.surface);
            ffi::egl::DestroyContext(self.display, self.context);
            ffi::egl::Terminate(self.display);
        }
    }
}
<commit_msg>Fix a use-after-free in Android get_proc_address.<commit_after>extern crate android_glue;

use libc;
use std::ffi::{CString};
use std::sync::mpsc::{Receiver, channel};
use {CreationError, Event, MouseCursor};
use CreationError::OsError;
use events::ElementState::{Pressed, Released};
use events::Event::{MouseInput, MouseMoved};
use events::MouseButton::LeftMouseButton;

use std::collections::RingBuf;

use BuilderAttribs;

pub struct Window {
    display: ffi::egl::types::EGLDisplay,
    context: ffi::egl::types::EGLContext,
    surface: ffi::egl::types::EGLSurface,
    event_rx: Receiver<android_glue::Event>,
}

pub struct MonitorID;

mod ffi;

pub fn get_available_monitors() -> RingBuf <MonitorID> {
    let mut rb = RingBuf::new();
    rb.push_back(MonitorID);
    rb
}

pub fn get_primary_monitor() -> MonitorID {
    MonitorID
}

impl MonitorID {
    pub fn get_name(&self) -> Option<String> {
        Some("Primary".to_string())
    }

    pub fn get_dimensions(&self) -> (u32, u32) {
        unimplemented!()
    }
}

#[cfg(feature = "headless")]
pub struct HeadlessContext(i32);

#[cfg(feature = "headless")]
impl HeadlessContext {
    /// See the docs in the crate root file.
    pub fn new(_builder: BuilderAttribs) -> Result<HeadlessContext, CreationError> {
        unimplemented!()
    }

    /// See the docs in the crate root file.
    pub unsafe fn make_current(&self) {
        unimplemented!()
    }

    /// See the docs in the crate root file.
    pub fn get_proc_address(&self, _addr: &str) -> *const () {
        unimplemented!()
    }

    pub fn get_api(&self) -> ::Api {
        ::Api::OpenGlEs
    }
}

#[cfg(feature = "headless")]
unsafe impl Send for HeadlessContext {}
#[cfg(feature = "headless")]
unsafe impl Sync for HeadlessContext {}

impl Window {
    pub fn new(builder: BuilderAttribs) -> Result<Window, CreationError> {
        use std::{mem, ptr};

        if builder.sharing.is_some() {
            unimplemented!()
        }

        let native_window = unsafe { android_glue::get_native_window() };
        if native_window.is_null() {
            return Err(OsError(format!("Android's native window is null")));
        }

        let display = unsafe {
            let display = ffi::egl::GetDisplay(mem::transmute(ffi::egl::DEFAULT_DISPLAY));
            if display.is_null() {
                return Err(OsError("No EGL display connection available".to_string()));
            }
            display
        };

        android_glue::write_log("eglGetDisplay succeeded");

        let (_major, _minor) = unsafe {
            let mut major: ffi::egl::types::EGLint = mem::uninitialized();
            let mut minor: ffi::egl::types::EGLint = mem::uninitialized();

            if ffi::egl::Initialize(display, &mut major, &mut minor) == 0 {
                return Err(OsError(format!("eglInitialize failed")))
            }

            (major, minor)
        };

        android_glue::write_log("eglInitialize succeeded");

        let use_gles2 = match builder.gl_version {
            Some((2, 0)) => true,
            _ => false,
        };

        let config = unsafe {
            let mut attribute_list = vec!();
            if use_gles2 {
                attribute_list.push_all(&[ffi::egl::RENDERABLE_TYPE as i32,
                                         ffi::egl::OPENGL_ES2_BIT as i32]);
            }
            attribute_list.push_all(&[ffi::egl::RED_SIZE as i32, 1]);
            attribute_list.push_all(&[ffi::egl::GREEN_SIZE as i32, 1]);
            attribute_list.push_all(&[ffi::egl::BLUE_SIZE as i32, 1]);
            attribute_list.push_all(&[ffi::egl::DEPTH_SIZE as i32, 1]);
            attribute_list.push(ffi::egl::NONE as i32);

            let mut num_config: ffi::egl::types::EGLint = mem::uninitialized();
            let mut config: ffi::egl::types::EGLConfig = mem::uninitialized();
            if ffi::egl::ChooseConfig(display, attribute_list.as_ptr(), &mut config, 1,
                &mut num_config) == 0
            {
                return Err(OsError(format!("eglChooseConfig failed")))
            }

            if num_config <= 0 {
                return Err(OsError(format!("eglChooseConfig returned no available config")))
            }

            config
        };

        android_glue::write_log("eglChooseConfig succeeded");

        let context = unsafe {
            let mut context_attributes = vec!();
            if use_gles2 {
                context_attributes.push_all(&[ffi::egl::CONTEXT_CLIENT_VERSION as i32, 2]);
            }
            context_attributes.push(ffi::egl::NONE as i32);

            let context = ffi::egl::CreateContext(display, config, ptr::null(),
                                                  context_attributes.as_ptr());
            if context.is_null() {
                return Err(OsError(format!("eglCreateContext failed")))
            }
            context
        };

        android_glue::write_log("eglCreateContext succeeded");

        let surface = unsafe {
            let surface = ffi::egl::CreateWindowSurface(display, config, native_window, ptr::null());
            if surface.is_null() {
                return Err(OsError(format!("eglCreateWindowSurface failed")))
            }
            surface
        };

        android_glue::write_log("eglCreateWindowSurface succeeded");

        let (tx, rx) = channel();
        android_glue::add_sender(tx);

        Ok(Window {
            display: display,
            context: context,
            surface: surface,
            event_rx: rx,
        })
    }

    pub fn is_closed(&self) -> bool {
        false
    }

    pub fn set_title(&self, _: &str) {
    }

    pub fn show(&self) {
    }

    pub fn hide(&self) {
    }

    pub fn get_position(&self) -> Option<(i32, i32)> {
        None
    }

    pub fn set_position(&self, _x: i32, _y: i32) {
    }

    pub fn get_inner_size(&self) -> Option<(u32, u32)> {
        let native_window = unsafe { android_glue::get_native_window() };

        if native_window.is_null() {
            None
        } else {
            Some((
                unsafe { ffi::ANativeWindow_getWidth(native_window) } as u32,
                unsafe { ffi::ANativeWindow_getHeight(native_window) } as u32
            ))
        }
    }

    pub fn get_outer_size(&self) -> Option<(u32, u32)> {
        self.get_inner_size()
    }

    pub fn set_inner_size(&self, _x: u32, _y: u32) {
    }

    pub fn create_window_proxy(&self) -> WindowProxy {
        WindowProxy
    }

    pub fn poll_events(&self) -> RingBuf<Event> {
        let mut events = RingBuf::new();
        loop {
            match self.event_rx.try_recv() {
                Ok(event) => match event {
                    android_glue::Event::EventDown => {
                        events.push_back(MouseInput(Pressed, LeftMouseButton));
                    },
                    android_glue::Event::EventUp => {
                        events.push_back(MouseInput(Released, LeftMouseButton));
                    },
                    android_glue::Event::EventMove(x, y) => {
                        events.push_back(MouseMoved((x as i32, y as i32)));
                    },
                },
                Err(_) => {
                    break;
                },
            }
        }
        events
    }

    pub fn wait_events(&self) -> RingBuf<Event> {
        use std::time::Duration;
        use std::io::timer;
        timer::sleep(Duration::milliseconds(16));
        self.poll_events()
    }

    pub fn make_current(&self) {
        unsafe {
            ffi::egl::MakeCurrent(self.display, self.surface, self.surface, self.context);
        }
    }

    pub fn get_proc_address(&self, addr: &str) -> *const () {
        let addr = CString::from_slice(addr.as_bytes());
        let addr = addr.as_slice_with_nul().as_ptr();
        unsafe {
            ffi::egl::GetProcAddress(addr) as *const ()
        }
    }

    pub fn swap_buffers(&self) {
        unsafe {
            ffi::egl::SwapBuffers(self.display, self.surface);
        }
    }

    pub fn platform_display(&self) -> *mut libc::c_void {
        self.display as *mut libc::c_void
    }

    pub fn get_api(&self) -> ::Api {
        ::Api::OpenGlEs
    }

    pub fn set_window_resize_callback(&mut self, _: Option<fn(u32, u32)>) {
    }

    pub fn set_cursor(&self, _: MouseCursor) {
    }

    pub fn hidpi_factor(&self) -> f32 {
        1.0
    }
}

unsafe impl Send for Window {}
unsafe impl Sync for Window {}

#[cfg(feature = "window")]
#[derive(Clone)]
pub struct WindowProxy;

impl WindowProxy {
    pub fn wakeup_event_loop(&self) {
        unimplemented!()
    }
}

#[unsafe_destructor]
impl Drop for Window {
    fn drop(&mut self) {
        use std::ptr;

        unsafe {
            android_glue::write_log("Destroying gl-init window");
            ffi::egl::MakeCurrent(self.display, ptr::null(), ptr::null(), ptr::null());
            ffi::egl::DestroySurface(self.display, self.surface);
            ffi::egl::DestroyContext(self.display, self.context);
            ffi::egl::Terminate(self.display);
        }
    }
}
<|endoftext|>