<commit_before>use crate::{
    player::Player,
    settings::Settings,
};

pub struct Game<'a> {
    pub settings: &'a Settings,
    players: [Player; 2],
    state: GameState,
    turn: u8,
}

impl<'a> Game<'a> {
    pub fn new(settings: &Settings) -> Game {
        let grid_size = [
            settings.spaces[0],
            settings.spaces[1],
        ];

        Game {
            settings: &settings,
            players: [
                Player::new(grid_size, false),
                Player::new(grid_size, true)
            ],
            state: GameState::Placement,
            turn: 0,
        }
    }

    /// Returns a reference to the currently active player.
    pub fn active_player(&self) -> &Player {
        &self.players[self.turn as usize]
    }

    /// Returns a reference to the currently inactive player.
    pub fn inactive_player(&self) -> &Player {
        &self.players[self.not_turn()]
    }

    /// Returns a mutable reference to the currently active player.
    pub fn active_player_mut(&mut self) -> &mut Player {
        &mut self.players[self.turn as usize]
    }

    /// Returns whether the game's current state is ship placement.
    pub fn is_state_placement(&self) -> bool {
        self.state == GameState::Placement
    }

    /// Returns whether the game's current state is active.
    pub fn is_state_active(&self) -> bool {
        self.state == GameState::Active
    }

    /// Returns whether the game's current state is complete.
    pub fn is_state_complete(&self) -> bool {
        self.state == GameState::Over
    }

    /// Starts the game by setting the game state to active.
    pub fn start(&mut self) {
        self.state = GameState::Active;
    }

    /// Returns as `usize` the index of the currently active player.
    pub fn turn(&self) -> usize {
        self.turn as usize
    }

    /// Returns as `usize` the index of the currently inactive player.
    pub fn not_turn(&self) -> usize {
        (self.turn + 1) as usize % 2
    }

    /// Sets the inactive player as active.
    pub fn switch_turn(&mut self) {
        self.turn = self.not_turn() as u8;
    }

    /// Returns whether it is currently a human player's turn.
    pub fn is_player_turn(&self) -> bool {
        !self.players[self.turn as usize].is_cpu
    }

    /// Returns whether a human player is currently placing ships.
    pub fn is_player_placing_ship(&self) -> bool {
        self.state == GameState::Placement && self.is_player_turn()
    }

    /// Returns whether a human player is currently selecting a space.
    pub fn is_player_selecting_space(&self) -> bool {
        self.state == GameState::Active && self.is_player_turn()
    }

    /// Returns whether the active player is CPU-controlled.
    pub fn is_active_player_cpu(&self) -> bool {
        self.players[self.turn as usize].is_cpu
    }

    /// Returns as `usize` the winner, if there is one.
    pub fn get_winner(&self) -> Option<usize> {
        match self.state {
            GameState::Over => Some(self.turn as usize),
            _ => None
        }
    }

    /// Selects a position on the opponent's grid if it is unchecked.
    pub fn select_opponent_space(&mut self, pos: &[u8; 2]) -> bool {
        let ref mut opponent = self.players[self.not_turn()];
        let selected = opponent.space(pos).is_unchecked() && opponent.select_space(pos);

        if selected && opponent.is_ship_sunk_by_pos(pos) {
            self.state = match opponent.all_ships_sunk() {
                true => GameState::Over,
                false => GameState::Active,
            };
        }

        selected
    }
}

#[derive(Clone, Copy, PartialEq)]
pub enum GameState {
    Placement,
    Active,
    Over
}

<commit_msg>Rename GameState::Over to GameState::Complete<commit_after>use crate::{
    player::Player,
    settings::Settings,
};

pub struct Game<'a> {
    pub settings: &'a Settings,
    players: [Player; 2],
    state: GameState,
    turn: u8,
}

impl<'a> Game<'a> {
    pub fn new(settings: &Settings) -> Game {
        let grid_size = [
            settings.spaces[0],
            settings.spaces[1],
        ];

        Game {
            settings: &settings,
            players: [
                Player::new(grid_size, false),
                Player::new(grid_size, true)
            ],
            state: GameState::Placement,
            turn: 0,
        }
    }

    /// Returns a reference to the currently active player.
    pub fn active_player(&self) -> &Player {
        &self.players[self.turn as usize]
    }

    /// Returns a reference to the currently inactive player.
    pub fn inactive_player(&self) -> &Player {
        &self.players[self.not_turn()]
    }

    /// Returns a mutable reference to the currently active player.
    pub fn active_player_mut(&mut self) -> &mut Player {
        &mut self.players[self.turn as usize]
    }

    /// Returns whether the game's current state is ship placement.
    pub fn is_state_placement(&self) -> bool {
        self.state == GameState::Placement
    }

    /// Returns whether the game's current state is active.
    pub fn is_state_active(&self) -> bool {
        self.state == GameState::Active
    }

    /// Returns whether the game's current state is complete.
    pub fn is_state_complete(&self) -> bool {
        self.state == GameState::Complete
    }

    /// Starts the game by setting the game state to active.
    pub fn start(&mut self) {
        self.state = GameState::Active;
    }

    /// Returns as `usize` the index of the currently active player.
    pub fn turn(&self) -> usize {
        self.turn as usize
    }

    /// Returns as `usize` the index of the currently inactive player.
    pub fn not_turn(&self) -> usize {
        (self.turn + 1) as usize % 2
    }

    /// Sets the inactive player as active.
    pub fn switch_turn(&mut self) {
        self.turn = self.not_turn() as u8;
    }

    /// Returns whether it is currently a human player's turn.
    pub fn is_player_turn(&self) -> bool {
        !self.players[self.turn as usize].is_cpu
    }

    /// Returns whether a human player is currently placing ships.
    pub fn is_player_placing_ship(&self) -> bool {
        self.state == GameState::Placement && self.is_player_turn()
    }

    /// Returns whether a human player is currently selecting a space.
    pub fn is_player_selecting_space(&self) -> bool {
        self.state == GameState::Active && self.is_player_turn()
    }

    /// Returns whether the active player is CPU-controlled.
    pub fn is_active_player_cpu(&self) -> bool {
        self.players[self.turn as usize].is_cpu
    }

    /// Returns as `usize` the winner, if there is one.
    pub fn get_winner(&self) -> Option<usize> {
        match self.state {
            GameState::Complete => Some(self.turn as usize),
            _ => None
        }
    }

    /// Selects a position on the opponent's grid if it is unchecked.
    pub fn select_opponent_space(&mut self, pos: &[u8; 2]) -> bool {
        let ref mut opponent = self.players[self.not_turn()];
        let selected = opponent.space(pos).is_unchecked() && opponent.select_space(pos);

        if selected && opponent.is_ship_sunk_by_pos(pos) {
            self.state = match opponent.all_ships_sunk() {
                true => GameState::Complete,
                false => GameState::Active,
            };
        }

        selected
    }
}

#[derive(Clone, Copy, PartialEq)]
pub enum GameState {
    Placement,
    Active,
    Complete,
}

<|endoftext|>


<commit_before>//! Game loop.

// External crates.
use graphics::*;
use gl;
use gl::types::GLint;
use time;

// Local crate.
use Gl = gl_back_end::Gl;
use GlData = gl_back_end::GlData;
use GameWindow = game_window::GameWindow;
use AssetStore = asset_store::AssetStore;
use keyboard;
use event;
use mouse;

/// Implemented by game applications.
pub trait Game {
    /// Render graphics.
    ///
    /// `context` is a Rust-Graphics context.
    /// `gl` is the Piston OpenGL back-end for Rust-Graphics.
    fn render(&self, _context: &Context, _gl: &mut Gl) {}

    /// Update the physical state of the game.
    ///
    /// `dt` is the delta time from last update in seconds.
    fn update(&mut self, _dt: f64, _asset_store: &mut AssetStore) {}

    /// Perform tasks for loading before showing anything.
    fn load(&mut self, _asset_store: &mut AssetStore) {}

    /// User pressed a key.
    ///
    /// This can be overridden to handle key pressed events.
    fn key_press(
        &mut self,
        _key: keyboard::Key,
        _asset_store: &mut AssetStore
    ) {}

    /// User released a key.
    ///
    /// This can be overridden to handle key released events.
    fn key_release(
        &mut self,
        _key: keyboard::Key,
        _asset_store: &mut AssetStore
    ) {}

    /// Pressed a mouse button.
    fn mouse_press(
        &mut self,
        _button: mouse::Button,
        _asset_store: &mut AssetStore
    ) {}

    /// Released a mouse button.
    fn mouse_release(
        &mut self,
        _button: mouse::Button,
        _asset_store: &mut AssetStore
    ) {}

    /// Moved mouse cursor.
    fn mouse_move(
        &mut self,
        _x: f64,
        _y: f64,
        _asset_store: &mut AssetStore
    ) {}

    /// Moved mouse relative, not bounded by cursor.
    fn mouse_relative_move(
        &mut self,
        _dx: f64,
        _dy: f64,
        _asset_store: &mut AssetStore
    ) {}

    /// Sets up viewport.
    ///
    /// A viewport is the region of the window where graphics is rendered.
    #[inline(always)]
    fn viewport<W: GameWindow>(&self, game_window: &W) {
        let (w, h) = game_window.get_size();
        gl::Viewport(0, 0, w as GLint, h as GLint);
    }

    /// Whether the window should be closed.
    ///
    /// When this is `true` the application shuts down.
    /// This can be overridden to emulate a user closing the window.
    /// One can also override this method to prevent window from closing.
    fn should_close<W: GameWindow>(&self, game_window: &W) -> bool {
        game_window.should_close()
    }

    /// Swaps the front buffer with the back buffer.
    ///
    /// When called, This shows the next frame.
    /// The graphics is rendered to the back buffer.
    /// The front buffer is displayed on the screen.
    fn swap_buffers<W: GameWindow>(&self, game_window: &W) {
        game_window.swap_buffers()
    }

    /// Handles events using current game window settings.
    ///
    /// This can be overriden to do custom event handling.
    fn handle_events<W: GameWindow>(
        &mut self,
        game_window: &mut W,
        asset_store: &mut AssetStore
    ) {
        loop {
            match game_window.poll_event() {
                event::KeyPressed(keycode) => {
                    self.key_press(keycode, asset_store)
                },
                event::KeyReleased(keycode) => {
                    self.key_release(keycode, asset_store)
                },
                event::MouseButtonPressed(mouse_button) => {
                    self.mouse_press(mouse_button, asset_store)
                },
                event::MouseButtonReleased(mouse_button) => {
                    self.mouse_release(mouse_button, asset_store)
                },
                event::MouseMoved(x, y, relative_move) => {
                    self.mouse_move(x, y, asset_store);
                    match relative_move {
                        Some((dx, dy)) =>
                            self.mouse_relative_move(dx, dy, asset_store),
                        None => {},
                    }
                },
                event::NoEvent => {
                    break
                },
            }
        }
    }

    /// Executes a game loop.
    ///
    /// The loop continues until `should_close` returns true.
    fn run<W: GameWindow>(
        &mut self,
        game_window: &mut W,
        asset_store: &mut AssetStore
    ) {
        use graphics::{Clear, AddColor};

        self.load(asset_store);
        let mut gl_data = GlData::new();
        let context = Context::new();
        let bg = game_window.get_settings().background_color;
        let bg = context.rgba(bg[0], bg[1], bg[2], bg[3]);
        let updates_per_second: u64 = 100;
        let dt: f64 = 1.0 / updates_per_second as f64;
        let update_time_in_ns: u64 = 1_000_000_000 / updates_per_second;
        let mut last_update = time::precise_time_ns();
        while !self.should_close(game_window) {
            self.viewport(game_window);
            let (w, h) = game_window.get_size();
            if w != 0 && h != 0 {
                let mut gl = Gl::new(&mut gl_data, asset_store);
                bg.clear(&mut gl);
                self.render(&context
                .trans(-1.0, 1.0)
                .scale(2.0 / w as f64, -2.0 / h as f64)
                .store_view(), &mut gl);
            }
            self.swap_buffers(game_window);
            // Perform updates by fixed time step until it catches up.
            loop {
                self.update(dt, asset_store);
                last_update += update_time_in_ns;
                let now = time::precise_time_ns();
                if now <= last_update { break; }
            }
            self.handle_events(game_window, asset_store);
        }
    }
}

<commit_msg>Updated game loop<commit_after>//! Game loop.

// External crates.
use graphics::*;
use gl;
use gl::types::GLint;
use time;

// Local crate.
use Gl = gl_back_end::Gl;
use GlData = gl_back_end::GlData;
use GameWindow = game_window::GameWindow;
use AssetStore = asset_store::AssetStore;
use keyboard;
use event;
use mouse;

/// Implemented by game applications.
pub trait Game {
    /// Render graphics.
    ///
    /// `context` is a Rust-Graphics context.
    /// `gl` is the Piston OpenGL back-end for Rust-Graphics.
    fn render(&self, _ext_dt: f64, _context: &Context, _gl: &mut Gl) {}

    /// Update the physical state of the game.
    ///
    /// `dt` is the delta time from last update in seconds.
    fn update(&mut self, _dt: f64, _asset_store: &mut AssetStore) {}

    /// Perform tasks for loading before showing anything.
    fn load(&mut self, _asset_store: &mut AssetStore) {}

    /// User pressed a key.
    ///
    /// This can be overridden to handle key pressed events.
    fn key_press(
        &mut self,
        _key: keyboard::Key,
        _asset_store: &mut AssetStore
    ) {}

    /// User released a key.
    ///
    /// This can be overridden to handle key released events.
    fn key_release(
        &mut self,
        _key: keyboard::Key,
        _asset_store: &mut AssetStore
    ) {}

    /// Pressed a mouse button.
    fn mouse_press(
        &mut self,
        _button: mouse::Button,
        _asset_store: &mut AssetStore
    ) {}

    /// Released a mouse button.
    fn mouse_release(
        &mut self,
        _button: mouse::Button,
        _asset_store: &mut AssetStore
    ) {}

    /// Moved mouse cursor.
    fn mouse_move(
        &mut self,
        _x: f64,
        _y: f64,
        _asset_store: &mut AssetStore
    ) {}

    /// Moved mouse relative, not bounded by cursor.
    fn mouse_relative_move(
        &mut self,
        _dx: f64,
        _dy: f64,
        _asset_store: &mut AssetStore
    ) {}

    /// Sets up viewport.
    ///
    /// A viewport is the region of the window where graphics is rendered.
    #[inline(always)]
    fn viewport<W: GameWindow>(&self, game_window: &W) {
        let (w, h) = game_window.get_size();
        gl::Viewport(0, 0, w as GLint, h as GLint);
    }

    /// Whether the window should be closed.
    ///
    /// When this is `true` the application shuts down.
    /// This can be overridden to emulate a user closing the window.
    /// One can also override this method to prevent window from closing.
    fn should_close<W: GameWindow>(&self, game_window: &W) -> bool {
        game_window.should_close()
    }

    /// Swaps the front buffer with the back buffer.
    ///
    /// When called, This shows the next frame.
    /// The graphics is rendered to the back buffer.
    /// The front buffer is displayed on the screen.
    fn swap_buffers<W: GameWindow>(&self, game_window: &W) {
        game_window.swap_buffers()
    }

    /// Handles events using current game window settings.
    ///
    /// This can be overriden to do custom event handling.
    fn handle_events<W: GameWindow>(
        &mut self,
        game_window: &mut W,
        asset_store: &mut AssetStore
    ) {
        loop {
            match game_window.poll_event() {
                event::KeyPressed(keycode) => {
                    self.key_press(keycode, asset_store)
                },
                event::KeyReleased(keycode) => {
                    self.key_release(keycode, asset_store)
                },
                event::MouseButtonPressed(mouse_button) => {
                    self.mouse_press(mouse_button, asset_store)
                },
                event::MouseButtonReleased(mouse_button) => {
                    self.mouse_release(mouse_button, asset_store)
                },
                event::MouseMoved(x, y, relative_move) => {
                    self.mouse_move(x, y, asset_store);
                    match relative_move {
                        Some((dx, dy)) =>
                            self.mouse_relative_move(dx, dy, asset_store),
                        None => {},
                    }
                },
                event::NoEvent => {
                    break
                },
            }
        }
    }

    /// Executes a game loop.
    ///
    /// The loop continues until `should_close` returns true.
    fn run<W: GameWindow>(
        &mut self,
        game_window: &mut W,
        asset_store: &mut AssetStore
    ) {
        use graphics::{Clear, AddColor};

        self.load(asset_store);
        let mut gl_data = GlData::new();
        let context = Context::new();
        let bg = game_window.get_settings().background_color;
        let bg = context.rgba(bg[0], bg[1], bg[2], bg[3]);
        let updates_per_second: f64 = 120.0;
        let max_updates_per_frame: u32 = 240;
        let max_frames_per_second: f64 = 60.0;

        let billion: u64 = 1_000_000_000;
        let dt: f64 = 1.0 / updates_per_second;
        let update_time_in_ns: u64 = billion / updates_per_second as u64;

        let start = time::precise_time_ns();
        let min_ns_per_frame = (billion as f64 / max_frames_per_second) as u64;
        let mut next_render = start;
        let mut last_update = start;
        // Set updated to 'true' to trigger rendering before first update.
        let mut updated = true;
        while !self.should_close(game_window) {
            let now = time::precise_time_ns();

            if updated && now >= next_render {
                // Render.
                let (w, h) = game_window.get_size();
                if w != 0 && h != 0 {
                    self.viewport(game_window);
                    let mut gl = Gl::new(&mut gl_data, asset_store);
                    bg.clear(&mut gl);
                    // Extrapolate time forward to allow smooth motion.
                    // 'now' is always bigger than 'last_update'.
                    let ext_dt = (now - last_update) as f64 / billion as f64;
                    self.render(
                        ext_dt,
                        &context
                        .trans(-1.0, 1.0)
                        .scale(2.0 / w as f64, -2.0 / h as f64)
                        .store_view(),
                        &mut gl
                    );
                    self.swap_buffers(game_window);
                }

                // Set moment for next rendering.
                next_render = now + min_ns_per_frame;
            }

            // Perform updates by fixed time step until it catches up.
            updated = false;
            for _ in range(0, max_updates_per_frame) {
                // Break when catching up to next frame.
                if next_render <= last_update { break; }

                // Handle user input.
                // This is handled every update to make it more responsive.
                self.handle_events(game_window, asset_store);

                // Update application state.
                self.update(dt, asset_store);
                last_update += update_time_in_ns;
                updated = true;
            }
        }
    }
}

<|endoftext|>


<commit_before>//! Game loop.

use time;
use glfw;
use glfw::Context;
use gl = opengles::gl2;
use graphics;
use Gl = gl::Gl;

use game_window::GameWindow;

/// Basic settings for window behavior.
pub struct GameSettings {
    /// If true, exit when pressing Esc.
    pub exit_on_esc: bool,
    /// The color to use as background.
    pub background_color: [f32, ..4],
}

impl GameSettings {
    /// Gets default settings.
    pub fn default() -> GameSettings {
        GameSettings {
            exit_on_esc: true,
            background_color: [0.0, 0.0, 0.0, 1.0],
        }
    }

    /// Creates a new Settings.
    pub fn new(exit_on_esc: bool, background_color: [f32, ..4]) -> GameSettings {
        GameSettings {
            exit_on_esc: exit_on_esc,
            background_color: background_color,
        }
    }
}

/// Implement default behavior for a game.
pub trait Game {
    /// Read settings.
    fn get_settings<'a>(&'a self) -> &'a GameSettings;

    /// Render graphics.
    fn render(&self, context: &graphics::Context, gl: &mut Gl);

    /// Update the physical state of the game.
    fn update(&mut self, dt: f64);

    /// Perform tasks for loading before showing anything.
    fn load(&mut self);

    /// User pressed a key.
    fn key_press(&mut self, _key: glfw::Key) {}

    /// User released a key.
    fn key_release(&mut self, _key: glfw::Key) {}

    /// Sets up viewport.
    #[inline(always)]
    fn viewport(&self, game_window: &GameWindow) {
        let (w, h) = game_window.window.get_size();
        gl::viewport(0, 0, w as gl::GLint, h as gl::GLint);
    }

    /// Whether the window should be closed.
    fn should_close(&self, game_window: &GameWindow) -> bool {
        game_window.window.should_close()
    }

    /// Swaps the front buffer with the back buffer.
    /// This shows the next frame.
    fn swap_buffers(&self, game_window: &GameWindow) {
        game_window.window.swap_buffers()
    }

    /// Handles events with default settings..
    fn handle_events(&mut self, game_window: &GameWindow) {
        let exit_on_esc = self.get_settings().exit_on_esc;
        game_window.glfw.poll_events();
        for (_, event) in
        glfw::flush_messages(&game_window.events) {
            match event {
                // Close with Esc.
                glfw::KeyEvent(glfw::KeyEscape, _, glfw::Press, _)
                if exit_on_esc  => {
                    game_window.window.set_should_close(true)
                },
                glfw::KeyEvent(key, _, glfw::Press, _) => {
                    self.key_press(key)
                },
                glfw::KeyEvent(key, _, glfw::Release, _) => {
                    self.key_release(key)
                },
                _ => {},
            }
        }
    }

    /// Executes a game loop.
    fn run(&mut self, game_window: &GameWindow) {
        use graphics::{Clear, AddColor};
        use gl::Gl;

        self.load();
        let mut gl = Gl::new();
        let context = graphics::Context::new();
        let bg = self.get_settings().background_color;
        let bg = context.rgba(bg[0], bg[1], bg[2], bg[3]);
        let updates_per_second: u64 = 100;
        let dt: f64 = 1.0 / updates_per_second as f64;
        let update_time_in_ns: u64 = 1_000_000_000 / updates_per_second;
        let mut last_update = time::precise_time_ns();
        while !self.should_close(game_window) {
            self.viewport(game_window);
            bg.clear(&mut gl);
            self.render(&context, &mut gl);
            self.swap_buffers(game_window);
            // Perform updates by fixed time step until it catches up.
            loop {
                self.update(dt);
                last_update += update_time_in_ns;
                let now = time::precise_time_ns();
                if now <= last_update { break; }
            }
            self.handle_events(game_window);
        }
    }
}

<commit_msg>Renamed `get_settings` to `get_game_settings`<commit_after>//! Game loop.

use time;
use glfw;
use glfw::Context;
use gl = opengles::gl2;
use graphics;
use Gl = gl::Gl;

use game_window::GameWindow;

/// Basic settings for window behavior.
pub struct GameSettings {
    /// If true, exit when pressing Esc.
    pub exit_on_esc: bool,
    /// The color to use as background.
    pub background_color: [f32, ..4],
}

impl GameSettings {
    /// Gets default settings.
    pub fn default() -> GameSettings {
        GameSettings {
            exit_on_esc: true,
            background_color: [0.0, 0.0, 0.0, 1.0],
        }
    }

    /// Creates a new Settings.
    pub fn new(exit_on_esc: bool, background_color: [f32, ..4]) -> GameSettings {
        GameSettings {
            exit_on_esc: exit_on_esc,
            background_color: background_color,
        }
    }
}

/// Implement default behavior for a game.
pub trait Game {
    /// Read game settings.
    fn get_game_settings<'a>(&'a self) -> &'a GameSettings;

    /// Render graphics.
    fn render(&self, context: &graphics::Context, gl: &mut Gl);

    /// Update the physical state of the game.
    fn update(&mut self, dt: f64);

    /// Perform tasks for loading before showing anything.
    fn load(&mut self);

    /// User pressed a key.
    fn key_press(&mut self, _key: glfw::Key) {}

    /// User released a key.
    fn key_release(&mut self, _key: glfw::Key) {}

    /// Sets up viewport.
    #[inline(always)]
    fn viewport(&self, game_window: &GameWindow) {
        let (w, h) = game_window.window.get_size();
        gl::viewport(0, 0, w as gl::GLint, h as gl::GLint);
    }

    /// Whether the window should be closed.
    fn should_close(&self, game_window: &GameWindow) -> bool {
        game_window.window.should_close()
    }

    /// Swaps the front buffer with the back buffer.
    /// This shows the next frame.
    fn swap_buffers(&self, game_window: &GameWindow) {
        game_window.window.swap_buffers()
    }

    /// Handles events with default settings..
    fn handle_events(&mut self, game_window: &GameWindow) {
        let exit_on_esc = self.get_game_settings().exit_on_esc;
        game_window.glfw.poll_events();
        for (_, event) in
        glfw::flush_messages(&game_window.events) {
            match event {
                // Close with Esc.
                glfw::KeyEvent(glfw::KeyEscape, _, glfw::Press, _)
                if exit_on_esc  => {
                    game_window.window.set_should_close(true)
                },
                glfw::KeyEvent(key, _, glfw::Press, _) => {
                    self.key_press(key)
                },
                glfw::KeyEvent(key, _, glfw::Release, _) => {
                    self.key_release(key)
                },
                _ => {},
            }
        }
    }

    /// Executes a game loop.
    fn run(&mut self, game_window: &GameWindow) {
        use graphics::{Clear, AddColor};
        use gl::Gl;

        self.load();
        let mut gl = Gl::new();
        let context = graphics::Context::new();
        let bg = self.get_game_settings().background_color;
        let bg = context.rgba(bg[0], bg[1], bg[2], bg[3]);
        let updates_per_second: u64 = 100;
        let dt: f64 = 1.0 / updates_per_second as f64;
        let update_time_in_ns: u64 = 1_000_000_000 / updates_per_second;
        let mut last_update = time::precise_time_ns();
        while !self.should_close(game_window) {
            self.viewport(game_window);
            bg.clear(&mut gl);
            self.render(&context, &mut gl);
            self.swap_buffers(game_window);
            // Perform updates by fixed time step until it catches up.
            loop {
                self.update(dt);
                last_update += update_time_in_ns;
                let now = time::precise_time_ns();
                if now <= last_update { break; }
            }
            self.handle_events(game_window);
        }
    }
}

<|endoftext|>


<commit_before>use gl;
use gl::types::*;
use gl_context::{GLContext, GLContextExistence};
use shader::*;
use std::cell::RefCell;
use std::kinds::marker::ContravariantLifetime;
use std::mem;
use std::ptr;
use std::rc::Rc;

/// Gets the id number for a given input of the shader program.
#[allow(non_snake_case)]
pub fn glGetAttribLocation(shader_program: GLuint, name: &str) -> GLint {
  name.with_c_str(|ptr| unsafe { gl::GetAttribLocation(shader_program, ptr) })
}

pub struct BufferHandle<'a> {
  pub gl_id: GLuint,
  pub lifetime: ContravariantLifetime<'a>,
}

impl<'a> BufferHandle<'a> {
  pub fn new(_gl: &'a GLContextExistence) -> BufferHandle<'a> {
    let mut gl_id = 0;

    unsafe {
      gl::GenBuffers(1, &mut gl_id);
    }

    assert!(gl_id != 0);

    BufferHandle {
      gl_id: gl_id,
      lifetime: ContravariantLifetime,
    }
  }
}

#[unsafe_destructor]
impl<'a> Drop for BufferHandle<'a> {
  fn drop(&mut self) {
    unsafe {
      gl::DeleteBuffers(1, &self.gl_id);
    }
  }
}

/// Fixed-size VRAM buffer for individual bytes.
pub struct GLByteBuffer<'a> {
  pub handle: BufferHandle<'a>,
  /// number of bytes in the buffer.
  pub length: uint,
  /// maximum number of bytes in the buffer.
  pub capacity: uint,
}

impl<'a> GLByteBuffer<'a> {
  /// Creates a new array of objects on the GPU.
  /// capacity is provided in units of size slice_span.
  pub fn new(
    gl: &'a GLContextExistence,
    gl_context: &mut GLContext,
    capacity: uint,
  ) -> GLByteBuffer<'a> {
    let handle = BufferHandle::new(gl);

    unsafe {
      gl::BindBuffer(gl::ARRAY_BUFFER, handle.gl_id);

      gl::BufferData(
        gl::ARRAY_BUFFER,
        capacity as GLsizeiptr,
        ptr::null(),
        gl::DYNAMIC_DRAW,
      );
    }

    match gl_context.get_error() {
      gl::NO_ERROR => {},
      gl::OUT_OF_MEMORY => panic!("Out of VRAM"),
      err => panic!("OpenGL error 0x{:x}", err),
    }

    GLByteBuffer {
      handle: handle,
      length: 0,
      capacity: capacity,
    }
  }

  /// Add more data into this buffer.
  pub unsafe fn push(&mut self, gl: &mut GLContext, vs: *const u8, count: uint) {
    assert!(
      self.length + count <= self.capacity,
      "GLByteBuffer::push {} into a {}/{} full GLByteBuffer",
      count,
      self.length,
      self.capacity
    );

    self.update_inner(gl, self.length, vs, count);
    self.length += count;
  }

  pub fn swap_remove(&mut self, _gl: &mut GLContext, i: uint, count: uint) {
    assert!(count <= self.length);
    self.length -= count;
    assert!(i <= self.length);

    // In the `i == self.length` case, we don't bother with the swap;
    // decreasing `self.length` is enough.

    if i < self.length {
      assert!(
        i <= self.length - count,
        "GLByteBuffer::swap_remove would cause copy in overlapping regions"
      );

      unsafe {
        gl::BindBuffer(gl::ARRAY_BUFFER, self.handle.gl_id);

        gl::CopyBufferSubData(
          gl::ARRAY_BUFFER,
          gl::ARRAY_BUFFER,
          self.length as i64,
          i as i64,
          count as i64,
        );
      }
    }
  }

  pub unsafe fn update(&self, gl: &mut GLContext, idx: uint, vs: *const u8, count: uint) {
    assert!(idx + count <= self.length);
    self.update_inner(gl, idx, vs, count);
  }

  unsafe fn update_inner(
    &self,
    _gl: &mut GLContext,
    idx: uint,
    vs: *const u8,
    count: uint,
  ) {
    assert!(idx + count <= self.capacity);

    gl::BindBuffer(gl::ARRAY_BUFFER, self.handle.gl_id);

    gl::BufferSubData(
      gl::ARRAY_BUFFER,
      idx as i64,
      count as i64,
      mem::transmute(vs)
    );
  }
}

/// Fixed-size typed VRAM buffer, optimized for bulk inserts.
pub struct GLBuffer<'a, T> {
  pub byte_buffer: GLByteBuffer<'a>,
}

impl<'a, T> GLBuffer<'a, T> {
  pub fn new(
    gl: &'a GLContextExistence,
    gl_context: &mut GLContext,
    capacity: uint,
  ) -> GLBuffer<'a, T> {
    GLBuffer {
      byte_buffer: GLByteBuffer::new(gl, gl_context, capacity * mem::size_of::<T>()),
    }
  }

  pub fn push(&mut self, gl: &mut GLContext, vs: &[T]) {
    unsafe {
      self.byte_buffer.push(
        gl,
        mem::transmute(vs.as_ptr()),
        mem::size_of::<T>() * vs.len()
      );
    }
  }

  pub fn update(&mut self, gl: &mut GLContext, idx: uint, vs: &[T]) {
    unsafe {
      self.byte_buffer.update(
        gl,
        mem::size_of::<T>() * idx,
        mem::transmute(vs.as_ptr()),
        mem::size_of::<T>() * vs.len(),
      );
    }
  }

  pub fn swap_remove(&mut self, gl: &mut GLContext, idx: uint, count: uint) {
    self.byte_buffer.swap_remove(
      gl,
      mem::size_of::<T>() * idx,
      mem::size_of::<T>() * count,
    );
  }
}

#[deriving(Show)]
#[deriving(Copy, Clone)]
pub enum DrawMode {
  Lines,
  Triangles,
  Points,
}

impl DrawMode {
  fn to_enum(&self) -> GLenum {
    match *self {
      DrawMode::Lines     => gl::LINES,
      DrawMode::Triangles => gl::TRIANGLES,
      DrawMode::Points    => gl::POINTS,
    }
  }
}

#[deriving(Show)]
#[deriving(Copy, Clone)]
pub enum GLType {
  Float,
  UInt,
  Int,
}

impl GLType {
  pub fn size(&self) -> uint {
    match *self {
      GLType::Float => mem::size_of::<GLfloat>(),
      GLType::UInt  => mem::size_of::<GLuint>(),
      GLType::Int   => mem::size_of::<GLint>(),
    }
  }

  pub fn gl_enum(&self) -> GLenum {
    match *self {
      GLType::Float => gl::FLOAT,
      GLType::UInt  => gl::UNSIGNED_INT,
      GLType::Int   => gl::INT,
    }
  }

  pub fn is_integral(&self) -> bool {
    match *self {
      GLType::Float => false,
      GLType::UInt  => true,
      GLType::Int   => true,
    }
  }
}

#[deriving(Show)]
/// Specifies how to pass data from OpenGL to the vertex shaders.
pub struct VertexAttribData<'a> {
  /// Cooresponds to the shader's `input variable`.
  pub name: &'a str,
  /// The size of this attribute, in the provided units.
  pub size: uint,
  pub unit: GLType,
}

pub struct ArrayHandle<'a> {
  pub lifetime: ContravariantLifetime<'a>,
  pub gl_id: GLuint,
}

impl<'a> ArrayHandle<'a> {
  pub fn new(_gl: &'a GLContextExistence) -> ArrayHandle<'a> {
    let mut gl_id = 0;
    unsafe {
      gl::GenVertexArrays(1, &mut gl_id);
    }

    ArrayHandle {
      gl_id: gl_id,
      lifetime: ContravariantLifetime,
    }
  }
}

#[unsafe_destructor]
impl<'a> Drop for ArrayHandle<'a> {
  fn drop(&mut self) {
    unsafe {
      gl::DeleteVertexArrays(1, &self.gl_id);
    }
  }
}

/// A fixed-capacity array of bytes passed to OpenGL.
pub struct GLArray<'a, T> {
  pub buffer: GLBuffer<'a, T>,
  pub handle: ArrayHandle<'a>,
  /// How to draw this buffer. Ex: gl::LINES, gl::TRIANGLES, etc.
  pub mode: GLenum,
  /// length in `T`s.
  pub length: uint,
}

impl<'a, T> GLArray<'a, T> {
  /// Creates a new array of objects on the GPU.
  /// capacity is provided in units of size slice_span.
  pub fn new(
    gl: &'a GLContextExistence,
    _gl_context: &mut GLContext,
    shader_program: Rc<RefCell<Shader>>,
    attribs: &[VertexAttribData],
    mode: DrawMode,
    buffer: GLBuffer<'a, T>,
  ) -> GLArray<'a, T> {
    let handle = ArrayHandle::new(gl);

    unsafe {
      gl::BindVertexArray(handle.gl_id);
    }

    let mut offset = 0;
    let attrib_span = {
      let mut attrib_span = 0;
      for attrib in attribs.iter() {
        attrib_span += attrib.size * attrib.unit.size();
      }
      attrib_span
    };
    for attrib in attribs.iter() {
      let shader_attrib =
        glGetAttribLocation(
          shader_program.borrow().handle.gl_id,
          attrib.name
        );
      assert!(shader_attrib != -1, "shader attribute \"{}\" not found", attrib.name);
      let shader_attrib = shader_attrib as GLuint;

      unsafe {
        gl::EnableVertexAttribArray(shader_attrib);

        if attrib.unit.is_integral() {
          gl::VertexAttribIPointer(
            shader_attrib,
            attrib.size as i32,
            attrib.unit.gl_enum(),
            attrib_span as i32,
            ptr::null().offset(offset),
          );
        } else {
          gl::VertexAttribPointer(
            shader_attrib,
            attrib.size as i32,
            attrib.unit.gl_enum(),
            gl::FALSE as GLboolean,
            attrib_span as i32,
            ptr::null().offset(offset),
          );
        }
      }
      offset += (attrib.size * attrib.unit.size()) as int;
    }

    match unsafe { gl::GetError() } {
      gl::NO_ERROR => {},
      err => panic!("OpenGL error 0x{:x}", err),
    }

    assert_eq!(attrib_span, mem::size_of::<T>());

    GLArray {
      buffer: buffer,
      handle: handle,
      mode: mode.to_enum(),
      length: 0,
    }
  }

  pub fn push(&mut self, gl: &mut GLContext, vs: &[T]) {
    self.buffer.push(gl, vs);
    self.length += vs.len();
  }

  pub fn swap_remove(&mut self, gl: &mut GLContext, idx: uint, count: uint) {
    self.buffer.swap_remove(gl, idx, count);
    self.length -= count;
  }

  /// Draws all the queued triangles to the screen.
  pub fn draw(&self, gl: &mut GLContext) {
    self.draw_slice(gl, 0, self.length);
  }

  /// Draw some subset of the triangle array.
  pub fn draw_slice(&self, _gl: &mut GLContext, start: uint, len: uint) {
    assert!(start + len <= self.length);

    unsafe {
      gl::BindVertexArray(self.handle.gl_id);
      gl::BindBuffer(gl::ARRAY_BUFFER, self.buffer.byte_buffer.handle.gl_id);

      gl::DrawArrays(self.mode, start as i32, len as i32);
    }
  }
}
<commit_msg>remove unnecessary Bind* calls<commit_after>use gl;
use gl::types::*;
use gl_context::{GLContext, GLContextExistence};
use shader::*;
use std::cell::RefCell;
use std::kinds::marker::ContravariantLifetime;
use std::mem;
use std::ptr;
use std::rc::Rc;

/// Gets the id number for a given input of the shader program.
#[allow(non_snake_case)]
pub fn glGetAttribLocation(shader_program: GLuint, name: &str) -> GLint {
  name.with_c_str(|ptr| unsafe { gl::GetAttribLocation(shader_program, ptr) })
}

pub struct BufferHandle<'a> {
  pub gl_id: GLuint,
  pub lifetime: ContravariantLifetime<'a>,
}

impl<'a> BufferHandle<'a> {
  pub fn new(_gl: &'a GLContextExistence) -> BufferHandle<'a> {
    let mut gl_id = 0;

    unsafe {
      gl::GenBuffers(1, &mut gl_id);
    }

    assert!(gl_id != 0);

    BufferHandle {
      gl_id: gl_id,
      lifetime: ContravariantLifetime,
    }
  }
}

#[unsafe_destructor]
impl<'a> Drop for BufferHandle<'a> {
  fn drop(&mut self) {
    unsafe {
      gl::DeleteBuffers(1, &self.gl_id);
    }
  }
}

/// Fixed-size VRAM buffer for individual bytes.
pub struct GLByteBuffer<'a> {
  pub handle: BufferHandle<'a>,
  /// number of bytes in the buffer.
  pub length: uint,
  /// maximum number of bytes in the buffer.
  pub capacity: uint,
}

impl<'a> GLByteBuffer<'a> {
  /// Creates a new array of objects on the GPU.
  /// capacity is provided in units of size slice_span.
  pub fn new(
    gl: &'a GLContextExistence,
    gl_context: &mut GLContext,
    capacity: uint,
  ) -> GLByteBuffer<'a> {
    let handle = BufferHandle::new(gl);

    unsafe {
      gl::BindBuffer(gl::ARRAY_BUFFER, handle.gl_id);

      gl::BufferData(
        gl::ARRAY_BUFFER,
        capacity as GLsizeiptr,
        ptr::null(),
        gl::DYNAMIC_DRAW,
      );
    }

    match gl_context.get_error() {
      gl::NO_ERROR => {},
      gl::OUT_OF_MEMORY => panic!("Out of VRAM"),
      err => panic!("OpenGL error 0x{:x}", err),
    }

    GLByteBuffer {
      handle: handle,
      length: 0,
      capacity: capacity,
    }
  }

  pub fn bind(&self, _: &mut GLContext) {
    unsafe {
      gl::BindBuffer(gl::ARRAY_BUFFER, self.handle.gl_id);
    }
  }

  /// Add more data into this buffer.
  pub unsafe fn push(&mut self, gl: &mut GLContext, vs: *const u8, count: uint) {
    assert!(
      self.length + count <= self.capacity,
      "GLByteBuffer::push {} into a {}/{} full GLByteBuffer",
      count,
      self.length,
      self.capacity
    );

    self.update_inner(gl, self.length, vs, count);
    self.length += count;
  }

  pub fn swap_remove(&mut self, _gl: &mut GLContext, i: uint, count: uint) {
    assert!(count <= self.length);
    self.length -= count;
    assert!(i <= self.length);

    // In the `i == self.length` case, we don't bother with the swap;
    // decreasing `self.length` is enough.

    if i < self.length {
      assert!(
        i <= self.length - count,
        "GLByteBuffer::swap_remove would cause copy in overlapping regions"
      );

      unsafe {
        gl::CopyBufferSubData(
          gl::ARRAY_BUFFER,
          gl::ARRAY_BUFFER,
          self.length as i64,
          i as i64,
          count as i64,
        );
      }
    }
  }

  pub unsafe fn update(&self, gl: &mut GLContext, idx: uint, vs: *const u8, count: uint) {
    assert!(idx + count <= self.length);
    self.update_inner(gl, idx, vs, count);
  }

  unsafe fn update_inner(
    &self,
    _gl: &mut GLContext,
    idx: uint,
    vs: *const u8,
    count: uint,
  ) {
    assert!(idx + count <= self.capacity);

    gl::BufferSubData(
      gl::ARRAY_BUFFER,
      idx as i64,
      count as i64,
      mem::transmute(vs)
    );
  }
}

/// Fixed-size typed VRAM buffer, optimized for bulk inserts.
pub struct GLBuffer<'a, T> {
  pub byte_buffer: GLByteBuffer<'a>,
}

impl<'a, T> GLBuffer<'a, T> {
  pub fn new(
    gl: &'a GLContextExistence,
    gl_context: &mut GLContext,
    capacity: uint,
  ) -> GLBuffer<'a, T> {
    GLBuffer {
      byte_buffer: GLByteBuffer::new(gl, gl_context, capacity * mem::size_of::<T>()),
    }
  }

  pub fn push(&mut self, gl: &mut GLContext, vs: &[T]) {
    unsafe {
      self.byte_buffer.push(
        gl,
        mem::transmute(vs.as_ptr()),
        mem::size_of::<T>() * vs.len()
      );
    }
  }

  pub fn update(&mut self, gl: &mut GLContext, idx: uint, vs: &[T]) {
    unsafe {
      self.byte_buffer.update(
        gl,
        mem::size_of::<T>() * idx,
        mem::transmute(vs.as_ptr()),
        mem::size_of::<T>() * vs.len(),
      );
    }
  }

  pub fn swap_remove(&mut self, gl: &mut GLContext, idx: uint, count: uint) {
    self.byte_buffer.swap_remove(
      gl,
      mem::size_of::<T>() * idx,
      mem::size_of::<T>() * count,
    );
  }
}

#[deriving(Show)]
#[deriving(Copy, Clone)]
pub enum DrawMode {
  Lines,
  Triangles,
  Points,
}

impl DrawMode {
  fn to_enum(&self) -> GLenum {
    match *self {
      DrawMode::Lines     => gl::LINES,
      DrawMode::Triangles => gl::TRIANGLES,
      DrawMode::Points    => gl::POINTS,
    }
  }
}

#[deriving(Show)]
#[deriving(Copy, Clone)]
pub enum GLType {
  Float,
  UInt,
  Int,
}

impl GLType {
  pub fn size(&self) -> uint {
    match *self {
      GLType::Float => mem::size_of::<GLfloat>(),
      GLType::UInt  => mem::size_of::<GLuint>(),
      GLType::Int   => mem::size_of::<GLint>(),
    }
  }

  pub fn gl_enum(&self) -> GLenum {
    match *self {
      GLType::Float => gl::FLOAT,
      GLType::UInt  => gl::UNSIGNED_INT,
      GLType::Int   => gl::INT,
    }
  }

  pub fn is_integral(&self) -> bool {
    match *self {
      GLType::Float => false,
      GLType::UInt  => true,
      GLType::Int   => true,
    }
  }
}

#[deriving(Show)]
/// Specifies how to pass data from OpenGL to the vertex shaders.
pub struct VertexAttribData<'a> {
  /// Cooresponds to the shader's `input variable`.
  pub name: &'a str,
  /// The size of this attribute, in the provided units.
  pub size: uint,
  pub unit: GLType,
}

pub struct ArrayHandle<'a> {
  pub lifetime: ContravariantLifetime<'a>,
  pub gl_id: GLuint,
}

impl<'a> ArrayHandle<'a> {
  pub fn new(_gl: &'a GLContextExistence) -> ArrayHandle<'a> {
    let mut gl_id = 0;
    unsafe {
      gl::GenVertexArrays(1, &mut gl_id);
    }

    ArrayHandle {
      gl_id: gl_id,
      lifetime: ContravariantLifetime,
    }
  }
}

#[unsafe_destructor]
impl<'a> Drop for ArrayHandle<'a> {
  fn drop(&mut self) {
    unsafe {
      gl::DeleteVertexArrays(1, &self.gl_id);
    }
  }
}

/// A fixed-capacity array of bytes passed to OpenGL.
pub struct GLArray<'a, T> {
  pub buffer: GLBuffer<'a, T>,
  pub handle: ArrayHandle<'a>,
  /// How to draw this buffer. Ex: gl::LINES, gl::TRIANGLES, etc.
  pub mode: GLenum,
  /// length in `T`s.
  pub length: uint,
}

impl<'a, T> GLArray<'a, T> {
  /// Creates a new array of objects on the GPU.
  /// capacity is provided in units of size slice_span.
  pub fn new(
    gl: &'a GLContextExistence,
    _gl_context: &mut GLContext,
    shader_program: Rc<RefCell<Shader>>,
    attribs: &[VertexAttribData],
    mode: DrawMode,
    buffer: GLBuffer<'a, T>,
  ) -> GLArray<'a, T> {
    let handle = ArrayHandle::new(gl);

    unsafe {
      gl::BindVertexArray(handle.gl_id);
    }

    let mut offset = 0;
    let attrib_span = {
      let mut attrib_span = 0;
      for attrib in attribs.iter() {
        attrib_span += attrib.size * attrib.unit.size();
      }
      attrib_span
    };
    for attrib in attribs.iter() {
      let shader_attrib =
        glGetAttribLocation(
          shader_program.borrow().handle.gl_id,
          attrib.name
        );
      assert!(shader_attrib != -1, "shader attribute \"{}\" not found", attrib.name);
      let shader_attrib = shader_attrib as GLuint;

      unsafe {
        gl::EnableVertexAttribArray(shader_attrib);

        if attrib.unit.is_integral() {
          gl::VertexAttribIPointer(
            shader_attrib,
            attrib.size as i32,
            attrib.unit.gl_enum(),
            attrib_span as i32,
            ptr::null().offset(offset),
          );
        } else {
          gl::VertexAttribPointer(
            shader_attrib,
            attrib.size as i32,
            attrib.unit.gl_enum(),
            gl::FALSE as GLboolean,
            attrib_span as i32,
            ptr::null().offset(offset),
          );
        }
      }
      offset += (attrib.size * attrib.unit.size()) as int;
    }

    match unsafe { gl::GetError() } {
      gl::NO_ERROR => {},
      err => panic!("OpenGL error 0x{:x}", err),
    }

    assert_eq!(attrib_span, mem::size_of::<T>());

    GLArray {
      buffer: buffer,
      handle: handle,
      mode: mode.to_enum(),
      length: 0,
    }
  }

  pub fn bind(&self, _: &mut GLContext) {
    unsafe {
      gl::BindVertexArray(self.handle.gl_id);
      gl::BindBuffer(gl::ARRAY_BUFFER, self.buffer.byte_buffer.handle.gl_id);
    }
  }

  pub fn push(&mut self, gl: &mut GLContext, vs: &[T]) {
    self.buffer.push(gl, vs);
    self.length += vs.len();
  }

  pub fn swap_remove(&mut self, gl: &mut GLContext, idx: uint, count: uint) {
    self.buffer.swap_remove(gl, idx, count);
    self.length -= count;
  }

  /// Draws all the queued triangles to the screen.
  pub fn draw(&self, gl: &mut GLContext) {
    self.draw_slice(gl, 0, self.length);
  }

  /// Draw some subset of the triangle array.
  pub fn draw_slice(&self, _gl: &mut GLContext, start: uint, len: uint) {
    assert!(start + len <= self.length);

    unsafe {
      gl::DrawArrays(self.mode, start as i32, len as i32);
    }
  }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::collections::HashMap;

use xcb;
use xcb_util::{ewmh, icccm};
use xcb_util::keysyms::KeySymbols;

use debug;
use keys::{KeyCombo, KeyHandlers, ModKey};
use groups::Group;
use stack::Stack;

pub use self::ewmh::StrutPartial;

/// A handle to an X Window.
#[derive(Debug, PartialEq)]
pub struct WindowId(xcb::Window);

impl WindowId {
    fn to_x(&self) -> xcb::Window {
        self.0
    }
}

impl fmt::Display for WindowId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum WindowType {
    Desktop,
    Dock,
    Toolbar,
    Menu,
    Utility,
    Splash,
    Dialog,
    DropdownMenu,
    PopupMenu,
    Tooltip,
    Notification,
    Combo,
    Dnd,
    Normal,
}

macro_rules! atoms {
    ( $( $name:ident ),+ ) => {
        #[allow(non_snake_case)]
        struct InternedAtoms {
            $(
                pub $name: xcb::Atom
            ),*
        }

        impl InternedAtoms {
            pub fn new(conn: &xcb::Connection) -> Result<InternedAtoms, xcb::GenericError> {
                Ok(InternedAtoms {
                    $(
                        $name: Connection::intern_atom(conn, stringify!($atom))?
                    ),*
                })
            }
        }
    };
    // Allow trailing comma:
    ( $( $name:ident ),+ , ) => (atoms!($( $name ),+);)
}

atoms!(
    WM_DELETE_WINDOW,
    WM_PROTOCOLS,
    _NET_NUMBER_OF_DESKTOPS,
    _NET_CURRENT_DESKTOP,
    _NET_DESKTOP_NAMES,
);

pub struct Connection {
    conn: ewmh::Connection,
    root: WindowId,
    screen_idx: i32,
    atoms: InternedAtoms,
    window_type_lookup: HashMap<xcb::Atom, WindowType>,
}

impl Connection {
    /// Opens a connection to the X server, returning a new Connection object.
    pub fn connect() -> Result<Connection, String> {
        let (conn, screen_idx) = xcb::Connection::connect(None).unwrap();
        let conn = ewmh::Connection::connect(conn).map_err(|_| ()).unwrap();
        let root = conn.get_setup()
            .roots()
            .nth(screen_idx as usize)
            .ok_or("Invalid screen")?
            .root();

        let atoms = InternedAtoms::new(&conn).or(Err("Failed to intern atoms"))?;

        let mut lookup = HashMap::new();
        lookup.insert(conn.WM_WINDOW_TYPE_DESKTOP(), WindowType::Desktop);
        lookup.insert(conn.WM_WINDOW_TYPE_DOCK(), WindowType::Dock);
        lookup.insert(conn.WM_WINDOW_TYPE_TOOLBAR(), WindowType::Toolbar);
        lookup.insert(conn.WM_WINDOW_TYPE_MENU(), WindowType::Menu);
        lookup.insert(conn.WM_WINDOW_TYPE_UTILITY(), WindowType::Utility);
        lookup.insert(conn.WM_WINDOW_TYPE_SPLASH(), WindowType::Splash);
        lookup.insert(conn.WM_WINDOW_TYPE_DIALOG(), WindowType::Dialog);
        lookup.insert(
            conn.WM_WINDOW_TYPE_DROPDOWN_MENU(),
            WindowType::DropdownMenu,
        );
        lookup.insert(conn.WM_WINDOW_TYPE_POPUP_MENU(), WindowType::PopupMenu);
        lookup.insert(conn.WM_WINDOW_TYPE_TOOLTIP(), WindowType::Tooltip);
        lookup.insert(conn.WM_WINDOW_TYPE_NOTIFICATION(), WindowType::Notification);
        lookup.insert(conn.WM_WINDOW_TYPE_COMBO(), WindowType::Combo);
        lookup.insert(conn.WM_WINDOW_TYPE_DND(), WindowType::Dnd);
        lookup.insert(conn.WM_WINDOW_TYPE_NORMAL(), WindowType::Normal);

        Ok(Connection {
            conn,
            root: WindowId(root),
            screen_idx,
            atoms,
            window_type_lookup: lookup,
        })
    }

    /// Returns the Atom identifier associated with the atom_name str.
    fn intern_atom(
        conn: &xcb::Connection,
        atom_name: &str,
    ) -> Result<xcb::Atom, xcb::GenericError> {
        Ok(xcb::intern_atom(conn, false, atom_name).get_reply()?.atom())
    }

    fn flush(&self) {
        self.conn.flush();
    }

    /// Installs the Connection as a window manager, by registers for
    /// SubstructureNotify and SubstructureRedirect events on the root window.
    /// If there is already a window manager on the display, then this will
    /// fail.
    pub fn install_as_wm(&self, key_handlers: &KeyHandlers) -> Result<(), String> {
        let values = [
            (
                xcb::CW_EVENT_MASK,
                xcb::EVENT_MASK_SUBSTRUCTURE_NOTIFY | xcb::EVENT_MASK_SUBSTRUCTURE_REDIRECT,
            ),
        ];
        xcb::change_window_attributes_checked(&self.conn, self.root.to_x(), &values)
            .request_check()
            .or(Err(
                "Could not register SUBSTRUCTURE_NOTIFY/REDIRECT".to_owned(),
            ))?;

        self.enable_window_key_events(&self.root, key_handlers);

        Ok(())
    }

    /// Returns the ID of the root window.
    pub fn root_window_id(&self) -> &WindowId {
        &self.root
    }

    pub fn update_ewmh_desktops(&self, groups: &Stack<Group>) {
        let group_names = groups.iter().map(|g| g.name());
        ewmh::set_desktop_names(&self.conn, self.screen_idx, group_names);
        ewmh::set_number_of_desktops(&self.conn, self.screen_idx, groups.len() as u32);

        // Matching the current group on name isn't perfect, but it's good enough for
        // EWMH.
        let focused_idx = groups.focused().and_then(|focused| {
            groups.iter().position(|g| g.name() == focused.name())
        });
        match focused_idx {
            Some(idx) => {
                ewmh::set_current_desktop(&self.conn, self.screen_idx, idx as u32);
            }
            None => {
                error!("Invariant: failed to get active group index");
            }
        };
    }

    pub fn top_level_windows(&self) -> Result<Vec<WindowId>, xcb::GenericError> {
        let windows = xcb::query_tree(&self.conn, self.root.to_x())
            .get_reply()?
            .children()
            .iter()
            .map(|w| WindowId(*w))
            .collect();
        Ok(windows)
    }

    /// Queries the WM_PROTOCOLS property of a window, returning a list of the
    /// protocols that it supports.
    // TODO: Have this return a list of atoms, rather than a list of strings.
    // (Perhaps we should
    // have a separate function to convert to a list of strings for debugging?)
    fn get_wm_protocols(&self, window_id: &WindowId) -> Result<Vec<xcb::Atom>, xcb::GenericError> {
        let reply = icccm::get_wm_protocols(&self.conn, window_id.to_x(), self.atoms.WM_PROTOCOLS)
            .get_reply()?;
        Ok(reply.atoms().to_vec())
    }

    pub fn get_window_types(&self, window_id: &WindowId) -> Vec<WindowType> {
        // Filter out any types we don't understand, as that's what the EWMH
        // spec suggests we should do. Don't error if _NET_WM_WINDOW_TYPE
        // is not set - lots of applications don't bother.
        ewmh::get_wm_window_type(&self.conn, window_id.to_x())
            .get_reply()
            .map(|reply| {
                reply
                    .atoms()
                    .iter()
                    .filter_map(|a| self.window_type_lookup.get(a).cloned())
                    .collect()
            })
            .unwrap_or(Vec::new())
    }

    pub fn get_strut_partial(&self, window_id: &WindowId) -> Option<StrutPartial> {
        ewmh::get_wm_strut_partial(&self.conn, window_id.to_x())
            .get_reply()
            .ok()
    }

    /// Closes a window.
    ///
    /// The window will be closed gracefully using the ICCCM WM_DELETE_WINDOW
    /// protocol if it is supported.
    pub fn close_window(&self, window_id: &WindowId) {
        let protocols = self.get_wm_protocols(window_id).unwrap();
        let has_wm_delete_window = protocols.contains(&self.atoms.WM_DELETE_WINDOW);

        // TODO: Use XDestroyWindow to forcefully close windows that do not support
        // WM_DELETE_WINDOW.
        if !has_wm_delete_window {
            panic!("Not implemented: closing windows that don't expose WM_DELETE_WINDOW");
        }

        let data = xcb::ClientMessageData::from_data32(
            [self.atoms.WM_DELETE_WINDOW, xcb::CURRENT_TIME, 0, 0, 0],
        );
        let event =
            xcb::ClientMessageEvent::new(32, window_id.to_x(), self.atoms.WM_PROTOCOLS, data);
        xcb::send_event(
            &self.conn,
            false,
            window_id.to_x(),
            xcb::EVENT_MASK_NO_EVENT,
            &event,
        );
    }

    /// Sets the window's position and size.
    pub fn configure_window(&self, window_id: &WindowId, x: u32, y: u32, width: u32, height: u32) {
        let values = [
            (xcb::CONFIG_WINDOW_X as u16, x),
            (xcb::CONFIG_WINDOW_Y as u16, y),
            (xcb::CONFIG_WINDOW_WIDTH as u16, width),
            (xcb::CONFIG_WINDOW_HEIGHT as u16, height),
        ];
        xcb::configure_window(&self.conn, window_id.to_x(), &values);
    }

    /// Get's the window's width and height.
    pub fn get_window_geometry(&self, window_id: &WindowId) -> (u32, u32) {
        let reply = xcb::get_geometry(&self.conn, window_id.to_x())
            .get_reply()
            .unwrap();
        // Cast as everywhere else uses u32.
        (reply.width() as u32, reply.height() as u32)
    }

    /// Map a window.
    pub fn map_window(&self, window_id: &WindowId) {
        xcb::map_window(&self.conn, window_id.to_x());
    }

    /// Unmap a window.
    pub fn unmap_window(&self, window_id: &WindowId) {
        xcb::unmap_window(&self.conn, window_id.to_x());
    }

    /// Registers for key events.
    pub fn enable_window_key_events(&self, window_id: &WindowId, key_handlers: &KeyHandlers) {
        let key_symbols = KeySymbols::new(&self.conn).expect("Failed to create KeySymbols");
        for key in key_handlers.key_combos() {
            let keycode = key_symbols.get_keycode(key.keysym);
            xcb::grab_key(
                &self.conn,
                false,
                window_id.to_x(),
                key.mod_mask as u16,
                keycode,
                xcb::GRAB_MODE_ASYNC as u8,
                xcb::GRAB_MODE_ASYNC as u8,
            );
        }
    }

    pub fn enable_window_focus_tracking(&self, window_id: &WindowId) {
        let values = [(xcb::CW_EVENT_MASK, xcb::EVENT_MASK_ENTER_WINDOW)];
        xcb::change_window_attributes(&self.conn, window_id.to_x(), &values);
    }

    pub fn disable_window_focus_tracking(&self, window_id: &WindowId) {
        let values = [(xcb::CW_EVENT_MASK, xcb::EVENT_MASK_NO_EVENT)];
        xcb::change_window_attributes(&self.conn, window_id.to_x(), &values);
    }

    pub fn focus_window(&self, window_id: &WindowId) {
        xcb::set_input_focus(
            &self.conn,
            xcb::INPUT_FOCUS_POINTER_ROOT as u8,
            window_id.to_x(),
            xcb::CURRENT_TIME,
        );
        ewmh::set_active_window(&self.conn, self.screen_idx, window_id.to_x());
    }

    pub fn get_event_loop(&self) -> EventLoop {
        EventLoop { connection: self }
    }
}

/// Events received from the `EventLoop`.
pub enum Event {
    MapRequest(WindowId),
    DestroyNotify(WindowId),
    KeyPress(KeyCombo),
    EnterNotify(WindowId),
}

/// An iterator that yields events from the X event loop.
///
/// Use `Connection::get_event_loop()` to get one.
pub struct EventLoop<'a> {
    connection: &'a Connection,
}

impl<'a> Iterator for EventLoop<'a> {
    type Item = Event;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            // Flush any pending operations that came out of the event we (might
            // have) just yielded.
            self.connection.flush();

            let event = self.connection.conn.wait_for_event().expect(
                "wait_for_event() returned None: IO error?",
            );

            let propagate = match event.response_type() {
                xcb::CONFIGURE_REQUEST => self.on_configure_request(xcb::cast_event(&event)),
                xcb::MAP_REQUEST => self.on_map_request(xcb::cast_event(&event)),
                xcb::DESTROY_NOTIFY => self.on_destroy_notify(xcb::cast_event(&event)),
                xcb::KEY_PRESS => self.on_key_press(xcb::cast_event(&event)),
                xcb::ENTER_NOTIFY => self.on_enter_notify(xcb::cast_event(&event)),
                _ => {
                    debug!("Unhandled event: {}", debug::xcb_event_to_str(&event));
                    None
                }
            };

            if let Some(propagate_event) = propagate {
                return Some(propagate_event);
            }
        }
    }
}

impl<'a> EventLoop<'a> {
    fn on_configure_request(&self, event: &xcb::ConfigureRequestEvent) -> Option<Event> {
        // This request is not interesting for us: grant it unchanged.
        // Build a request with all attributes set, then filter out to only include
        // those from the original request.
        let values = vec![
            (xcb::CONFIG_WINDOW_X as u16, event.x() as u32),
            (xcb::CONFIG_WINDOW_Y as u16, event.y() as u32),
            (xcb::CONFIG_WINDOW_WIDTH as u16, event.width() as u32),
            (xcb::CONFIG_WINDOW_HEIGHT as u16, event.height() as u32),
            (
                xcb::CONFIG_WINDOW_BORDER_WIDTH as u16,
                event.border_width() as u32
            ),
            (xcb::CONFIG_WINDOW_SIBLING as u16, event.sibling() as u32),
            (
                xcb::CONFIG_WINDOW_STACK_MODE as u16,
                event.stack_mode() as u32
            ),
        ];
        let filtered_values: Vec<_> = values
            .into_iter()
            .filter(|&(mask, _)| mask & event.value_mask() != 0)
            .collect();
        xcb::configure_window(&self.connection.conn, event.window(), &filtered_values);

        // There's no value in propogating this event.
        None
    }

    fn on_map_request(&self, event: &xcb::MapRequestEvent) -> Option<Event> {
        Some(Event::MapRequest(WindowId(event.window())))
    }

    fn on_destroy_notify(&self, event: &xcb::DestroyNotifyEvent) -> Option<Event> {
        Some(Event::DestroyNotify(WindowId(event.window())))
    }

    fn on_key_press(&self, event: &xcb::KeyPressEvent) -> Option<Event> {
        let key_symbols =
            KeySymbols::new(&self.connection.conn).expect("Failed to create KeySymbols");
        let keysym = key_symbols.key_press_lookup_keysym(event, 0);
        let mod_mask = event.state() as u32 & ModKey::mask_all();
        let key = KeyCombo { mod_mask, keysym };
        Some(Event::KeyPress(key))
    }

    fn on_enter_notify(&self, event: &xcb::EnterNotifyEvent) -> Option<Event> {
        Some(Event::EnterNotify(WindowId(event.event())))
    }
}
<commit_msg>Support non-WM_DELETE window closing.<commit_after>use std::fmt;
use std::collections::HashMap;

use xcb;
use xcb_util::{ewmh, icccm};
use xcb_util::keysyms::KeySymbols;

use debug;
use keys::{KeyCombo, KeyHandlers, ModKey};
use groups::Group;
use stack::Stack;

pub use self::ewmh::StrutPartial;

/// A handle to an X Window.
#[derive(Debug, PartialEq)]
pub struct WindowId(xcb::Window);

impl WindowId {
    fn to_x(&self) -> xcb::Window {
        self.0
    }
}

impl fmt::Display for WindowId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum WindowType {
    Desktop,
    Dock,
    Toolbar,
    Menu,
    Utility,
    Splash,
    Dialog,
    DropdownMenu,
    PopupMenu,
    Tooltip,
    Notification,
    Combo,
    Dnd,
    Normal,
}

macro_rules! atoms {
    ( $( $name:ident ),+ ) => {
        #[allow(non_snake_case)]
        struct InternedAtoms {
            $(
                pub $name: xcb::Atom
            ),*
        }

        impl InternedAtoms {
            pub fn new(conn: &xcb::Connection) -> Result<InternedAtoms, xcb::GenericError> {
                Ok(InternedAtoms {
                    $(
                        $name: Connection::intern_atom(conn, stringify!($atom))?
                    ),*
                })
            }
        }
    };
    // Allow trailing comma:
    ( $( $name:ident ),+ , ) => (atoms!($( $name ),+);)
}

atoms!(
    WM_DELETE_WINDOW,
    WM_PROTOCOLS,
    _NET_NUMBER_OF_DESKTOPS,
    _NET_CURRENT_DESKTOP,
    _NET_DESKTOP_NAMES,
);

pub struct Connection {
    conn: ewmh::Connection,
    root: WindowId,
    screen_idx: i32,
    atoms: InternedAtoms,
    window_type_lookup: HashMap<xcb::Atom, WindowType>,
}

impl Connection {
    /// Opens a connection to the X server, returning a new Connection object.
    pub fn connect() -> Result<Connection, String> {
        let (conn, screen_idx) = xcb::Connection::connect(None).unwrap();
        let conn = ewmh::Connection::connect(conn).map_err(|_| ()).unwrap();
        let root = conn.get_setup()
            .roots()
            .nth(screen_idx as usize)
            .ok_or("Invalid screen")?
            .root();

        let atoms = InternedAtoms::new(&conn).or(Err("Failed to intern atoms"))?;

        let mut lookup = HashMap::new();
        lookup.insert(conn.WM_WINDOW_TYPE_DESKTOP(), WindowType::Desktop);
        lookup.insert(conn.WM_WINDOW_TYPE_DOCK(), WindowType::Dock);
        lookup.insert(conn.WM_WINDOW_TYPE_TOOLBAR(), WindowType::Toolbar);
        lookup.insert(conn.WM_WINDOW_TYPE_MENU(), WindowType::Menu);
        lookup.insert(conn.WM_WINDOW_TYPE_UTILITY(), WindowType::Utility);
        lookup.insert(conn.WM_WINDOW_TYPE_SPLASH(), WindowType::Splash);
        lookup.insert(conn.WM_WINDOW_TYPE_DIALOG(), WindowType::Dialog);
        lookup.insert(
            conn.WM_WINDOW_TYPE_DROPDOWN_MENU(),
            WindowType::DropdownMenu,
        );
        lookup.insert(conn.WM_WINDOW_TYPE_POPUP_MENU(), WindowType::PopupMenu);
        lookup.insert(conn.WM_WINDOW_TYPE_TOOLTIP(), WindowType::Tooltip);
        lookup.insert(conn.WM_WINDOW_TYPE_NOTIFICATION(), WindowType::Notification);
        lookup.insert(conn.WM_WINDOW_TYPE_COMBO(), WindowType::Combo);
        lookup.insert(conn.WM_WINDOW_TYPE_DND(), WindowType::Dnd);
        lookup.insert(conn.WM_WINDOW_TYPE_NORMAL(), WindowType::Normal);

        Ok(Connection {
            conn,
            root: WindowId(root),
            screen_idx,
            atoms,
            window_type_lookup: lookup,
        })
    }

    /// Returns the Atom identifier associated with the atom_name str.
    fn intern_atom(
        conn: &xcb::Connection,
        atom_name: &str,
    ) -> Result<xcb::Atom, xcb::GenericError> {
        Ok(xcb::intern_atom(conn, false, atom_name).get_reply()?.atom())
    }

    fn flush(&self) {
        self.conn.flush();
    }

    /// Installs the Connection as a window manager, by registers for
    /// SubstructureNotify and SubstructureRedirect events on the root window.
    /// If there is already a window manager on the display, then this will
    /// fail.
    pub fn install_as_wm(&self, key_handlers: &KeyHandlers) -> Result<(), String> {
        let values = [
            (
                xcb::CW_EVENT_MASK,
                xcb::EVENT_MASK_SUBSTRUCTURE_NOTIFY | xcb::EVENT_MASK_SUBSTRUCTURE_REDIRECT,
            ),
        ];
        xcb::change_window_attributes_checked(&self.conn, self.root.to_x(), &values)
            .request_check()
            .or(Err(
                "Could not register SUBSTRUCTURE_NOTIFY/REDIRECT".to_owned(),
            ))?;

        self.enable_window_key_events(&self.root, key_handlers);

        Ok(())
    }

    /// Returns the ID of the root window.
    pub fn root_window_id(&self) -> &WindowId {
        &self.root
    }

    pub fn update_ewmh_desktops(&self, groups: &Stack<Group>) {
        let group_names = groups.iter().map(|g| g.name());
        ewmh::set_desktop_names(&self.conn, self.screen_idx, group_names);
        ewmh::set_number_of_desktops(&self.conn, self.screen_idx, groups.len() as u32);

        // Matching the current group on name isn't perfect, but it's good enough for
        // EWMH.
        let focused_idx = groups.focused().and_then(|focused| {
            groups.iter().position(|g| g.name() == focused.name())
        });
        match focused_idx {
            Some(idx) => {
                ewmh::set_current_desktop(&self.conn, self.screen_idx, idx as u32);
            }
            None => {
                error!("Invariant: failed to get active group index");
            }
        };
    }

    pub fn top_level_windows(&self) -> Result<Vec<WindowId>, xcb::GenericError> {
        let windows = xcb::query_tree(&self.conn, self.root.to_x())
            .get_reply()?
            .children()
            .iter()
            .map(|w| WindowId(*w))
            .collect();
        Ok(windows)
    }

    /// Queries the WM_PROTOCOLS property of a window, returning a list of the
    /// protocols that it supports.
    // TODO: Have this return a list of atoms, rather than a list of strings.
    // (Perhaps we should
    // have a separate function to convert to a list of strings for debugging?)
    fn get_wm_protocols(&self, window_id: &WindowId) -> Result<Vec<xcb::Atom>, xcb::GenericError> {
        let reply = icccm::get_wm_protocols(&self.conn, window_id.to_x(), self.atoms.WM_PROTOCOLS)
            .get_reply()?;
        Ok(reply.atoms().to_vec())
    }

    pub fn get_window_types(&self, window_id: &WindowId) -> Vec<WindowType> {
        // Filter out any types we don't understand, as that's what the EWMH
        // spec suggests we should do. Don't error if _NET_WM_WINDOW_TYPE
        // is not set - lots of applications don't bother.
        ewmh::get_wm_window_type(&self.conn, window_id.to_x())
            .get_reply()
            .map(|reply| {
                reply
                    .atoms()
                    .iter()
                    .filter_map(|a| self.window_type_lookup.get(a).cloned())
                    .collect()
            })
            .unwrap_or(Vec::new())
    }

    pub fn get_strut_partial(&self, window_id: &WindowId) -> Option<StrutPartial> {
        ewmh::get_wm_strut_partial(&self.conn, window_id.to_x())
            .get_reply()
            .ok()
    }

    /// Closes a window.
    ///
    /// The window will be closed gracefully using the ICCCM WM_DELETE_WINDOW
    /// protocol if it is supported.
    pub fn close_window(&self, window_id: &WindowId) {
        let protocols = self.get_wm_protocols(window_id).unwrap();
        let has_wm_delete_window = protocols.contains(&self.atoms.WM_DELETE_WINDOW);

        if has_wm_delete_window {
            let data = xcb::ClientMessageData::from_data32(
                [self.atoms.WM_DELETE_WINDOW, xcb::CURRENT_TIME, 0, 0, 0],
            );
            let event =
                xcb::ClientMessageEvent::new(32, window_id.to_x(), self.atoms.WM_PROTOCOLS, data);
            xcb::send_event(
                &self.conn,
                false,
                window_id.to_x(),
                xcb::EVENT_MASK_NO_EVENT,
                &event,
            );
        } else {
            xcb::destroy_window(&self.conn, window_id.to_x());
        }
    }

    /// Sets the window's position and size.
    pub fn configure_window(&self, window_id: &WindowId, x: u32, y: u32, width: u32, height: u32) {
        let values = [
            (xcb::CONFIG_WINDOW_X as u16, x),
            (xcb::CONFIG_WINDOW_Y as u16, y),
            (xcb::CONFIG_WINDOW_WIDTH as u16, width),
            (xcb::CONFIG_WINDOW_HEIGHT as u16, height),
        ];
        xcb::configure_window(&self.conn, window_id.to_x(), &values);
    }

    /// Get's the window's width and height.
    pub fn get_window_geometry(&self, window_id: &WindowId) -> (u32, u32) {
        let reply = xcb::get_geometry(&self.conn, window_id.to_x())
            .get_reply()
            .unwrap();
        // Cast as everywhere else uses u32.
        (reply.width() as u32, reply.height() as u32)
    }

    /// Map a window.
    pub fn map_window(&self, window_id: &WindowId) {
        xcb::map_window(&self.conn, window_id.to_x());
    }

    /// Unmap a window.
    pub fn unmap_window(&self, window_id: &WindowId) {
        xcb::unmap_window(&self.conn, window_id.to_x());
    }

    /// Registers for key events.
    pub fn enable_window_key_events(&self, window_id: &WindowId, key_handlers: &KeyHandlers) {
        let key_symbols = KeySymbols::new(&self.conn).expect("Failed to create KeySymbols");
        for key in key_handlers.key_combos() {
            let keycode = key_symbols.get_keycode(key.keysym);
            xcb::grab_key(
                &self.conn,
                false,
                window_id.to_x(),
                key.mod_mask as u16,
                keycode,
                xcb::GRAB_MODE_ASYNC as u8,
                xcb::GRAB_MODE_ASYNC as u8,
            );
        }
    }

    pub fn enable_window_focus_tracking(&self, window_id: &WindowId) {
        let values = [(xcb::CW_EVENT_MASK, xcb::EVENT_MASK_ENTER_WINDOW)];
        xcb::change_window_attributes(&self.conn, window_id.to_x(), &values);
    }

    pub fn disable_window_focus_tracking(&self, window_id: &WindowId) {
        let values = [(xcb::CW_EVENT_MASK, xcb::EVENT_MASK_NO_EVENT)];
        xcb::change_window_attributes(&self.conn, window_id.to_x(), &values);
    }

    pub fn focus_window(&self, window_id: &WindowId) {
        xcb::set_input_focus(
            &self.conn,
            xcb::INPUT_FOCUS_POINTER_ROOT as u8,
            window_id.to_x(),
            xcb::CURRENT_TIME,
        );
        ewmh::set_active_window(&self.conn, self.screen_idx, window_id.to_x());
    }

    pub fn get_event_loop(&self) -> EventLoop {
        EventLoop { connection: self }
    }
}

/// Events received from the `EventLoop`.
pub enum Event {
    MapRequest(WindowId),
    DestroyNotify(WindowId),
    KeyPress(KeyCombo),
    EnterNotify(WindowId),
}

/// An iterator that yields events from the X event loop.
///
/// Use `Connection::get_event_loop()` to get one.
pub struct EventLoop<'a> {
    connection: &'a Connection,
}

impl<'a> Iterator for EventLoop<'a> {
    type Item = Event;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            // Flush any pending operations that came out of the event we (might
            // have) just yielded.
            self.connection.flush();

            let event = self.connection.conn.wait_for_event().expect(
                "wait_for_event() returned None: IO error?",
            );

            let propagate = match event.response_type() {
                xcb::CONFIGURE_REQUEST => self.on_configure_request(xcb::cast_event(&event)),
                xcb::MAP_REQUEST => self.on_map_request(xcb::cast_event(&event)),
                xcb::DESTROY_NOTIFY => self.on_destroy_notify(xcb::cast_event(&event)),
                xcb::KEY_PRESS => self.on_key_press(xcb::cast_event(&event)),
                xcb::ENTER_NOTIFY => self.on_enter_notify(xcb::cast_event(&event)),
                _ => {
                    debug!("Unhandled event: {}", debug::xcb_event_to_str(&event));
                    None
                }
            };

            if let Some(propagate_event) = propagate {
                return Some(propagate_event);
            }
        }
    }
}

impl<'a> EventLoop<'a> {
    fn on_configure_request(&self, event: &xcb::ConfigureRequestEvent) -> Option<Event> {
        // This request is not interesting for us: grant it unchanged.
        // Build a request with all attributes set, then filter out to only include
        // those from the original request.
        let values = vec![
            (xcb::CONFIG_WINDOW_X as u16, event.x() as u32),
            (xcb::CONFIG_WINDOW_Y as u16, event.y() as u32),
            (xcb::CONFIG_WINDOW_WIDTH as u16, event.width() as u32),
            (xcb::CONFIG_WINDOW_HEIGHT as u16, event.height() as u32),
            (
                xcb::CONFIG_WINDOW_BORDER_WIDTH as u16,
                event.border_width() as u32
            ),
            (xcb::CONFIG_WINDOW_SIBLING as u16, event.sibling() as u32),
            (
                xcb::CONFIG_WINDOW_STACK_MODE as u16,
                event.stack_mode() as u32
            ),
        ];
        let filtered_values: Vec<_> = values
            .into_iter()
            .filter(|&(mask, _)| mask & event.value_mask() != 0)
            .collect();
        xcb::configure_window(&self.connection.conn, event.window(), &filtered_values);

        // There's no value in propogating this event.
        None
    }

    fn on_map_request(&self, event: &xcb::MapRequestEvent) -> Option<Event> {
        Some(Event::MapRequest(WindowId(event.window())))
    }

    fn on_destroy_notify(&self, event: &xcb::DestroyNotifyEvent) -> Option<Event> {
        Some(Event::DestroyNotify(WindowId(event.window())))
    }

    fn on_key_press(&self, event: &xcb::KeyPressEvent) -> Option<Event> {
        let key_symbols =
            KeySymbols::new(&self.connection.conn).expect("Failed to create KeySymbols");
        let keysym = key_symbols.key_press_lookup_keysym(event, 0);
        let mod_mask = event.state() as u32 & ModKey::mask_all();
        let key = KeyCombo { mod_mask, keysym };
        Some(Event::KeyPress(key))
    }

    fn on_enter_notify(&self, event: &xcb::EnterNotifyEvent) -> Option<Event> {
        Some(Event::EnterNotify(WindowId(event.event())))
    }
}
<|endoftext|>


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

#![allow(unused_imports)]

use std::collections::{BTreeSet, BTreeMap, LinkedList};
use std::cmp::{Ordering, Ord, PartialOrd};
use std::fmt::{Display, Formatter};

use symbols;
use num::bigint::{BigInt, ToBigInt, ParseBigIntError};
use ordered_float::OrderedFloat;

/// Value represents one of the allowed values in an EDN string.
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
pub enum Value {
    Nil,
    Boolean(bool),
    Integer(i64),
    BigInteger(BigInt),
    // https://users.rust-lang.org/t/hashmap-key-cant-be-float-number-type-why/7892
    Float(OrderedFloat<f64>),
    Text(String),
    PlainSymbol(symbols::PlainSymbol),
    NamespacedSymbol(symbols::NamespacedSymbol),
    Keyword(symbols::Keyword),
    NamespacedKeyword(symbols::NamespacedKeyword),
    Vector(Vec<Value>),
    List(LinkedList<Value>),
    // We're using BTree{Set, Map} rather than Hash{Set, Map} because the BTree variants
    // implement Hash. The Hash variants don't in order to preserve O(n) hashing
    // time, which is hard given recursive data structures.
    // See https://internals.rust-lang.org/t/implementing-hash-for-hashset-hashmap/3817/1
    Set(BTreeSet<Value>),
    Map(BTreeMap<Value, Value>),
}

use self::Value::*;

impl Display for Value {
    fn fmt(&self, f: &mut Formatter) -> ::std::fmt::Result {
        match *self {
            Keyword(ref v) => v.fmt(f),
            NamespacedKeyword(ref v) => v.fmt(f),
            PlainSymbol(ref v) => v.fmt(f),
            NamespacedSymbol(ref v) => v.fmt(f),

            Integer(v) => write!(f, "{}", v),
            BigInteger(ref v) => write!(f, "{}N", v),
            Float(OrderedFloat(v)) => write!(f, "{}", v),       // TODO: make sure float syntax is correct.
                                                                // TODO: NaN.
            Text(ref v) => write!(f, "{}", v),                  // TODO: EDN escaping.
            Vector(ref v) => {
                try!(write!(f, "["));
                for x in v {
                    try!(write!(f, " {}", x));
                }
                write!(f, " ]")
            }
            _ =>
                write!(f, "{}",
                       match *self {
                           Nil => "null",
                           Boolean(b) => if b { "true" } else { "false" },
                           _ => unimplemented!(),
                       }),
        }
    }
}

#[test]
fn test_value_from() {
    assert_eq!(Value::from(42f64), Value::Float(OrderedFloat::from(42f64)));
    assert_eq!(Value::from_bigint("42").unwrap(), Value::BigInteger(42.to_bigint().unwrap()));
}

#[test]
fn test_print_edn() {
    assert_eq!("[ 1 2 [ 3.1 ] [ ] :five :six/seven eight nine/ten true ]",
               Value::Vector(vec!(Value::Integer(1),
               Value::Integer(2),
               Value::Vector(vec!(Value::Float(OrderedFloat(3.1)))),
               Value::Vector(vec!()),
               Value::Keyword(symbols::Keyword::new("five")),
               Value::NamespacedKeyword(symbols::NamespacedKeyword::new("six", "seven")),
               Value::PlainSymbol(symbols::PlainSymbol::new("eight")),
               Value::NamespacedSymbol(symbols::NamespacedSymbol::new("nine", "ten")),
               Value::Boolean(true))).to_string());
}

/// Creates `is_$TYPE` helper functions for Value, like
/// `is_big_integer()` or `is_text()`.
macro_rules! def_is {
    ($name: ident, $pat: pat) => {
        pub fn $name(&self) -> bool {
            match *self { $pat => true, _ => false }
        }
    }
}

/// Creates `as_$TYPE` helper functions for Value, like `as_big_integer()`,
/// which returns the underlying value representing this Value wrapped
/// in an Option, like `<Option<&BigInt>`.
macro_rules! def_as {
    ($name: ident, $kind: path, $t: ty) => {
        pub fn $name(&self) -> Option<&$t> {
            match *self { $kind(ref v) => Some(v), _ => None }
        }
    }
}

impl Value {
    def_is!(is_nil, Nil);
    def_is!(is_boolean, Boolean(_));
    def_is!(is_integer, Integer(_));
    def_is!(is_big_integer, BigInteger(_));
    def_is!(is_float, Float(_));
    def_is!(is_text, Text(_));
    def_is!(is_symbol, PlainSymbol(_));
    def_is!(is_namespaced_symbol, NamespacedSymbol(_));
    def_is!(is_keyword, Keyword(_));
    def_is!(is_namespaced_keyword, NamespacedKeyword(_));
    def_is!(is_vector, Vector(_));
    def_is!(is_list, List(_));
    def_is!(is_set, Set(_));
    def_is!(is_map, Map(_));

    /// `as_nil` does not use the macro as it does not have an underlying
    /// value, and returns `Option<()>`.
    pub fn as_nil(&self) -> Option<()> {
        match *self { Nil => Some(()), _ => None }
    }

    def_as!(as_boolean, Boolean, bool);
    def_as!(as_integer, Integer, i64);
    def_as!(as_big_integer, BigInteger, BigInt);
    def_as!(as_float, Float, OrderedFloat<f64>);
    def_as!(as_text, Text, String);
    def_as!(as_symbol, PlainSymbol, symbols::PlainSymbol);
    def_as!(as_namespaced_symbol, NamespacedSymbol, symbols::NamespacedSymbol);
    def_as!(as_keyword, Keyword, symbols::Keyword);
    def_as!(as_namespaced_keyword, NamespacedKeyword, symbols::NamespacedKeyword);
    def_as!(as_vector, Vector, Vec<Value>);
    def_as!(as_list, List, LinkedList<Value>);
    def_as!(as_set, Set, BTreeSet<Value>);
    def_as!(as_map, Map, BTreeMap<Value, Value>);

    pub fn from_bigint(src: &str) -> Option<Value> {
        src.parse::<BigInt>().map(Value::BigInteger).ok()
    }
}

impl From<f64> for Value {
    fn from(src: f64) -> Value {
        Value::Float(OrderedFloat::from(src))
    }
}

impl PartialOrd for Value {
    fn partial_cmp(&self, other: &Value) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

// TODO: Check we follow the equality rules at the bottom of https://github.com/edn-format/edn
impl Ord for Value {
    fn cmp(&self, other: &Value) -> Ordering {

        let ord_order = to_ord(self).cmp(&to_ord(other));
        match *self {
            Nil             => match *other { Nil             => Ordering::Equal, _ => ord_order },
            Boolean(bs)     => match *other { Boolean(bo)     => bo.cmp(&bs), _ => ord_order },
            BigInteger(ref bs) => match *other { BigInteger(ref bo) => bo.cmp(&bs), _ => ord_order },
            Integer(is)     => match *other { Integer(io)     => io.cmp(&is), _ => ord_order },
            Float(ref fs)   => match *other { Float(ref fo)   => fo.cmp(&fs), _ => ord_order },
            Text(ref ts)    => match *other { Text(ref to)    => to.cmp(&ts), _ => ord_order },
            PlainSymbol(ref ss)  => match *other { PlainSymbol(ref so)  => so.cmp(&ss), _ => ord_order },
            NamespacedSymbol(ref ss)
                => match *other { NamespacedSymbol(ref so)    => so.cmp(&ss), _ => ord_order },
            Keyword(ref ks) => match *other { Keyword(ref ko) => ko.cmp(&ks), _ => ord_order },
            NamespacedKeyword(ref ks)
                => match *other { NamespacedKeyword(ref ko)   => ko.cmp(&ks), _ => ord_order },
            Vector(ref vs)  => match *other { Vector(ref vo)  => vo.cmp(&vs), _ => ord_order },
            List(ref ls)    => match *other { List(ref lo)    => lo.cmp(&ls), _ => ord_order },
            Set(ref ss)     => match *other { Set(ref so)     => so.cmp(&ss), _ => ord_order },
            Map(ref ms)     => match *other { Map(ref mo)     => mo.cmp(&ms), _ => ord_order },
        }
    }
}

fn to_ord(value: &Value) -> i32 {
    match *value {
        Nil => 0,
        Boolean(_) => 1,
        Integer(_) => 2,
        BigInteger(_) => 3,
        Float(_) => 4,
        Text(_) => 5,
        PlainSymbol(_) => 6,
        NamespacedSymbol(_) => 7,
        Keyword(_) => 8,
        NamespacedKeyword(_) => 9,
        Vector(_) => 10,
        List(_) => 11,
        Set(_) => 12,
        Map(_) => 13,
    }
}

/// Converts `name` into a plain or namespaced value symbol, depending on
/// whether or not `namespace` is given.
///
/// # Examples
///
/// ```
/// # use edn::types::to_symbol;
/// # use edn::types::Value;
/// # use edn::symbols;
/// let value = to_symbol("foo", "bar");
/// assert_eq!(value, Value::NamespacedSymbol(symbols::NamespacedSymbol::new("foo", "bar")));
///
/// let value = to_symbol(None, "baz");
/// assert_eq!(value, Value::PlainSymbol(symbols::PlainSymbol::new("baz")));
/// ```
pub fn to_symbol<'a, T: Into<Option<&'a str>>>(namespace: T, name: &str) -> Value {
    namespace.into().map_or_else(
        || Value::PlainSymbol(symbols::PlainSymbol::new(name)),
        |ns| Value::NamespacedSymbol(symbols::NamespacedSymbol::new(ns, name)))
}

/// Converts `name` into a plain or namespaced value keyword, depending on
/// whether or not `namespace` is given.
///
/// # Examples
///
/// ```
/// # use edn::types::to_keyword;
/// # use edn::types::Value;
/// # use edn::symbols;
/// let value = to_keyword("foo", "bar");
/// assert_eq!(value, Value::NamespacedKeyword(symbols::NamespacedKeyword::new("foo", "bar")));
///
/// let value = to_keyword(None, "baz");
/// assert_eq!(value, Value::Keyword(symbols::Keyword::new("baz")));
/// ```
pub fn to_keyword<'a, T: Into<Option<&'a str>>>(namespace: T, name: &str) -> Value {
    namespace.into().map_or_else(
        || Value::Keyword(symbols::Keyword::new(name)),
        |ns| Value::NamespacedKeyword(symbols::NamespacedKeyword::new(ns, name)))
}<commit_msg>Add note about linked lists data type choice for edn::Value<commit_after>// Copyright 2016 Mozilla
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
// this file except in compliance with the License. You may obtain a copy of the
// License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

#![allow(unused_imports)]

use std::collections::{BTreeSet, BTreeMap, LinkedList};
use std::cmp::{Ordering, Ord, PartialOrd};
use std::fmt::{Display, Formatter};

use symbols;
use num::bigint::{BigInt, ToBigInt, ParseBigIntError};
use ordered_float::OrderedFloat;

/// Value represents one of the allowed values in an EDN string.
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
pub enum Value {
    Nil,
    Boolean(bool),
    Integer(i64),
    BigInteger(BigInt),
    // https://users.rust-lang.org/t/hashmap-key-cant-be-float-number-type-why/7892
    Float(OrderedFloat<f64>),
    Text(String),
    PlainSymbol(symbols::PlainSymbol),
    NamespacedSymbol(symbols::NamespacedSymbol),
    Keyword(symbols::Keyword),
    NamespacedKeyword(symbols::NamespacedKeyword),
    Vector(Vec<Value>),
    // We're using a LinkedList here instead of a Vec or VecDeque because the
    // LinkedList is faster for appending (which we do a lot of).
    // See https://github.com/mozilla/mentat/issues/231
    List(LinkedList<Value>),
    // We're using BTree{Set, Map} rather than Hash{Set, Map} because the BTree variants
    // implement Hash. The Hash variants don't in order to preserve O(n) hashing
    // time, which is hard given recursive data structures.
    // See https://internals.rust-lang.org/t/implementing-hash-for-hashset-hashmap/3817/1
    Set(BTreeSet<Value>),
    Map(BTreeMap<Value, Value>),
}

use self::Value::*;

impl Display for Value {
    fn fmt(&self, f: &mut Formatter) -> ::std::fmt::Result {
        match *self {
            Keyword(ref v) => v.fmt(f),
            NamespacedKeyword(ref v) => v.fmt(f),
            PlainSymbol(ref v) => v.fmt(f),
            NamespacedSymbol(ref v) => v.fmt(f),

            Integer(v) => write!(f, "{}", v),
            BigInteger(ref v) => write!(f, "{}N", v),
            Float(OrderedFloat(v)) => write!(f, "{}", v),       // TODO: make sure float syntax is correct.
                                                                // TODO: NaN.
            Text(ref v) => write!(f, "{}", v),                  // TODO: EDN escaping.
            Vector(ref v) => {
                try!(write!(f, "["));
                for x in v {
                    try!(write!(f, " {}", x));
                }
                write!(f, " ]")
            }
            _ =>
                write!(f, "{}",
                       match *self {
                           Nil => "null",
                           Boolean(b) => if b { "true" } else { "false" },
                           _ => unimplemented!(),
                       }),
        }
    }
}

#[test]
fn test_value_from() {
    assert_eq!(Value::from(42f64), Value::Float(OrderedFloat::from(42f64)));
    assert_eq!(Value::from_bigint("42").unwrap(), Value::BigInteger(42.to_bigint().unwrap()));
}

#[test]
fn test_print_edn() {
    assert_eq!("[ 1 2 [ 3.1 ] [ ] :five :six/seven eight nine/ten true ]",
               Value::Vector(vec!(Value::Integer(1),
               Value::Integer(2),
               Value::Vector(vec!(Value::Float(OrderedFloat(3.1)))),
               Value::Vector(vec!()),
               Value::Keyword(symbols::Keyword::new("five")),
               Value::NamespacedKeyword(symbols::NamespacedKeyword::new("six", "seven")),
               Value::PlainSymbol(symbols::PlainSymbol::new("eight")),
               Value::NamespacedSymbol(symbols::NamespacedSymbol::new("nine", "ten")),
               Value::Boolean(true))).to_string());
}

/// Creates `is_$TYPE` helper functions for Value, like
/// `is_big_integer()` or `is_text()`.
macro_rules! def_is {
    ($name: ident, $pat: pat) => {
        pub fn $name(&self) -> bool {
            match *self { $pat => true, _ => false }
        }
    }
}

/// Creates `as_$TYPE` helper functions for Value, like `as_big_integer()`,
/// which returns the underlying value representing this Value wrapped
/// in an Option, like `<Option<&BigInt>`.
macro_rules! def_as {
    ($name: ident, $kind: path, $t: ty) => {
        pub fn $name(&self) -> Option<&$t> {
            match *self { $kind(ref v) => Some(v), _ => None }
        }
    }
}

impl Value {
    def_is!(is_nil, Nil);
    def_is!(is_boolean, Boolean(_));
    def_is!(is_integer, Integer(_));
    def_is!(is_big_integer, BigInteger(_));
    def_is!(is_float, Float(_));
    def_is!(is_text, Text(_));
    def_is!(is_symbol, PlainSymbol(_));
    def_is!(is_namespaced_symbol, NamespacedSymbol(_));
    def_is!(is_keyword, Keyword(_));
    def_is!(is_namespaced_keyword, NamespacedKeyword(_));
    def_is!(is_vector, Vector(_));
    def_is!(is_list, List(_));
    def_is!(is_set, Set(_));
    def_is!(is_map, Map(_));

    /// `as_nil` does not use the macro as it does not have an underlying
    /// value, and returns `Option<()>`.
    pub fn as_nil(&self) -> Option<()> {
        match *self { Nil => Some(()), _ => None }
    }

    def_as!(as_boolean, Boolean, bool);
    def_as!(as_integer, Integer, i64);
    def_as!(as_big_integer, BigInteger, BigInt);
    def_as!(as_float, Float, OrderedFloat<f64>);
    def_as!(as_text, Text, String);
    def_as!(as_symbol, PlainSymbol, symbols::PlainSymbol);
    def_as!(as_namespaced_symbol, NamespacedSymbol, symbols::NamespacedSymbol);
    def_as!(as_keyword, Keyword, symbols::Keyword);
    def_as!(as_namespaced_keyword, NamespacedKeyword, symbols::NamespacedKeyword);
    def_as!(as_vector, Vector, Vec<Value>);
    def_as!(as_list, List, LinkedList<Value>);
    def_as!(as_set, Set, BTreeSet<Value>);
    def_as!(as_map, Map, BTreeMap<Value, Value>);

    pub fn from_bigint(src: &str) -> Option<Value> {
        src.parse::<BigInt>().map(Value::BigInteger).ok()
    }
}

impl From<f64> for Value {
    fn from(src: f64) -> Value {
        Value::Float(OrderedFloat::from(src))
    }
}

impl PartialOrd for Value {
    fn partial_cmp(&self, other: &Value) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

// TODO: Check we follow the equality rules at the bottom of https://github.com/edn-format/edn
impl Ord for Value {
    fn cmp(&self, other: &Value) -> Ordering {

        let ord_order = to_ord(self).cmp(&to_ord(other));
        match *self {
            Nil             => match *other { Nil             => Ordering::Equal, _ => ord_order },
            Boolean(bs)     => match *other { Boolean(bo)     => bo.cmp(&bs), _ => ord_order },
            BigInteger(ref bs) => match *other { BigInteger(ref bo) => bo.cmp(&bs), _ => ord_order },
            Integer(is)     => match *other { Integer(io)     => io.cmp(&is), _ => ord_order },
            Float(ref fs)   => match *other { Float(ref fo)   => fo.cmp(&fs), _ => ord_order },
            Text(ref ts)    => match *other { Text(ref to)    => to.cmp(&ts), _ => ord_order },
            PlainSymbol(ref ss)  => match *other { PlainSymbol(ref so)  => so.cmp(&ss), _ => ord_order },
            NamespacedSymbol(ref ss)
                => match *other { NamespacedSymbol(ref so)    => so.cmp(&ss), _ => ord_order },
            Keyword(ref ks) => match *other { Keyword(ref ko) => ko.cmp(&ks), _ => ord_order },
            NamespacedKeyword(ref ks)
                => match *other { NamespacedKeyword(ref ko)   => ko.cmp(&ks), _ => ord_order },
            Vector(ref vs)  => match *other { Vector(ref vo)  => vo.cmp(&vs), _ => ord_order },
            List(ref ls)    => match *other { List(ref lo)    => lo.cmp(&ls), _ => ord_order },
            Set(ref ss)     => match *other { Set(ref so)     => so.cmp(&ss), _ => ord_order },
            Map(ref ms)     => match *other { Map(ref mo)     => mo.cmp(&ms), _ => ord_order },
        }
    }
}

fn to_ord(value: &Value) -> i32 {
    match *value {
        Nil => 0,
        Boolean(_) => 1,
        Integer(_) => 2,
        BigInteger(_) => 3,
        Float(_) => 4,
        Text(_) => 5,
        PlainSymbol(_) => 6,
        NamespacedSymbol(_) => 7,
        Keyword(_) => 8,
        NamespacedKeyword(_) => 9,
        Vector(_) => 10,
        List(_) => 11,
        Set(_) => 12,
        Map(_) => 13,
    }
}

/// Converts `name` into a plain or namespaced value symbol, depending on
/// whether or not `namespace` is given.
///
/// # Examples
///
/// ```
/// # use edn::types::to_symbol;
/// # use edn::types::Value;
/// # use edn::symbols;
/// let value = to_symbol("foo", "bar");
/// assert_eq!(value, Value::NamespacedSymbol(symbols::NamespacedSymbol::new("foo", "bar")));
///
/// let value = to_symbol(None, "baz");
/// assert_eq!(value, Value::PlainSymbol(symbols::PlainSymbol::new("baz")));
/// ```
pub fn to_symbol<'a, T: Into<Option<&'a str>>>(namespace: T, name: &str) -> Value {
    namespace.into().map_or_else(
        || Value::PlainSymbol(symbols::PlainSymbol::new(name)),
        |ns| Value::NamespacedSymbol(symbols::NamespacedSymbol::new(ns, name)))
}

/// Converts `name` into a plain or namespaced value keyword, depending on
/// whether or not `namespace` is given.
///
/// # Examples
///
/// ```
/// # use edn::types::to_keyword;
/// # use edn::types::Value;
/// # use edn::symbols;
/// let value = to_keyword("foo", "bar");
/// assert_eq!(value, Value::NamespacedKeyword(symbols::NamespacedKeyword::new("foo", "bar")));
///
/// let value = to_keyword(None, "baz");
/// assert_eq!(value, Value::Keyword(symbols::Keyword::new("baz")));
/// ```
pub fn to_keyword<'a, T: Into<Option<&'a str>>>(namespace: T, name: &str) -> Value {
    namespace.into().map_or_else(
        || Value::Keyword(symbols::Keyword::new(name)),
        |ns| Value::NamespacedKeyword(symbols::NamespacedKeyword::new(ns, name)))
}<|endoftext|>


<commit_before>// Extracted from the scopeguard crate
use core::{
    mem,
    ops::{Deref, DerefMut},
    ptr,
};

pub struct ScopeGuard<T, F>
where
    F: FnMut(&mut T),
{
    dropfn: F,
    value: T,
}

#[inline]
pub fn guard<T, F>(value: T, dropfn: F) -> ScopeGuard<T, F>
where
    F: FnMut(&mut T),
{
    ScopeGuard { dropfn, value }
}

impl<T, F> ScopeGuard<T, F>
where
    F: FnMut(&mut T),
{
    #[inline]
    pub fn into_inner(guard: Self) -> T {
        // Cannot move out of Drop-implementing types, so
        // ptr::read the value and forget the guard.
        unsafe {
            let value = ptr::read(&guard.value);
            // read the closure so that it is dropped, and assign it to a local
            // variable to ensure that it is only dropped after the guard has
            // been forgotten. (In case the Drop impl of the closure, or that
            // of any consumed captured variable, panics).
            let _dropfn = ptr::read(&guard.dropfn);
            mem::forget(guard);
            value
        }
    }
}

impl<T, F> Deref for ScopeGuard<T, F>
where
    F: FnMut(&mut T),
{
    type Target = T;
    #[inline]
    fn deref(&self) -> &T {
        &self.value
    }
}

impl<T, F> DerefMut for ScopeGuard<T, F>
where
    F: FnMut(&mut T),
{
    #[inline]
    fn deref_mut(&mut self) -> &mut T {
        &mut self.value
    }
}

impl<T, F> Drop for ScopeGuard<T, F>
where
    F: FnMut(&mut T),
{
    #[inline]
    fn drop(&mut self) {
        (self.dropfn)(&mut self.value);
    }
}
<commit_msg>Use `ManuallyDrop<T>` instead of `mem::forget` in scopeguard<commit_after>// Extracted from the scopeguard crate
use core::{
    mem::ManuallyDrop,
    ops::{Deref, DerefMut},
    ptr,
};

pub struct ScopeGuard<T, F>
where
    F: FnMut(&mut T),
{
    dropfn: F,
    value: T,
}

#[inline]
pub fn guard<T, F>(value: T, dropfn: F) -> ScopeGuard<T, F>
where
    F: FnMut(&mut T),
{
    ScopeGuard { dropfn, value }
}

impl<T, F> ScopeGuard<T, F>
where
    F: FnMut(&mut T),
{
    #[inline]
    pub fn into_inner(guard: Self) -> T {
        // Cannot move out of Drop-implementing types, so
        // ptr::read the value out of a ManuallyDrop<Self>
        // Don't use mem::forget as that might invalidate value
        let guard = ManuallyDrop::new(guard);
        unsafe {
            let value = ptr::read(&guard.value);
            // read the closure so that it is dropped
            let _ = ptr::read(&guard.dropfn);
            value
        }
    }
}

impl<T, F> Deref for ScopeGuard<T, F>
where
    F: FnMut(&mut T),
{
    type Target = T;
    #[inline]
    fn deref(&self) -> &T {
        &self.value
    }
}

impl<T, F> DerefMut for ScopeGuard<T, F>
where
    F: FnMut(&mut T),
{
    #[inline]
    fn deref_mut(&mut self) -> &mut T {
        &mut self.value
    }
}

impl<T, F> Drop for ScopeGuard<T, F>
where
    F: FnMut(&mut T),
{
    #[inline]
    fn drop(&mut self) {
        (self.dropfn)(&mut self.value);
    }
}
<|endoftext|>