<commit_before>//! Free functions that create iterator adaptors or call iterator methods.
//!
//! The benefit of free functions is that they accept any [`IntoIterator`] as
//! argument, so the resulting code may be easier to read.

#[cfg(feature = "use_alloc")]
use std::fmt::Display;
use std::iter::{self, Zip};
#[cfg(feature = "use_alloc")]
type VecIntoIter<T> = alloc::vec::IntoIter<T>;

#[cfg(feature = "use_alloc")]
use alloc::string::String;

use crate::intersperse::{Intersperse, IntersperseWith};
use crate::Itertools;

pub use crate::adaptors::{interleave, merge, put_back};
#[cfg(feature = "use_alloc")]
pub use crate::kmerge_impl::kmerge;
pub use crate::merge_join::merge_join_by;
#[cfg(feature = "use_alloc")]
pub use crate::multipeek_impl::multipeek;
#[cfg(feature = "use_alloc")]
pub use crate::peek_nth::peek_nth;
#[cfg(feature = "use_alloc")]
pub use crate::put_back_n_impl::put_back_n;
#[cfg(feature = "use_alloc")]
pub use crate::rciter_impl::rciter;
pub use crate::zip_eq_impl::zip_eq;

/// Iterate `iterable` with a particular value inserted between each element.
///
/// [`IntoIterator`] enabled version of [`Iterator::intersperse`].
///
/// ```
/// use itertools::intersperse;
///
/// itertools::assert_equal(intersperse((0..3), 8), vec![0, 8, 1, 8, 2]);
/// ```
pub fn intersperse<I>(iterable: I, element: I::Item) -> Intersperse<I::IntoIter>
where
    I: IntoIterator,
    <I as IntoIterator>::Item: Clone,
{
    Itertools::intersperse(iterable.into_iter(), element)
}

/// Iterate `iterable` with a particular value created by a function inserted
/// between each element.
///
/// [`IntoIterator`] enabled version of [`Iterator::intersperse_with`].
///
/// ```
/// use itertools::intersperse_with;
///
/// let mut i = 10;
/// itertools::assert_equal(intersperse_with((0..3), || { i -= 1; i }), vec![0, 9, 1, 8, 2]);
/// assert_eq!(i, 8);
/// ```
pub fn intersperse_with<I, F>(iterable: I, element: F) -> IntersperseWith<I::IntoIter, F>
where
    I: IntoIterator,
    F: FnMut() -> I::Item,
{
    Itertools::intersperse_with(iterable.into_iter(), element)
}

/// Iterate `iterable` with a running index.
///
/// [`IntoIterator`] enabled version of [`Iterator::enumerate`].
///
/// ```
/// use itertools::enumerate;
///
/// for (i, elt) in enumerate(&[1, 2, 3]) {
///     /* loop body */
/// }
/// ```
pub fn enumerate<I>(iterable: I) -> iter::Enumerate<I::IntoIter>
where
    I: IntoIterator,
{
    iterable.into_iter().enumerate()
}

/// Iterate `iterable` in reverse.
///
/// [`IntoIterator`] enabled version of [`Iterator::rev`].
///
/// ```
/// use itertools::rev;
///
/// for elt in rev(&[1, 2, 3]) {
///     /* loop body */
/// }
/// ```
pub fn rev<I>(iterable: I) -> iter::Rev<I::IntoIter>
where
    I: IntoIterator,
    I::IntoIter: DoubleEndedIterator,
{
    iterable.into_iter().rev()
}

/// Iterate `i` and `j` in lock step.
///
/// [`IntoIterator`] enabled version of [`Iterator::zip`].
///
/// ```
/// use itertools::zip;
///
/// let data_1 = [1, 2, 3, 4, 5];
/// let data_2 = ['a', 'b', 'c'];
/// let mut result: Vec<(i32, char)> = Vec::new();
///
/// for (a, b) in zip(&data_1, &data_2) {
///     result.push((*a, *b));
/// }
/// assert_eq!(result, vec![(1, 'a'),(2, 'b'),(3, 'c')]);
/// ```
///
pub fn zip<I, J>(i: I, j: J) -> Zip<I::IntoIter, J::IntoIter>
where
    I: IntoIterator,
    J: IntoIterator,
{
    i.into_iter().zip(j)
}

/// Create an iterator that first iterates `i` and then `j`.
///
/// [`IntoIterator`] enabled version of [`Iterator::chain`].
///
/// ```
/// use itertools::chain;
///
/// for elt in chain(&[1, 2, 3], &[4]) {
///     /* loop body */
/// }
/// ```
pub fn chain<I, J>(
    i: I,
    j: J,
) -> iter::Chain<<I as IntoIterator>::IntoIter, <J as IntoIterator>::IntoIter>
where
    I: IntoIterator,
    J: IntoIterator<Item = I::Item>,
{
    i.into_iter().chain(j)
}

/// Create an iterator that clones each element from &T to T
///
/// [`IntoIterator`] enabled version of [`Iterator::cloned`].
///
/// ```
/// use itertools::cloned;
///
/// assert_eq!(cloned(b"abc").next(), Some(b'a'));
/// ```
pub fn cloned<'a, I, T: 'a>(iterable: I) -> iter::Cloned<I::IntoIter>
where
    I: IntoIterator<Item = &'a T>,
    T: Clone,
{
    iterable.into_iter().cloned()
}

/// Perform a fold operation over the iterable.
///
/// [`IntoIterator`] enabled version of [`Iterator::fold`].
///
/// ```
/// use itertools::fold;
///
/// assert_eq!(fold(&[1., 2., 3.], 0., |a, &b| f32::max(a, b)), 3.);
/// ```
pub fn fold<I, B, F>(iterable: I, init: B, f: F) -> B
where
    I: IntoIterator,
    F: FnMut(B, I::Item) -> B,
{
    iterable.into_iter().fold(init, f)
}

/// Test whether the predicate holds for all elements in the iterable.
///
/// [`IntoIterator`] enabled version of [`Iterator::all`].
///
/// ```
/// use itertools::all;
///
/// assert!(all(&[1, 2, 3], |elt| *elt > 0));
/// ```
pub fn all<I, F>(iterable: I, f: F) -> bool
where
    I: IntoIterator,
    F: FnMut(I::Item) -> bool,
{
    iterable.into_iter().all(f)
}

/// Test whether the predicate holds for any elements in the iterable.
///
/// [`IntoIterator`] enabled version of [`Iterator::any`].
///
/// ```
/// use itertools::any;
///
/// assert!(any(&[0, -1, 2], |elt| *elt > 0));
/// ```
pub fn any<I, F>(iterable: I, f: F) -> bool
where
    I: IntoIterator,
    F: FnMut(I::Item) -> bool,
{
    iterable.into_iter().any(f)
}

/// Return the maximum value of the iterable.
///
/// [`IntoIterator`] enabled version of [`Iterator::max`].
///
/// ```
/// use itertools::max;
///
/// assert_eq!(max(0..10), Some(9));
/// ```
pub fn max<I>(iterable: I) -> Option<I::Item>
where
    I: IntoIterator,
    I::Item: Ord,
{
    iterable.into_iter().max()
}

/// Return the minimum value of the iterable.
///
/// [`IntoIterator`] enabled version of [`Iterator::min`].
///
/// ```
/// use itertools::min;
///
/// assert_eq!(min(0..10), Some(0));
/// ```
pub fn min<I>(iterable: I) -> Option<I::Item>
where
    I: IntoIterator,
    I::Item: Ord,
{
    iterable.into_iter().min()
}

/// Combine all iterator elements into one String, separated by `sep`.
///
/// [`IntoIterator`] enabled version of [`Itertools::join`].
///
/// ```
/// use itertools::join;
///
/// assert_eq!(join(&[1, 2, 3], ", "), "1, 2, 3");
/// ```
#[cfg(feature = "use_alloc")]
pub fn join<I>(iterable: I, sep: &str) -> String
where
    I: IntoIterator,
    I::Item: Display,
{
    iterable.into_iter().join(sep)
}

/// Sort all iterator elements into a new iterator in ascending order.
///
/// [`IntoIterator`] enabled version of [`Itertools::sorted`].
///
/// ```
/// use itertools::sorted;
/// use itertools::assert_equal;
///
/// assert_equal(sorted("rust".chars()), "rstu".chars());
/// ```
#[cfg(feature = "use_alloc")]
pub fn sorted<I>(iterable: I) -> VecIntoIter<I::Item>
where
    I: IntoIterator,
    I::Item: Ord,
{
    iterable.into_iter().sorted()
}
<commit_msg>Reverted formatting  changes<commit_after>//! Free functions that create iterator adaptors or call iterator methods.
//!
//! The benefit of free functions is that they accept any [`IntoIterator`] as
//! argument, so the resulting code may be easier to read.

#[cfg(feature = "use_alloc")]
use std::fmt::Display;
use std::iter::{self, Zip};
#[cfg(feature = "use_alloc")]
type VecIntoIter<T> = alloc::vec::IntoIter<T>;

#[cfg(feature = "use_alloc")]
use alloc::{
    string::String,
};

use crate::Itertools;
use crate::intersperse::{Intersperse, IntersperseWith};

pub use crate::adaptors::{
    interleave,
    merge,
    put_back,
};
#[cfg(feature = "use_alloc")]
pub use crate::put_back_n_impl::put_back_n;
#[cfg(feature = "use_alloc")]
pub use crate::multipeek_impl::multipeek;
#[cfg(feature = "use_alloc")]
pub use crate::peek_nth::peek_nth;
#[cfg(feature = "use_alloc")]
pub use crate::kmerge_impl::kmerge;
pub use crate::zip_eq_impl::zip_eq;
pub use crate::merge_join::merge_join_by;
#[cfg(feature = "use_alloc")]
pub use crate::rciter_impl::rciter;

/// Iterate `iterable` with a particular value inserted between each element.
///
/// [`IntoIterator`] enabled version of [`Iterator::intersperse`].
///
/// ```
/// use itertools::intersperse;
///
/// itertools::assert_equal(intersperse((0..3), 8), vec![0, 8, 1, 8, 2]);
/// ```
pub fn intersperse<I>(iterable: I, element: I::Item) -> Intersperse<I::IntoIter>
    where I: IntoIterator,
          <I as IntoIterator>::Item: Clone
{
    Itertools::intersperse(iterable.into_iter(), element)
}

/// Iterate `iterable` with a particular value created by a function inserted
/// between each element.
///
/// [`IntoIterator`] enabled version of [`Iterator::intersperse_with`].
///
/// ```
/// use itertools::intersperse_with;
///
/// let mut i = 10;
/// itertools::assert_equal(intersperse_with((0..3), || { i -= 1; i }), vec![0, 9, 1, 8, 2]);
/// assert_eq!(i, 8);
/// ```
pub fn intersperse_with<I, F>(iterable: I, element: F) -> IntersperseWith<I::IntoIter, F>
    where I: IntoIterator,
          F: FnMut() -> I::Item
{
    Itertools::intersperse_with(iterable.into_iter(), element)
}

/// Iterate `iterable` with a running index.
///
/// [`IntoIterator`] enabled version of [`Iterator::enumerate`].
///
/// ```
/// use itertools::enumerate;
///
/// for (i, elt) in enumerate(&[1, 2, 3]) {
///     /* loop body */
/// }
/// ```
pub fn enumerate<I>(iterable: I) -> iter::Enumerate<I::IntoIter>
    where I: IntoIterator
{
    iterable.into_iter().enumerate()
}

/// Iterate `iterable` in reverse.
///
/// [`IntoIterator`] enabled version of [`Iterator::rev`].
///
/// ```
/// use itertools::rev;
///
/// for elt in rev(&[1, 2, 3]) {
///     /* loop body */
/// }
/// ```
pub fn rev<I>(iterable: I) -> iter::Rev<I::IntoIter>
    where I: IntoIterator,
          I::IntoIter: DoubleEndedIterator
{
    iterable.into_iter().rev()
}

/// Iterate `i` and `j` in lock step.
///
/// [`IntoIterator`] enabled version of [`Iterator::zip`].
///
/// ```
/// use itertools::zip;
///
/// let data_1 = [1, 2, 3, 4, 5];
/// let data_2 = ['a', 'b', 'c'];
/// let mut result: Vec<(i32, char)> = Vec::new();
///
/// for (a, b) in zip(&data_1, &data_2) {
///     result.push((*a, *b));
/// }
/// assert_eq!(result, vec![(1, 'a'),(2, 'b'),(3, 'c')]);
/// ```
pub fn zip<I, J>(i: I, j: J) -> Zip<I::IntoIter, J::IntoIter>
    where I: IntoIterator,
          J: IntoIterator
{
    i.into_iter().zip(j)
}

/// Create an iterator that first iterates `i` and then `j`.
///
/// [`IntoIterator`] enabled version of [`Iterator::chain`].
///
/// ```
/// use itertools::chain;
///
/// for elt in chain(&[1, 2, 3], &[4]) {
///     /* loop body */
/// }
/// ```
pub fn chain<I, J>(i: I, j: J) -> iter::Chain<<I as IntoIterator>::IntoIter, <J as IntoIterator>::IntoIter>
    where I: IntoIterator,
          J: IntoIterator<Item = I::Item>
{
    i.into_iter().chain(j)
}

/// Create an iterator that clones each element from &T to T
///
/// [`IntoIterator`] enabled version of [`Iterator::cloned`].
///
/// ```
/// use itertools::cloned;
///
/// assert_eq!(cloned(b"abc").next(), Some(b'a'));
/// ```
pub fn cloned<'a, I, T: 'a>(iterable: I) -> iter::Cloned<I::IntoIter>
    where I: IntoIterator<Item=&'a T>,
          T: Clone,
{
    iterable.into_iter().cloned()
}

/// Perform a fold operation over the iterable.
///
/// [`IntoIterator`] enabled version of [`Iterator::fold`].
///
/// ```
/// use itertools::fold;
///
/// assert_eq!(fold(&[1., 2., 3.], 0., |a, &b| f32::max(a, b)), 3.);
/// ```
pub fn fold<I, B, F>(iterable: I, init: B, f: F) -> B
    where I: IntoIterator,
          F: FnMut(B, I::Item) -> B
{
    iterable.into_iter().fold(init, f)
}

/// Test whether the predicate holds for all elements in the iterable.
///
/// [`IntoIterator`] enabled version of [`Iterator::all`].
///
/// ```
/// use itertools::all;
///
/// assert!(all(&[1, 2, 3], |elt| *elt > 0));
/// ```
pub fn all<I, F>(iterable: I, f: F) -> bool
    where I: IntoIterator,
          F: FnMut(I::Item) -> bool
{
    iterable.into_iter().all(f)
}

/// Test whether the predicate holds for any elements in the iterable.
///
/// [`IntoIterator`] enabled version of [`Iterator::any`].
///
/// ```
/// use itertools::any;
///
/// assert!(any(&[0, -1, 2], |elt| *elt > 0));
/// ```
pub fn any<I, F>(iterable: I, f: F) -> bool
    where I: IntoIterator,
          F: FnMut(I::Item) -> bool
{
    iterable.into_iter().any(f)
}

/// Return the maximum value of the iterable.
///
/// [`IntoIterator`] enabled version of [`Iterator::max`].
///
/// ```
/// use itertools::max;
///
/// assert_eq!(max(0..10), Some(9));
/// ```
pub fn max<I>(iterable: I) -> Option<I::Item>
    where I: IntoIterator,
          I::Item: Ord
{
    iterable.into_iter().max()
}

/// Return the minimum value of the iterable.
///
/// [`IntoIterator`] enabled version of [`Iterator::min`].
///
/// ```
/// use itertools::min;
///
/// assert_eq!(min(0..10), Some(0));
/// ```
pub fn min<I>(iterable: I) -> Option<I::Item>
    where I: IntoIterator,
          I::Item: Ord
{
    iterable.into_iter().min()
}

/// Combine all iterator elements into one String, separated by `sep`.
///
/// [`IntoIterator`] enabled version of [`Itertools::join`].
///
/// ```
/// use itertools::join;
///
/// assert_eq!(join(&[1, 2, 3], ", "), "1, 2, 3");
/// ```
#[cfg(feature = "use_alloc")]
pub fn join<I>(iterable: I, sep: &str) -> String
    where I: IntoIterator,
          I::Item: Display
{
    iterable.into_iter().join(sep)
}

/// Sort all iterator elements into a new iterator in ascending order.
///
/// [`IntoIterator`] enabled version of [`Itertools::sorted`].
///
/// ```
/// use itertools::sorted;
/// use itertools::assert_equal;
///
/// assert_equal(sorted("rust".chars()), "rstu".chars());
/// ```
#[cfg(feature = "use_alloc")]
pub fn sorted<I>(iterable: I) -> VecIntoIter<I::Item>
    where I: IntoIterator,
          I::Item: Ord
{
    iterable.into_iter().sorted()
}

<|endoftext|>


<commit_before>//! Game loop.

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

// Local crate.
use GameWindow = game_window::GameWindow;
use GameIteratorSettings;
use AssetStore;
use GameIterator;
use KeyPress;
use KeyPressArgs;
use KeyRelease;
use KeyReleaseArgs;
use MouseMove;
use MouseMoveArgs;
use MouseRelativeMove;
use MouseRelativeMoveArgs;
use MousePress;
use MousePressArgs;
use MouseRelease;
use MouseReleaseArgs;
use Render;
use RenderArgs;
use Update;
use UpdateArgs;

/// 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, _args: RenderArgs) {}

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

    /// 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, _args: KeyPressArgs) {}

    /// User released a key.
    ///
    /// This can be overridden to handle key released events.
    fn key_release(&mut self, _args: KeyReleaseArgs) {}

    /// Pressed a mouse button.
    fn mouse_press(&mut self, _args: MousePressArgs) {}

    /// Released a mouse button.
    fn mouse_release(&mut self, _args: MouseReleaseArgs) {}

    /// Moved mouse cursor.
    fn mouse_move(&mut self, _args: MouseMoveArgs) {}

    /// Moved mouse relative, not bounded by cursor.
    fn mouse_relative_move(&mut self, _args: MouseRelativeMoveArgs) {}

    /// 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()
    }

    /// 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
    ) {
        self.load(asset_store);

        let mut game_iter = GameIterator::new(
            game_window,
            &GameIteratorSettings {
                updates_per_second: 120,
                max_frames_per_second: 60
            });
        loop {
            match game_iter.next() {
                None => { break }
                Some(e) => match e {

Render(args) => self.render(
    &Context::abs(
        args.width as f64,
        args.height as f64
    ), args),
Update(args) => self.update(args),
KeyPress(args) => self.key_press(args),
KeyRelease(args) => self.key_release(args),
MousePress(args) => self.mouse_press(args),
MouseRelease(args) => self.mouse_release(args),
MouseMove(args) => self.mouse_move(args),
MouseRelativeMove(args) => self.mouse_relative_move(args),

                }
            }
        }
    }
}

<commit_msg>Removed unused methods on `Game` trait<commit_after>//! Game loop.

// External crates.
use graphics::Context;

// Local crate.
use GameWindow = game_window::GameWindow;
use GameIteratorSettings;
use AssetStore;
use GameIterator;
use KeyPress;
use KeyPressArgs;
use KeyRelease;
use KeyReleaseArgs;
use MouseMove;
use MouseMoveArgs;
use MouseRelativeMove;
use MouseRelativeMoveArgs;
use MousePress;
use MousePressArgs;
use MouseRelease;
use MouseReleaseArgs;
use Render;
use RenderArgs;
use Update;
use UpdateArgs;

/// 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, _args: RenderArgs) {}

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

    /// 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, _args: KeyPressArgs) {}

    /// User released a key.
    ///
    /// This can be overridden to handle key released events.
    fn key_release(&mut self, _args: KeyReleaseArgs) {}

    /// Pressed a mouse button.
    fn mouse_press(&mut self, _args: MousePressArgs) {}

    /// Released a mouse button.
    fn mouse_release(&mut self, _args: MouseReleaseArgs) {}

    /// Moved mouse cursor.
    fn mouse_move(&mut self, _args: MouseMoveArgs) {}

    /// Moved mouse relative, not bounded by cursor.
    fn mouse_relative_move(&mut self, _args: MouseRelativeMoveArgs) {}

    /// 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
    ) {
        self.load(asset_store);

        let mut game_iter = GameIterator::new(
            game_window,
            &GameIteratorSettings {
                updates_per_second: 120,
                max_frames_per_second: 60
            });
        loop {
            match game_iter.next() {
                None => { break }
                Some(e) => match e {
                    Render(args) => self.render(
                        &Context::abs(
                            args.width as f64,
                            args.height as f64
                        ),
                        args
                    ),
                    Update(args) => self.update(args),
                    KeyPress(args) => self.key_press(args),
                    KeyRelease(args) => self.key_release(args),
                    MousePress(args) => self.mouse_press(args),
                    MouseRelease(args) => self.mouse_release(args),
                    MouseMove(args) => self.mouse_move(args),
                    MouseRelativeMove(args) => self.mouse_relative_move(args),

                }
            }
        }
    }
}

<|endoftext|>


<commit_before>//! This module contains the game logic

use std::f64;
use std::path::Path;

use graphics::{self, Transformed};
use itertools;
use opengl_graphics::GlGraphics;
use opengl_graphics::glyph_cache::GlyphCache;
use piston::input::Key;
use rand::{self, Rng, ThreadRng};

use drawing::{color, Point, Size};
use models::{Bullet, Enemy, Particle, Vector, World};
use traits::{Advance, Collide, Position};

const UPS: u16 = 120;
const BULLET_RATE: f64 = 0.01;

/// The data structure that drives the game
pub struct Game {
    /// The world contains everything that needs to be drawn
    world: World,
    /// The current score of the player
    score: u32,
    /// The active actions
    actions: Actions,
    /// Timers needed by the game
    timers: Timers,
    /// A random number generator
    rng: ThreadRng,
    /// Resources needed for drawing
    resources: Resources
}

/// Active actions (toggled by user input)
#[derive(Default)]
struct Actions {
    rotate_left: bool,
    rotate_right: bool,
    boost: bool,
    shoot: bool
}

/// Timers to handle creation of bullets, enemies and particles
#[derive(Default)]
struct Timers {
    current_time: f64,
    last_tail_particle: f64,
    last_shoot: f64,
    last_spawned_enemy: f64
}

/// Additional resources needed for the game
struct Resources {
    font: GlyphCache<'static>
}

impl Game {
    /// Returns a new `Game` containing a `World` of the given `Size`
    pub fn new(size: Size) -> Game {
        let mut rng = rand::thread_rng();
        Game {
            world: World::new(&mut rng, size),
            score: 0,
            actions: Actions::default(),
            timers: Timers::default(),
            rng: rng,
            resources: Resources { font: GlyphCache::new(&Path::new("resources/FiraMono-Bold.ttf")).unwrap() }
        }
    }

    /// Processes a key press
    pub fn key_press(&mut self, key: Key) {
        self.handle_key(key, true);
    }

    /// Processes a key release
    pub fn key_release(&mut self, key: Key) {
        self.handle_key(key, false);
    }

    /// Handles a key press or release
    fn handle_key(&mut self, key: Key, pressed: bool) {
        match key {
            Key::Left => self.actions.rotate_left = pressed,
            Key::Right => self.actions.rotate_right = pressed,
            Key::Up => self.actions.boost = pressed,
            Key::Space => self.actions.shoot = pressed,
            _ => ()
        }
    }

    /// Renders the game to the screen
    pub fn render(&mut self, c: graphics::context::Context, g: &mut GlGraphics) {
        // Clear everything
        graphics::clear(color::BLACK, g);

        // Render the world
        self.world.render(c, g);

        // Render the score
        let mut text = graphics::Text::new(22);
        text.color = color::ORANGE;
        text.draw(&format!("Score: {}", self.score),
                  &mut self.resources.font,
                  &c.draw_state,
                  c.trans(10.0, 20.0).transform,
                  g);
    }

    /// Updates the game
    ///
    /// `dt` is the amount of seconds that have passed since the last update
    pub fn update(&mut self, dt: f64) {
        self.timers.current_time += dt;

        // Update rocket rotation
        if self.actions.rotate_left {
            *self.world.player.direction_mut() += (-0.06 * UPS as f64) * dt;
        }
        if self.actions.rotate_right {
            *self.world.player.direction_mut() += (0.06 * UPS as f64) * dt;
        };

        // Set speed and advance the player with wrap around
        let speed = if self.actions.boost { 470.0  } else { 200.0 };
        self.world.player.advance_wrapping(dt * speed, self.world.size.clone());

        // Update particles
        for particle in &mut self.world.particles {
            particle.update(dt);
        }

        // Remove old particles
        self.world.particles.retain(|p| p.ttl > 0.0);

        // Add new particles at the player's position, to leave a trail
        if self.timers.current_time - self.timers.last_tail_particle > 0.05 {
            self.timers.last_tail_particle = self.timers.current_time;
            self.world.particles.push(Particle::new(self.world.player.vector.clone().invert(), 0.5));
        }

        // Add bullets
        if self.actions.shoot && self.timers.current_time - self.timers.last_shoot > BULLET_RATE {
            self.timers.last_shoot = self.timers.current_time;
            self.world.bullets.push(Bullet::new(Vector::new(self.world.player.nose(), self.world.player.direction() + self.rng.gen::<f64>() - 0.5)));
        }

        // Advance bullets
        for bullet in &mut self.world.bullets {
            bullet.update(dt * 500.0);
        }

        // Remove bullets outside the viewport
        { // Shorten the lifetime of size
        let size = &self.world.size;
        self.world.bullets.retain(|b| size.contains(b.position()));
        }

        // Spawn enemies at random locations
        if self.timers.current_time - self.timers.last_spawned_enemy > 1.0 {
            self.timers.last_spawned_enemy = self.timers.current_time;
            let mut new_enemy: Enemy;
            loop {
                new_enemy = Enemy::new(Vector::random(&mut self.rng, self.world.size.clone()));
                if !self.world.player.collides_with(&new_enemy) {
                    break;
                }
            }
            self.world.enemies.push(new_enemy);
        }

        // Move enemies in the player's direction
        for enemy in &mut self.world.enemies {
            enemy.update(dt * 100.0, self.world.player.position());
        }

        self.handle_player_collisions();
        self.handle_bullet_collisions();
    }

    /// Handles collisions between the bullets and the enemies
    ///
    /// When an enemy is reached by a bullet, both the enemy and the bullet
    /// will be removed. Additionally, the score will be increased by 10
    fn handle_bullet_collisions(&mut self) {
        let old_enemy_count = self.world.enemies.len();

        { // We introduce a scope to shorten the lifetime of the borrows below
        // The references are to avoid using self in the closure
        // (the borrow checker doesn't like that)
        let bullets = &mut self.world.bullets;
        let enemies = &mut self.world.enemies;
        let particles = &mut self.world.particles;

        bullets.retain(|bullet| {
            // Remove the first enemy that collides with a bullet (if any)
            // Add an explosion on its place
            if let Some((index, position)) = enemies.iter().enumerate()
                .find(|&(_, enemy)| enemy.collides_with(bullet))
                .map(|(index, enemy)| (index, enemy.position()))
            {
                Game::make_explosion(particles, position, 10);
                enemies.remove(index);
                false
            } else {
                true
            }
        });
        }

        let killed_enemies = (old_enemy_count - self.world.enemies.len()) as u32;
        self.score += 10 * killed_enemies;
    }

    /// reset our game-state
    fn reset(&mut self) {
        // Reset player position
        *self.world.player.x_mut() = self.world.size.random_x(&mut self.rng);
        *self.world.player.y_mut() = self.world.size.random_y(&mut self.rng);

        // Reset score
        self.score = 0;

        // Remove all enemies and bullets
        self.world.bullets.clear();
        self.world.enemies.clear();
    }

    /// Handles collisions between the player and the enemies
    fn handle_player_collisions(&mut self) {
        if self.world.enemies.iter().any(|enemy| self.world.player.collides_with(enemy)) {
            // Make an explosion where the player was
            let ppos = self.world.player.position();
            Game::make_explosion(&mut self.world.particles, ppos, 8);

            self.reset();
        }
    }

    // Generates a new explosion of the given intensity at the given position. This works best with values between 5 and 25
    fn make_explosion(particles: &mut Vec<Particle>, position: Point, intensity: u8) {
        for rotation in itertools::linspace(0.0, 2.0 * f64::consts::PI, 30) {
            for ttl in (1..intensity).map(|x| (x as f64) / 10.0) {
                particles.push(Particle::new(Vector::new(position.clone(), rotation), ttl));
            }
        }
    }
}
<commit_msg>Only spread out bullets when boosting.<commit_after>//! This module contains the game logic

use std::f64;
use std::path::Path;

use graphics::{self, Transformed};
use itertools;
use opengl_graphics::GlGraphics;
use opengl_graphics::glyph_cache::GlyphCache;
use piston::input::Key;
use rand::{self, Rng, ThreadRng};

use drawing::{color, Point, Size};
use models::{Bullet, Enemy, Particle, Vector, World};
use traits::{Advance, Collide, Position};

const UPS: u16 = 120;
const BULLET_RATE: f64 = 0.01;

/// The data structure that drives the game
pub struct Game {
    /// The world contains everything that needs to be drawn
    world: World,
    /// The current score of the player
    score: u32,
    /// The active actions
    actions: Actions,
    /// Timers needed by the game
    timers: Timers,
    /// A random number generator
    rng: ThreadRng,
    /// Resources needed for drawing
    resources: Resources
}

/// Active actions (toggled by user input)
#[derive(Default)]
struct Actions {
    rotate_left: bool,
    rotate_right: bool,
    boost: bool,
    shoot: bool
}

/// Timers to handle creation of bullets, enemies and particles
#[derive(Default)]
struct Timers {
    current_time: f64,
    last_tail_particle: f64,
    last_shoot: f64,
    last_spawned_enemy: f64
}

/// Additional resources needed for the game
struct Resources {
    font: GlyphCache<'static>
}

impl Game {
    /// Returns a new `Game` containing a `World` of the given `Size`
    pub fn new(size: Size) -> Game {
        let mut rng = rand::thread_rng();
        Game {
            world: World::new(&mut rng, size),
            score: 0,
            actions: Actions::default(),
            timers: Timers::default(),
            rng: rng,
            resources: Resources { font: GlyphCache::new(&Path::new("resources/FiraMono-Bold.ttf")).unwrap() }
        }
    }

    /// Processes a key press
    pub fn key_press(&mut self, key: Key) {
        self.handle_key(key, true);
    }

    /// Processes a key release
    pub fn key_release(&mut self, key: Key) {
        self.handle_key(key, false);
    }

    /// Handles a key press or release
    fn handle_key(&mut self, key: Key, pressed: bool) {
        match key {
            Key::Left => self.actions.rotate_left = pressed,
            Key::Right => self.actions.rotate_right = pressed,
            Key::Up => self.actions.boost = pressed,
            Key::Space => self.actions.shoot = pressed,
            _ => ()
        }
    }

    /// Renders the game to the screen
    pub fn render(&mut self, c: graphics::context::Context, g: &mut GlGraphics) {
        // Clear everything
        graphics::clear(color::BLACK, g);

        // Render the world
        self.world.render(c, g);

        // Render the score
        let mut text = graphics::Text::new(22);
        text.color = color::ORANGE;
        text.draw(&format!("Score: {}", self.score),
                  &mut self.resources.font,
                  &c.draw_state,
                  c.trans(10.0, 20.0).transform,
                  g);
    }

    /// Updates the game
    ///
    /// `dt` is the amount of seconds that have passed since the last update
    pub fn update(&mut self, dt: f64) {
        self.timers.current_time += dt;

        // Update rocket rotation
        if self.actions.rotate_left {
            *self.world.player.direction_mut() += (-0.06 * UPS as f64) * dt;
        }
        if self.actions.rotate_right {
            *self.world.player.direction_mut() += (0.06 * UPS as f64) * dt;
        };

        // Set speed and advance the player with wrap around
        let speed = if self.actions.boost { 470.0  } else { 200.0 };
        self.world.player.advance_wrapping(dt * speed, self.world.size.clone());

        // Update particles
        for particle in &mut self.world.particles {
            particle.update(dt);
        }

        // Remove old particles
        self.world.particles.retain(|p| p.ttl > 0.0);

        // Add new particles at the player's position, to leave a trail
        if self.timers.current_time - self.timers.last_tail_particle > 0.05 {
            self.timers.last_tail_particle = self.timers.current_time;
            self.world.particles.push(Particle::new(self.world.player.vector.clone().invert(), 0.5));
        }

        // Add bullets
        if self.actions.shoot && self.timers.current_time - self.timers.last_shoot > BULLET_RATE {
            self.timers.last_shoot = self.timers.current_time;
            let bullet_angle = if self.actions.boost {self.rng.gen::<f64>() - 0.5} else {0.};
            self.world.bullets.push(Bullet::new(Vector::new(self.world.player.nose(), self.world.player.direction() + bullet_angle)));
        }

        // Advance bullets
        for bullet in &mut self.world.bullets {
            bullet.update(dt * 500.0);
        }

        // Remove bullets outside the viewport
        { // Shorten the lifetime of size
        let size = &self.world.size;
        self.world.bullets.retain(|b| size.contains(b.position()));
        }

        // Spawn enemies at random locations
        if self.timers.current_time - self.timers.last_spawned_enemy > 1.0 {
            self.timers.last_spawned_enemy = self.timers.current_time;
            let mut new_enemy: Enemy;
            loop {
                new_enemy = Enemy::new(Vector::random(&mut self.rng, self.world.size.clone()));
                if !self.world.player.collides_with(&new_enemy) {
                    break;
                }
            }
            self.world.enemies.push(new_enemy);
        }

        // Move enemies in the player's direction
        for enemy in &mut self.world.enemies {
            enemy.update(dt * 100.0, self.world.player.position());
        }

        self.handle_player_collisions();
        self.handle_bullet_collisions();
    }

    /// Handles collisions between the bullets and the enemies
    ///
    /// When an enemy is reached by a bullet, both the enemy and the bullet
    /// will be removed. Additionally, the score will be increased by 10
    fn handle_bullet_collisions(&mut self) {
        let old_enemy_count = self.world.enemies.len();

        { // We introduce a scope to shorten the lifetime of the borrows below
        // The references are to avoid using self in the closure
        // (the borrow checker doesn't like that)
        let bullets = &mut self.world.bullets;
        let enemies = &mut self.world.enemies;
        let particles = &mut self.world.particles;

        bullets.retain(|bullet| {
            // Remove the first enemy that collides with a bullet (if any)
            // Add an explosion on its place
            if let Some((index, position)) = enemies.iter().enumerate()
                .find(|&(_, enemy)| enemy.collides_with(bullet))
                .map(|(index, enemy)| (index, enemy.position()))
            {
                Game::make_explosion(particles, position, 10);
                enemies.remove(index);
                false
            } else {
                true
            }
        });
        }

        let killed_enemies = (old_enemy_count - self.world.enemies.len()) as u32;
        self.score += 10 * killed_enemies;
    }

    /// reset our game-state
    fn reset(&mut self) {
        // Reset player position
        *self.world.player.x_mut() = self.world.size.random_x(&mut self.rng);
        *self.world.player.y_mut() = self.world.size.random_y(&mut self.rng);

        // Reset score
        self.score = 0;

        // Remove all enemies and bullets
        self.world.bullets.clear();
        self.world.enemies.clear();
    }

    /// Handles collisions between the player and the enemies
    fn handle_player_collisions(&mut self) {
        if self.world.enemies.iter().any(|enemy| self.world.player.collides_with(enemy)) {
            // Make an explosion where the player was
            let ppos = self.world.player.position();
            Game::make_explosion(&mut self.world.particles, ppos, 8);

            self.reset();
        }
    }

    // Generates a new explosion of the given intensity at the given position. This works best with values between 5 and 25
    fn make_explosion(particles: &mut Vec<Particle>, position: Point, intensity: u8) {
        for rotation in itertools::linspace(0.0, 2.0 * f64::consts::PI, 30) {
            for ttl in (1..intensity).map(|x| (x as f64) / 10.0) {
                particles.push(Particle::new(Vector::new(position.clone(), rotation), ttl));
            }
        }
    }
}
<|endoftext|>


<commit_before>use crate::player::Player;
use crate::settings::GameSettings;

pub struct Game {
    players: [Player; 2],
    state: GameState,
    turn: u8,
}

impl Game {
    pub fn new(settings: GameSettings) -> Game {
        let grid_size = [settings.spaces[0], settings.spaces[1]];

        Game {
            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 a human player is currently placing ships.
    pub fn is_player_placing_ship(&self) -> bool {
        self.state == GameState::Placement && !self.active_player().is_cpu()
    }

    /// Returns whether a human player is currently selecting a space.
    pub fn is_player_selecting_space(&self) -> bool {
        self.state == GameState::Active && !self.active_player().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 space on the inactive player's grid if it's unchecked.
    ///
    /// # Errors
    ///
    /// Returns an error if the inactive player's space at `pos` was already
    /// checked.
    pub fn select_space(&mut self, pos: &[u8; 2]) -> Result<(), &'static str> {
        let ref mut opponent = self.players[self.not_turn()];

        opponent.select_space(pos)?;

        // If it's an error, no ship was at the position; and if it's false, the
        // ship wasn't sunk
        if opponent.sink_ship_if_all_hit(pos) == Ok(true) {
            self.state = match opponent.all_ships_sunk() {
                true => GameState::Complete,
                false => GameState::Active,
            };
        }

        Ok(())
    }
}

#[derive(Clone, Copy, PartialEq)]
pub enum GameState {
    Placement,
    Active,
    Complete,
}
<commit_msg>Add Game settings field<commit_after>use crate::player::Player;
use crate::settings::GameSettings;

pub struct Game {
    settings: GameSettings,
    players: [Player; 2],
    state: GameState,
    turn: u8,
}

impl Game {
    pub fn new(settings: GameSettings) -> 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 a human player is currently placing ships.
    pub fn is_player_placing_ship(&self) -> bool {
        self.state == GameState::Placement && !self.active_player().is_cpu()
    }

    /// Returns whether a human player is currently selecting a space.
    pub fn is_player_selecting_space(&self) -> bool {
        self.state == GameState::Active && !self.active_player().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 space on the inactive player's grid if it's unchecked.
    ///
    /// # Errors
    ///
    /// Returns an error if the inactive player's space at `pos` was already
    /// checked.
    pub fn select_space(&mut self, pos: &[u8; 2]) -> Result<(), &'static str> {
        let ref mut opponent = self.players[self.not_turn()];

        opponent.select_space(pos)?;

        // If it's an error, no ship was at the position; and if it's false, the
        // ship wasn't sunk
        if opponent.sink_ship_if_all_hit(pos) == Ok(true) {
            self.state = match opponent.all_ships_sunk() {
                true => GameState::Complete,
                false => GameState::Active,
            };
        }

        Ok(())
    }
}

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


<commit_before>use std::str::raw;
use std::os::getenv;
use std::path::Path;
use std::libc::{c_int, c_char};
use sync::mutex::{StaticMutex, MUTEX_INIT};

#[link(name = "gdal")]
extern {
    fn GDALVersionInfo(key: *c_char) -> *c_char;
    fn GDALCreate(
            hDriver: *(),
            pszFilename: *c_char,
            nXSize: c_int,
            nYSize: c_int,
            nBands: c_int,
            eBandType: c_int,
            papszOptions: **c_char
        ) -> *();
    fn GDALOpen(pszFilename: *c_char, eAccess: c_int) -> *();
    fn GDALClose(hDS: *());
    fn GDALGetDatasetDriver(hDataset: *()) -> *();
    fn GDALGetRasterXSize(hDataset: *()) -> c_int;
    fn GDALGetRasterYSize(hDataset: *()) -> c_int;
    fn GDALGetRasterCount(hDataset: *()) -> c_int;
    fn GDALGetProjectionRef(hDS: *()) -> *c_char;
    fn GDALSetProjection(hDS: *(), pszProjection: *c_char) -> c_int;
    fn GDALAllRegister();
    fn GDALGetDriverByName(pszName: *c_char) -> *();
    fn GDALGetDriverShortName(hDriver: *()) -> *c_char;
    fn GDALGetDriverLongName(hDriver: *()) -> *c_char;
}

static GA_ReadOnly:  c_int = 0;
static GA_Update:    c_int = 1;

static GDT_Unknown:  c_int = 0;
static GDT_Byte:     c_int = 1;
static GDT_UInt16:   c_int = 2;
static GDT_Int16:    c_int = 3;
static GDT_UInt32:   c_int = 4;
static GDT_Int32:    c_int = 5;
static GDT_Float32:  c_int = 6;
static GDT_Float64:  c_int = 7;
static GDT_CInt16:   c_int = 8;
static GDT_CInt32:   c_int = 9;
static GDT_CFloat32: c_int = 10;
static GDT_CFloat64: c_int = 11;

static mut LOCK: StaticMutex = MUTEX_INIT;
static mut registered_drivers: bool = false;

fn register_drivers() {
    unsafe {
        let _g = LOCK.lock();
        if ! registered_drivers {
            GDALAllRegister();
            registered_drivers = true;
        }
    }
}

pub fn version_info(key: &str) -> ~str {
    let info = key.with_c_str(|c_key| {
        unsafe {
            let rv = GDALVersionInfo(c_key);
            return raw::from_c_str(rv);
        };
    });
    return info;
}

struct Dataset {
    c_dataset: *(),
}

impl Drop for Dataset {
    fn drop(&mut self) {
        unsafe { GDALClose(self.c_dataset); }
    }
}

impl Dataset {
    pub fn get_raster_size(&self) -> (int, int) {
        let size_x = unsafe { GDALGetRasterXSize(self.c_dataset) } as int;
        let size_y = unsafe { GDALGetRasterYSize(self.c_dataset) } as int;
        return (size_x, size_y);
    }

    pub fn get_driver(&self) -> Driver {
        let c_driver = unsafe { GDALGetDatasetDriver(self.c_dataset) };
        return Driver{c_driver: c_driver};
    }

    pub fn get_raster_count(&self) -> int {
        return unsafe { GDALGetRasterCount(self.c_dataset) } as int;
    }

    pub fn get_projection(&self) -> ~str {
        unsafe {
            let rv = GDALGetProjectionRef(self.c_dataset);
            return raw::from_c_str(rv);
        }
    }

    pub fn set_projection(&self, projection: &str) {
        projection.with_c_str(|c_projection| {
            unsafe { GDALSetProjection(self.c_dataset, c_projection) };
        });
    }
}

pub fn open(path: &Path) -> Option<Dataset> {
    register_drivers();
    let filename = path.as_str().unwrap();
    let c_dataset = filename.with_c_str(|c_filename| {
        return unsafe { GDALOpen(c_filename, GA_ReadOnly) };
    });
    return match c_dataset.is_null() {
        true  => None,
        false => Some(Dataset{c_dataset: c_dataset}),
    };
}

struct Driver {
    c_driver: *(),
}

impl Driver {
    pub fn get_short_name(&self) -> ~str {
        unsafe {
            let rv = GDALGetDriverShortName(self.c_driver);
            return raw::from_c_str(rv);
        }
    }

    pub fn get_long_name(&self) -> ~str {
        unsafe {
            let rv = GDALGetDriverLongName(self.c_driver);
            return raw::from_c_str(rv);
        }
    }

    pub fn create(
        &self,
        filename: &str,
        size_x: int,
        size_y: int,
        bands: int
    ) -> Option<Dataset> {
        use std::ptr::null;
        let c_dataset = filename.with_c_str(|c_filename| {
            unsafe {
                return GDALCreate(
                    self.c_driver,
                    c_filename,
                    size_x as c_int,
                    size_y as c_int,
                    bands as c_int,
                    GDT_Byte,
                    null()
                );
            }
        });
        return match c_dataset.is_null() {
            true  => None,
            false => Some(Dataset{c_dataset: c_dataset}),
        };
    }
}

pub fn get_driver(name: &str) -> Option<Driver> {
    register_drivers();
    let c_driver = name.with_c_str(|c_name| {
        return unsafe { GDALGetDriverByName(c_name) };
    });
    return match c_driver.is_null() {
        true  => None,
        false => Some(Driver{c_driver: c_driver}),
    };
}

#[test]
fn test_version_info() {
    let release_date = version_info("RELEASE_DATE");
    let release_name = version_info("RELEASE_NAME");
    let version_text = version_info("--version");

    let expected_text: ~str = "GDAL " + release_name + ", " +
        "released " + release_date.slice(0, 4) + "/" +
        release_date.slice(4, 6) + "/" + release_date.slice(6, 8);

    assert_eq!(version_text.into_owned(), expected_text);
}

fn fixture_path(name: &str) -> Path {
    let envvar = "RUSTILES_TEST_FIXTURES";
    let fixtures = match getenv(envvar) {
        Some(p) => Path::new(p),
        None => fail!("Environment variable {} not set", envvar)
    };
    let rv = fixtures.join(name);
    return rv;
}

#[test]
fn test_open() {
    let dataset = open(&fixture_path("tinymarble.jpeg"));
    assert!(dataset.is_some());

    let missing_dataset = open(&fixture_path("no_such_file.jpeg"));
    assert!(missing_dataset.is_none());
}

#[test]
fn test_get_raster_size() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    let (size_x, size_y) = dataset.get_raster_size();
    assert_eq!(size_x, 100);
    assert_eq!(size_y, 50);
}

#[test]
fn test_get_raster_count() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    let count = dataset.get_raster_count();
    assert_eq!(count, 3);
}

#[test]
fn test_get_projection() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    //dataset.set_projection("WGS84");
    let projection = dataset.get_projection();
    assert_eq!(projection.slice(0, 16), "GEOGCS[\"WGS 84\",");
}

#[test]
fn test_get_dataset_driver() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    let driver = dataset.get_driver();
    assert_eq!(driver.get_short_name(), ~"JPEG");
    assert_eq!(driver.get_long_name(), ~"JPEG JFIF");
}

#[test]
fn test_get_driver_by_name() {
    let missing_driver = get_driver("wtf");
    assert!(missing_driver.is_none());

    let ok_driver = get_driver("GTiff");
    assert!(ok_driver.is_some());
    let driver = ok_driver.unwrap();
    assert_eq!(driver.get_short_name(), ~"GTiff");
    assert_eq!(driver.get_long_name(), ~"GeoTIFF");
}

#[test]
fn test_create() {
    let driver = get_driver("MEM").unwrap();
    let dataset = driver.create("", 10, 20, 3).unwrap();
    assert_eq!(dataset.get_raster_size(), (10, 20));
    assert_eq!(dataset.get_raster_count(), 3);
    assert_eq!(dataset.get_driver().get_short_name(), ~"MEM");
}
<commit_msg>read raster data<commit_after>use std::slice;
use std::str::raw;
use std::os::getenv;
use std::path::Path;
use std::libc::{c_int, c_char};
use sync::mutex::{StaticMutex, MUTEX_INIT};

#[link(name = "gdal")]
extern {
    fn GDALVersionInfo(key: *c_char) -> *c_char;
    fn GDALCreate(
            hDriver: *(),
            pszFilename: *c_char,
            nXSize: c_int,
            nYSize: c_int,
            nBands: c_int,
            eBandType: c_int,
            papszOptions: **c_char
        ) -> *();
    fn GDALOpen(pszFilename: *c_char, eAccess: c_int) -> *();
    fn GDALClose(hDS: *());
    fn GDALGetDatasetDriver(hDataset: *()) -> *();
    fn GDALGetRasterXSize(hDataset: *()) -> c_int;
    fn GDALGetRasterYSize(hDataset: *()) -> c_int;
    fn GDALGetRasterCount(hDataset: *()) -> c_int;
    fn GDALGetProjectionRef(hDS: *()) -> *c_char;
    fn GDALSetProjection(hDS: *(), pszProjection: *c_char) -> c_int;
    fn GDALGetRasterBand(hDS: *(), nBandId: c_int) -> *();
    fn GDALRasterIO(
            hBand: *(),
            eRWFlag: c_int,
            nXOff: c_int,
            nYOff: c_int,
            nXSize: c_int,
            nYSize: c_int,
            pData: *(),
            nBufXSize: c_int,
            nBufYSize: c_int,
            GDALDataType: c_int,
            nPixelSpace: c_int,
            nLineSpace: c_int
        ) -> c_int;
    fn GDALAllRegister();
    fn GDALGetDriverByName(pszName: *c_char) -> *();
    fn GDALGetDriverShortName(hDriver: *()) -> *c_char;
    fn GDALGetDriverLongName(hDriver: *()) -> *c_char;
}

static GA_ReadOnly:  c_int = 0;
static GA_Update:    c_int = 1;

static GDT_Unknown:  c_int = 0;
static GDT_Byte:     c_int = 1;
static GDT_UInt16:   c_int = 2;
static GDT_Int16:    c_int = 3;
static GDT_UInt32:   c_int = 4;
static GDT_Int32:    c_int = 5;
static GDT_Float32:  c_int = 6;
static GDT_Float64:  c_int = 7;
static GDT_CInt16:   c_int = 8;
static GDT_CInt32:   c_int = 9;
static GDT_CFloat32: c_int = 10;
static GDT_CFloat64: c_int = 11;

static GF_Read:      c_int = 0;
static GF_Write:     c_int = 1;

static mut LOCK: StaticMutex = MUTEX_INIT;
static mut registered_drivers: bool = false;

fn register_drivers() {
    unsafe {
        let _g = LOCK.lock();
        if ! registered_drivers {
            GDALAllRegister();
            registered_drivers = true;
        }
    }
}

pub fn version_info(key: &str) -> ~str {
    let info = key.with_c_str(|c_key| {
        unsafe {
            let rv = GDALVersionInfo(c_key);
            return raw::from_c_str(rv);
        };
    });
    return info;
}

struct Dataset {
    c_dataset: *(),
}

impl Drop for Dataset {
    fn drop(&mut self) {
        unsafe { GDALClose(self.c_dataset); }
    }
}

impl Dataset {
    pub fn get_raster_size(&self) -> (int, int) {
        let size_x = unsafe { GDALGetRasterXSize(self.c_dataset) } as int;
        let size_y = unsafe { GDALGetRasterYSize(self.c_dataset) } as int;
        return (size_x, size_y);
    }

    pub fn get_driver(&self) -> Driver {
        let c_driver = unsafe { GDALGetDatasetDriver(self.c_dataset) };
        return Driver{c_driver: c_driver};
    }

    pub fn get_raster_count(&self) -> int {
        return unsafe { GDALGetRasterCount(self.c_dataset) } as int;
    }

    pub fn get_projection(&self) -> ~str {
        unsafe {
            let rv = GDALGetProjectionRef(self.c_dataset);
            return raw::from_c_str(rv);
        }
    }

    pub fn set_projection(&self, projection: &str) {
        projection.with_c_str(|c_projection| {
            unsafe { GDALSetProjection(self.c_dataset, c_projection) };
        });
    }

    pub fn read_raster(
        &self,
        band_index: int,
        window_x: int, window_y: int,
        window_width: uint, window_height: uint,
        buffer_width: uint, buffer_height: uint
    ) -> ByteBuffer {
        let buffer_size = buffer_width * buffer_height;
        let mut data: ~[u8] = slice::with_capacity(buffer_size);
        for _ in range(0, buffer_size) { data.push(0u8); } // TODO zero fill
        unsafe {
            let c_band = GDALGetRasterBand(self.c_dataset, band_index as c_int);
            let rv = GDALRasterIO(
                c_band,
                GF_Read,
                window_x as c_int,
                window_y as c_int,
                window_width as c_int,
                window_height as c_int,
                data.as_mut_ptr() as *(),
                buffer_width as c_int,
                buffer_height as c_int,
                GDT_Byte,
                0,
                0
            ) as int;
            assert!(rv == 0);
        };
        return ByteBuffer{
            width: buffer_width,
            height: buffer_height,
            data: data,
        };
    }
}

pub fn open(path: &Path) -> Option<Dataset> {
    register_drivers();
    let filename = path.as_str().unwrap();
    let c_dataset = filename.with_c_str(|c_filename| {
        return unsafe { GDALOpen(c_filename, GA_ReadOnly) };
    });
    return match c_dataset.is_null() {
        true  => None,
        false => Some(Dataset{c_dataset: c_dataset}),
    };
}

struct Driver {
    c_driver: *(),
}

impl Driver {
    pub fn get_short_name(&self) -> ~str {
        unsafe {
            let rv = GDALGetDriverShortName(self.c_driver);
            return raw::from_c_str(rv);
        }
    }

    pub fn get_long_name(&self) -> ~str {
        unsafe {
            let rv = GDALGetDriverLongName(self.c_driver);
            return raw::from_c_str(rv);
        }
    }

    pub fn create(
        &self,
        filename: &str,
        size_x: int,
        size_y: int,
        bands: int
    ) -> Option<Dataset> {
        use std::ptr::null;
        let c_dataset = filename.with_c_str(|c_filename| {
            unsafe {
                return GDALCreate(
                    self.c_driver,
                    c_filename,
                    size_x as c_int,
                    size_y as c_int,
                    bands as c_int,
                    GDT_Byte,
                    null()
                );
            }
        });
        return match c_dataset.is_null() {
            true  => None,
            false => Some(Dataset{c_dataset: c_dataset}),
        };
    }
}

pub fn get_driver(name: &str) -> Option<Driver> {
    register_drivers();
    let c_driver = name.with_c_str(|c_name| {
        return unsafe { GDALGetDriverByName(c_name) };
    });
    return match c_driver.is_null() {
        true  => None,
        false => Some(Driver{c_driver: c_driver}),
    };
}

struct ByteBuffer {
    width: uint,
    height: uint,
    data: ~[u8],
}

#[test]
fn test_version_info() {
    let release_date = version_info("RELEASE_DATE");
    let release_name = version_info("RELEASE_NAME");
    let version_text = version_info("--version");

    let expected_text: ~str = "GDAL " + release_name + ", " +
        "released " + release_date.slice(0, 4) + "/" +
        release_date.slice(4, 6) + "/" + release_date.slice(6, 8);

    assert_eq!(version_text.into_owned(), expected_text);
}

fn fixture_path(name: &str) -> Path {
    let envvar = "RUSTILES_TEST_FIXTURES";
    let fixtures = match getenv(envvar) {
        Some(p) => Path::new(p),
        None => fail!("Environment variable {} not set", envvar)
    };
    let rv = fixtures.join(name);
    return rv;
}

#[test]
fn test_open() {
    let dataset = open(&fixture_path("tinymarble.jpeg"));
    assert!(dataset.is_some());

    let missing_dataset = open(&fixture_path("no_such_file.jpeg"));
    assert!(missing_dataset.is_none());
}

#[test]
fn test_get_raster_size() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    let (size_x, size_y) = dataset.get_raster_size();
    assert_eq!(size_x, 100);
    assert_eq!(size_y, 50);
}

#[test]
fn test_get_raster_count() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    let count = dataset.get_raster_count();
    assert_eq!(count, 3);
}

#[test]
fn test_get_projection() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    //dataset.set_projection("WGS84");
    let projection = dataset.get_projection();
    assert_eq!(projection.slice(0, 16), "GEOGCS[\"WGS 84\",");
}

#[test]
fn test_read_raster() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    let raster = dataset.read_raster(1, 20, 30, 10, 10, 3, 5);
    assert_eq!(raster.width, 3);
    assert_eq!(raster.height, 5);
    assert_eq!(raster.data, ~[13, 3, 18, 6, 9, 1, 2, 9, 4, 6, 11, 4, 6, 2, 9]);
}

#[test]
fn test_get_dataset_driver() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    let driver = dataset.get_driver();
    assert_eq!(driver.get_short_name(), ~"JPEG");
    assert_eq!(driver.get_long_name(), ~"JPEG JFIF");
}

#[test]
fn test_get_driver_by_name() {
    let missing_driver = get_driver("wtf");
    assert!(missing_driver.is_none());

    let ok_driver = get_driver("GTiff");
    assert!(ok_driver.is_some());
    let driver = ok_driver.unwrap();
    assert_eq!(driver.get_short_name(), ~"GTiff");
    assert_eq!(driver.get_long_name(), ~"GeoTIFF");
}

#[test]
fn test_create() {
    let driver = get_driver("MEM").unwrap();
    let dataset = driver.create("", 10, 20, 3).unwrap();
    assert_eq!(dataset.get_raster_size(), (10, 20));
    assert_eq!(dataset.get_raster_count(), 3);
    assert_eq!(dataset.get_driver().get_short_name(), ~"MEM");
}
<|endoftext|>


<commit_before>/// interface to gpsd daemon
/// - via local port 2947

// ---- low-level stuff ----------------------------------------------------------------------------

use std::net::TcpStream;
use std::io::{Read, Write};
use std::f64;
use std::str;
use std::sync::mpsc;

use Info;

// ---- main thread --------------------------------------------------------------------------------

pub fn main(tx: mpsc::Sender<Info>) {
    const MAXTRIES: usize = 10;        // some tries, then give up
    for try in 1..MAXTRIES {
        match TcpStream::connect("127.0.0.1:2947") {
            Err(e) => {
                if try==MAXTRIES-1 {
                    println!("!--gpsd port 2947 not available, giving up - {}", e);
                    return
                } else {
                    println!("!--gpsd port 2947 not available, retrying ({}): {}", try, e);
                    ::wait(3000)
                }
            },

            // from now on we assume that gpsd socket won't crash/misbehave without a monumental reason
            //
            Ok(gpsd) => {
                flow(&tx, gpsd);
                ::wait(1000)
            }
        }
    }

    println!("!--gpsd thread premature end");
}

fn flow(tx: &mpsc::Sender<Info>, mut gpsd: ::std::net::TcpStream) {
    gpsd.write(b"?WATCH={\"enable\":true,\"json\":true}").expect("gpsd socket write");

    let mut buf: [u8; 1024] = [0; 1024];  // json packets from gpsd daemon
    let mut n = 0;                        // number of bytes currently in buffer

    loop {                                // loop reading chunks of data
        match gpsd.read(&mut buf[n..]) {
            Err(e) => {
                println!("!--gpsd port 2947 read error {}", e);
                return
            },

            Ok(0) => {
                continue
            },

            Ok(got) => {
                n += got;

                for idx in n-got..n {          // support partial chunks, just in case
                    if buf[idx] == b'\n'  {    // completed a line? (including \r\n)

                        // we only need Time/Position/Velocity packets
                        if buf.starts_with(b"{\"class\":\"TPV\",") {
                            let fields = &buf[1..idx-3];  // 1 to skip "{", -3 to skip "}\r\n"
                            emit(&fields, &tx)            // send available fields out
                        }

                        let len = n-idx-1;     // remaining bytes to parse on next iteration
                        for i in 0..len {
                            buf[i] = buf[idx + i + 1]
                        }
                        n = len;
                        break                  // exit the "wait for a complete line" loop
                    }
                }
            }
        }
    }
}

fn emit(buf: &[u8], tx: &mpsc::Sender<Info>) {
    let mut t = 0;                     // GPS timestamp if available, in Unix seconds
    let mut lat = ::std::f64::NAN;     // latitude or NaN
    let mut lon = ::std::f64::NAN;     // longitude or NaN
    let mut alt = -1;                  // altitude in meters (expected -1000...10000)
    let mut track = -1;                // heading in degrees (expected 0..360)
    let mut speed = -1;                // speed in decimeters/second (expected 0..25000)

    let fields = String::from_utf8_lossy(&buf[..]);
    for fld in fields.split(",\"") {
        if fld.starts_with("time\":\"") {          // timestamp field found?
            let tstr = &fld[7..31];                // "2016-02-19T00:16:14.000Z"
            let year = str::parse::<i32>(&tstr[0..4]).unwrap_or(0);
            if year >= 2016 {
                let month = str::parse::<i32>(&tstr[5..7]).unwrap_or(0);
                let day   = str::parse::<i32>(&tstr[8..10]).unwrap_or(1);
                let hour  = str::parse::<i32>(&tstr[11..13]).unwrap_or(0);
                let min   = str::parse::<i32>(&tstr[14..16]).unwrap_or(0);
                let sec   = str::parse::<i32>(&tstr[17..19]).unwrap_or(0);
                let mill  = str::parse::<i32>(&tstr[20..23]).unwrap_or(0);

                let tm = ::time::Tm { tm_year: year-1900, tm_mon: month-1, tm_mday: day,
                                      tm_hour: hour, tm_min: min, tm_sec: sec,
                                      tm_wday: 0, tm_utcoff: 0, tm_isdst: -1, tm_yday: 0,
                                      tm_nsec: mill*1_000_000 }.to_timespec();
                t = tm.sec;
            }
            continue
        }

        if fld.starts_with("lat\":") {             // latitude
            lat = str::parse::<f64>(str::from_utf8(fld[5..].as_bytes()).
                expect("gps lat: not utf8")).expect("gps lat: not parseable");
            continue
        }

        if fld.starts_with("lon\":") {             // longitude
            lon = str::parse::<f64>(str::from_utf8(fld[5..].as_bytes()).
                expect("gps lon: not utf8")).expect("gps lon: not parseable");
            continue
        }

        if fld.starts_with("alt\":") {             // altitude in meters (ignore fraction)
            alt = str::parse::<f64>(str::from_utf8(fld[5..].as_bytes()).
                expect("gps alt: not utf8")).expect("gps alt: not parseable") as isize;
            continue
        }

        if fld.starts_with("track\":") {           // estimated heading (ignore grade fraction)
            track = str::parse::<f64>(str::from_utf8(fld[7..].as_bytes()).
                expect("gps track: not utf8")).expect("gps track: not parseable") as isize;
            continue
        }

        if fld.starts_with("speed\":") {           // speed (convert from m/s to dm/hr and round)
            speed = ((str::parse::<f64>(str::from_utf8(fld[7..].as_bytes()).
                expect("gps speed: not utf8")).expect("gps speed: not parseable") * 36.0).
                    floor() / 10.0) as isize;
            continue
        }
    }

    tx.send(Info::Gps {
        t: ::clock(),
        ts: t as usize,
        alt: alt,
        track: track,
        speed: speed
    }).expect("gpsd send packet");

    // future modification: don't send a NaN packet after a NaN one
    //
    tx.send(Info::Pos {
        t: ::clock(),
        lat: lat,
        lon: lon,
    }).expect("gpsd packet send");
}

<commit_msg>upd: don't support year 2016 anymore...<commit_after>/// interface to gpsd daemon
/// - via local port 2947

// ---- low-level stuff ----------------------------------------------------------------------------

use std::net::TcpStream;
use std::io::{Read, Write};
use std::f64;
use std::str;
use std::sync::mpsc;

use Info;

// ---- main thread --------------------------------------------------------------------------------

pub fn main(tx: mpsc::Sender<Info>) {
    const MAXTRIES: usize = 10;        // some tries, then give up
    for try in 1..MAXTRIES {
        match TcpStream::connect("127.0.0.1:2947") {
            Err(e) => {
                if try==MAXTRIES-1 {
                    println!("!--gpsd port 2947 not available, giving up - {}", e);
                    return
                } else {
                    println!("!--gpsd port 2947 not available, retrying ({}): {}", try, e);
                    ::wait(3000)
                }
            },

            // from now on we assume that gpsd socket won't crash/misbehave without a monumental reason
            //
            Ok(gpsd) => {
                flow(&tx, gpsd);
                ::wait(1000)
            }
        }
    }

    println!("!--gpsd thread premature end");
}

fn flow(tx: &mpsc::Sender<Info>, mut gpsd: ::std::net::TcpStream) {
    gpsd.write(b"?WATCH={\"enable\":true,\"json\":true}").expect("gpsd socket write");

    let mut buf: [u8; 1024] = [0; 1024];  // json packets from gpsd daemon
    let mut n = 0;                        // number of bytes currently in buffer

    loop {                                // loop reading chunks of data
        match gpsd.read(&mut buf[n..]) {
            Err(e) => {
                println!("!--gpsd port 2947 read error {}", e);
                return
            },

            Ok(0) => {
                continue
            },

            Ok(got) => {
                n += got;

                for idx in n-got..n {          // support partial chunks, just in case
                    if buf[idx] == b'\n'  {    // completed a line? (including \r\n)

                        // we only need Time/Position/Velocity packets
                        if buf.starts_with(b"{\"class\":\"TPV\",") {
                            let fields = &buf[1..idx-3];  // 1 to skip "{", -3 to skip "}\r\n"
                            emit(&fields, &tx)            // send available fields out
                        }

                        let len = n-idx-1;     // remaining bytes to parse on next iteration
                        for i in 0..len {
                            buf[i] = buf[idx + i + 1]
                        }
                        n = len;
                        break                  // exit the "wait for a complete line" loop
                    }
                }
            }
        }
    }
}

fn emit(buf: &[u8], tx: &mpsc::Sender<Info>) {
    let mut t = 0;                     // GPS timestamp if available, in Unix seconds
    let mut lat = ::std::f64::NAN;     // latitude or NaN
    let mut lon = ::std::f64::NAN;     // longitude or NaN
    let mut alt = -1;                  // altitude in meters (expected -1000...10000)
    let mut track = -1;                // heading in degrees (expected 0..360)
    let mut speed = -1;                // speed in decimeters/second (expected 0..25000)

    let fields = String::from_utf8_lossy(&buf[..]);
    for fld in fields.split(",\"") {
        if fld.starts_with("time\":\"") {          // timestamp field found?
            let tstr = &fld[7..31];                // "2016-02-19T00:16:14.000Z"
            let year = str::parse::<i32>(&tstr[0..4]).unwrap_or(0);

            if year > 2016 {                       // only accept reasonable dates (sometimes uBlox GPS reports a weird year)
                let month = str::parse::<i32>(&tstr[5..7]).unwrap_or(0);
                let day   = str::parse::<i32>(&tstr[8..10]).unwrap_or(1);
                let hour  = str::parse::<i32>(&tstr[11..13]).unwrap_or(0);
                let min   = str::parse::<i32>(&tstr[14..16]).unwrap_or(0);
                let sec   = str::parse::<i32>(&tstr[17..19]).unwrap_or(0);
                let mill  = str::parse::<i32>(&tstr[20..23]).unwrap_or(0);

                let tm = ::time::Tm { tm_year: year-1900, tm_mon: month-1, tm_mday: day,
                                      tm_hour: hour, tm_min: min, tm_sec: sec,
                                      tm_wday: 0, tm_utcoff: 0, tm_isdst: -1, tm_yday: 0,
                                      tm_nsec: mill*1_000_000 }.to_timespec();
                t = tm.sec;
            }
            continue
        }

        if fld.starts_with("lat\":") {             // latitude
            lat = str::parse::<f64>(str::from_utf8(fld[5..].as_bytes()).
                expect("gps lat: not utf8")).expect("gps lat: not parseable");
            continue
        }

        if fld.starts_with("lon\":") {             // longitude
            lon = str::parse::<f64>(str::from_utf8(fld[5..].as_bytes()).
                expect("gps lon: not utf8")).expect("gps lon: not parseable");
            continue
        }

        if fld.starts_with("alt\":") {             // altitude in meters (ignore fraction)
            alt = str::parse::<f64>(str::from_utf8(fld[5..].as_bytes()).
                expect("gps alt: not utf8")).expect("gps alt: not parseable") as isize;
            continue
        }

        if fld.starts_with("track\":") {           // estimated heading (ignore grade fraction)
            track = str::parse::<f64>(str::from_utf8(fld[7..].as_bytes()).
                expect("gps track: not utf8")).expect("gps track: not parseable") as isize;
            continue
        }

        if fld.starts_with("speed\":") {           // speed (convert from m/s to dm/hr and round)
            speed = ((str::parse::<f64>(str::from_utf8(fld[7..].as_bytes()).
                expect("gps speed: not utf8")).expect("gps speed: not parseable") * 36.0).
                    floor() / 10.0) as isize;
            continue
        }
    }

    tx.send(Info::Gps {
        t: ::clock(),
        ts: t as usize,
        alt: alt,
        track: track,
        speed: speed
    }).expect("gpsd send packet");

    // future modification: don't send a NaN packet after a NaN one
    //
    tx.send(Info::Pos {
        t: ::clock(),
        lat: lat,
        lon: lon,
    }).expect("gpsd packet send");
}

<|endoftext|>


<commit_before>//! A flat grid with square cells.

use math::{ Matrix2d, Scalar, Vec2d };
use { DrawState, Graphics, Line };

/// Represents a flat grid with square cells.
#[derive(Copy, Clone)]
pub struct Grid {
    /// Number of columns.
    pub cols: u32,
    /// Number of rows.
    pub rows: u32,
    /// The width and height of each grid cell.
    pub units: Scalar,
}

/// Iterates through the cells of a grid as (u32, u32).
#[derive(Copy, Clone)]
pub struct GridCells {
    cols: u32,
    rows: u32,
    state: u64,
}

impl Grid {
    /// Draws the grid.
    pub fn draw<G>(
        &self,
        line: &Line,
        draw_state: &DrawState,
        transform: Matrix2d,
        g: &mut G
    )
        where G: Graphics
    {
        let &Grid {
            cols, rows, units
        } = self;
        for x in 0..cols + 1 {
            let x1 = x as Scalar * units;
            let y1 = 0.0;
            let x2 = x1;
            let y2 = rows as Scalar * units;
            line.draw([x1, y1, x2, y2], draw_state, transform, g);
        }
        for y in 0..rows + 1 {
            let x1 = 0.0;
            let y1 = y as Scalar * units;
            let x2 = cols as Scalar * units;
            let y2 = y1;
            line.draw([x1, y1, x2, y2], draw_state, transform, g);
        }
    }

    /// Get a GridIterator for the grid
    pub fn cells(&self) -> GridCells {
        GridCells {
            cols: self.cols,
            rows: self.rows,
            state: 0,
        }
    }

    /// Get on-screen position of a grid cell
    pub fn cell_position(&self, cell: (u32, u32)) -> Vec2d {
        [cell.0 as Scalar * &self.units, cell.1 as Scalar * &self.units]
    }

    /// Get on-screen x position of a grid cell
    pub fn x_pos(&self, cell: (u32, u32)) -> Scalar {
        self.cell_position(cell)[0]
    }

    /// Get on-screen y position of a grid cell
    pub fn y_pos(&self, cell: (u32, u32)) -> Scalar {
        self.cell_position(cell)[1]
    }
}

impl Iterator for GridCells {
    type Item = (u32, u32);

    fn next(&mut self) -> Option<(u32, u32)> {
        let cols = self.cols as u64;
        let rows = self.rows as u64;

        if self.state == cols * rows {
            return None
        }
        let ret = (
            (self.state % cols) as u32,
            (self.state / rows) as u32,
        );
        self.state += 1;

        return Some(ret);
    }

}

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

    #[test]
    fn test_grid_iterator() {
        let g: Grid = Grid {cols: 2, rows: 2, units: 2.0};
        let expected: Vec<(u32, u32)> = vec![(0, 0), (1, 0), (0, 1), (1, 1)];
        let cells: Vec<(u32, u32)> = g.cells().collect();
        assert_eq!(expected, cells);
    }

    #[test]
    fn test_cell_positions() {
        let g: Grid = Grid {cols: 2, rows: 3, units: 2.0};
        assert_eq!(4.0, g.x_pos((2,3)));
        assert_eq!(6.0, g.y_pos((2,3)));
    }
}
<commit_msg>Implement Debug for Grid and GridCells<commit_after>//! A flat grid with square cells.

use math::{ Matrix2d, Scalar, Vec2d };
use { DrawState, Graphics, Line };

/// Represents a flat grid with square cells.
#[derive(Debug, Copy, Clone)]
pub struct Grid {
    /// Number of columns.
    pub cols: u32,
    /// Number of rows.
    pub rows: u32,
    /// The width and height of each grid cell.
    pub units: Scalar,
}

/// Iterates through the cells of a grid as (u32, u32).
#[derive(Debug, Copy, Clone)]
pub struct GridCells {
    cols: u32,
    rows: u32,
    state: u64,
}

impl Grid {
    /// Draws the grid.
    pub fn draw<G>(
        &self,
        line: &Line,
        draw_state: &DrawState,
        transform: Matrix2d,
        g: &mut G
    )
        where G: Graphics
    {
        let &Grid {
            cols, rows, units
        } = self;
        for x in 0..cols + 1 {
            let x1 = x as Scalar * units;
            let y1 = 0.0;
            let x2 = x1;
            let y2 = rows as Scalar * units;
            line.draw([x1, y1, x2, y2], draw_state, transform, g);
        }
        for y in 0..rows + 1 {
            let x1 = 0.0;
            let y1 = y as Scalar * units;
            let x2 = cols as Scalar * units;
            let y2 = y1;
            line.draw([x1, y1, x2, y2], draw_state, transform, g);
        }
    }

    /// Get a GridIterator for the grid
    pub fn cells(&self) -> GridCells {
        GridCells {
            cols: self.cols,
            rows: self.rows,
            state: 0,
        }
    }

    /// Get on-screen position of a grid cell
    pub fn cell_position(&self, cell: (u32, u32)) -> Vec2d {
        [cell.0 as Scalar * &self.units, cell.1 as Scalar * &self.units]
    }

    /// Get on-screen x position of a grid cell
    pub fn x_pos(&self, cell: (u32, u32)) -> Scalar {
        self.cell_position(cell)[0]
    }

    /// Get on-screen y position of a grid cell
    pub fn y_pos(&self, cell: (u32, u32)) -> Scalar {
        self.cell_position(cell)[1]
    }
}

impl Iterator for GridCells {
    type Item = (u32, u32);

    fn next(&mut self) -> Option<(u32, u32)> {
        let cols = self.cols as u64;
        let rows = self.rows as u64;

        if self.state == cols * rows {
            return None
        }
        let ret = (
            (self.state % cols) as u32,
            (self.state / rows) as u32,
        );
        self.state += 1;

        return Some(ret);
    }

}

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

    #[test]
    fn test_grid_iterator() {
        let g: Grid = Grid {cols: 2, rows: 2, units: 2.0};
        let expected: Vec<(u32, u32)> = vec![(0, 0), (1, 0), (0, 1), (1, 1)];
        let cells: Vec<(u32, u32)> = g.cells().collect();
        assert_eq!(expected, cells);
    }

    #[test]
    fn test_cell_positions() {
        let g: Grid = Grid {cols: 2, rows: 3, units: 2.0};
        assert_eq!(4.0, g.x_pos((2,3)));
        assert_eq!(6.0, g.y_pos((2,3)));
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use Command;

pub struct Grid {
    width: u32,
    height: u32,
    chars: Vec<char>,
}

impl fmt::Show for Grid {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        let s: String = String::from_chars(self.chars.as_slice());
        write!(w, "Grid {{ width: {}, height: {}, chars: {} }}",
               self.width, self.height, s)
    }
}

pub enum ParseErr {
    PrematureLineEnd(u32, String, u32),
    BadTerminationChar(u32, String, char),
}

impl fmt::Show for ParseErr {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            PrematureLineEnd(h, ref s, width) =>
                write!(w, "line {} content {} ended prematurely; \
                           expected {} characters", h, s, width),
            BadTerminationChar(h, ref s, c) =>
                write!(w, "line {} expected end of input or line \
                           after {}, got {}", h, s, c),
        }
    }
}

impl Grid {
    pub fn new(width: u32, height: u32, background: char) -> Grid {
        let len = width * height;
        let chars = Vec::from_elem(len.to_uint().unwrap(), background);
        Grid { width: width, height: height, chars: chars }
    }

    pub fn to_string(&self) -> String {
        let len = self.height * (self.width + 1);
        let mut s = String::with_capacity(len.to_uint().unwrap());
        for y in range(0, self.height) {
            for x in range(0, self.width) {
                s.push(self.get(x, y));
            }
            s.push('\n');
        }
        s
    }

    pub fn from_str(s: &str) -> Result<Grid, ParseErr> {
        let mut w = 0u32;
        for c in s.chars() {
            if c == '\n' {
                break;
            } else {
                w += 1;
            }
        }

        let mut grid = vec![];
        let mut chars = s.chars();
        let mut h = 0;

        loop {
            h += 1;
            let row_start = grid.len();
            for i in range(0, w) {
                match (i, chars.next()) {
                    (0, None) => break,
                    (_, None) => {
                        let line = grid.slice_from(row_start).to_string();
                        return Err(PrematureLineEnd(h, line, w))
                    }
                    (_, Some(c)) => grid.push(c),
                }
            }
            match chars.next() {
                None => break,
                Some('\n') => continue,
                Some(c) => {
                    let line = grid.slice_from(row_start).to_string();
                    return Err(BadTerminationChar(h, line, c))
                }
            }
        }

        Ok(Grid { width: w, height: h, chars: grid })
    }

    pub fn width(&self) -> u32 { self.width }
    pub fn height(&self) -> u32 { self.height }

    pub fn get(&self, x: u32, y: u32) -> char {
        assert!(x < self.width);
        assert!(y < self.height);
        let idx = y * self.width + x;
        self.chars[idx.to_uint().unwrap()]
    }

    pub fn set(&mut self, x: u32, y: u32, c: char) {
        assert!(x < self.width);
        assert!(y < self.height);
        let idx = y * self.width + x;
        self.chars[idx.to_uint().unwrap()] = c;
    }

    pub fn exec(&mut self, command: &Command) {
        let Command { x, y, w, h, fill } = *command;

        if w == 1 || h == 1 {
            return self.draw_line(command);
        }

        self.set(x, y, '+');
        self.set(x, y+h-1, '+');
        self.set(x+w-1, y, '+');
        self.set(x+w-1, y+h-1, '+');

        for i in range(x + 1, x + w - 1) {
            self.set(i, y, '-');
            self.set(i, y + h - 1, '-');
        }

        for j in range(y + 1, y + h - 1) {
            self.set(x, j, '|');
            self.set(x + w - 1, j, '|');
        }

        for i in range(x+1, x + w - 1) {
            for j in range(y + 1, y + h - 1) {
                self.set(i, j, fill);
            }
        }
    }

    fn draw_line(&mut self, command: &Command) {
        assert!(command.w == 1 || command.h == 1);
        let Command { x, y, w, h, fill } = *command;
        for i in range(x, x+w) {
            for j in range(y, y+h) {
                self.set(i, j, fill);
            }
        }
    }
}
<commit_msg>tests and small fixes for grid parsing.<commit_after>use std::fmt;
use Command;

#[deriving(PartialEq, Eq, PartialOrd, Ord)]
pub struct Grid {
    width: u32,
    height: u32,
    chars: Vec<char>,
}

impl fmt::Show for Grid {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        let s: String = String::from_chars(self.chars.as_slice());
        write!(w, "Grid {{ width: {}, height: {}, chars: {} }}",
               self.width, self.height, s)
    }
}

#[deriving(PartialEq, Eq, PartialOrd, Ord)]
pub enum ParseErr {
    PrematureLineEnd(u32, String, u32),
    BadTerminationChar(u32, String, char),
}

impl fmt::Show for ParseErr {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            PrematureLineEnd(h, ref s, width) =>
                write!(w, "line {} content {} ended prematurely; \
                           expected {} characters", h, s, width),
            BadTerminationChar(h, ref s, c) =>
                write!(w, "line {} expected end of input or line \
                           after {}, got {}", h, s, c),
        }
    }
}

impl Grid {
    pub fn new(width: u32, height: u32, background: char) -> Grid {
        let len = width * height;
        let chars = Vec::from_elem(len.to_uint().unwrap(), background);
        Grid { width: width, height: height, chars: chars }
    }

    pub fn to_string(&self) -> String {
        let len = self.height * (self.width + 1);
        let mut s = String::with_capacity(len.to_uint().unwrap());
        for y in range(0, self.height) {
            for x in range(0, self.width) {
                s.push(self.get(x, y));
            }
            s.push('\n');
        }
        s
    }

    pub fn from_str(s: &str) -> Result<Grid, ParseErr> {
        let mut w = 0u32;
        for c in s.chars() {
            if c == '\n' {
                break;
            } else {
                w += 1;
            }
        }

        let mut grid = vec![];
        let mut chars = s.chars();
        let mut h = 0;

        loop {
            let mut started_line = false;
            let row_start = grid.len();
            for i in range(0, w) {
                match (i, chars.next()) {
                    (0, None) => break,
                    (_, None) => {
                        let line = String::from_chars(grid.slice_from(row_start));
                        return Err(PrematureLineEnd(h, line, w))
                    }
                    (_, Some(c)) => {
                        if !started_line {
                            h += 1;
                            started_line = true;
                        }
                        grid.push(c)
                    }
                }
            }
            match chars.next() {
                None => break,
                Some('\n') => continue,
                Some(c) => {
                    let line = String::from_chars(grid.slice_from(row_start));
                    return Err(BadTerminationChar(h, line, c))
                }
            }
        }

        Ok(Grid { width: w, height: h, chars: grid })
    }

    pub fn width(&self) -> u32 { self.width }
    pub fn height(&self) -> u32 { self.height }

    pub fn get(&self, x: u32, y: u32) -> char {
        assert!(x < self.width);
        assert!(y < self.height);
        let idx = y * self.width + x;
        self.chars[idx.to_uint().unwrap()]
    }

    pub fn set(&mut self, x: u32, y: u32, c: char) {
        assert!(x < self.width);
        assert!(y < self.height);
        let idx = y * self.width + x;
        self.chars[idx.to_uint().unwrap()] = c;
    }

    pub fn exec(&mut self, command: &Command) {
        let Command { x, y, w, h, fill } = *command;

        if w == 1 || h == 1 {
            return self.draw_line(command);
        }

        self.set(x, y, '+');
        self.set(x, y+h-1, '+');
        self.set(x+w-1, y, '+');
        self.set(x+w-1, y+h-1, '+');

        for i in range(x + 1, x + w - 1) {
            self.set(i, y, '-');
            self.set(i, y + h - 1, '-');
        }

        for j in range(y + 1, y + h - 1) {
            self.set(x, j, '|');
            self.set(x + w - 1, j, '|');
        }

        for i in range(x+1, x + w - 1) {
            for j in range(y + 1, y + h - 1) {
                self.set(i, j, fill);
            }
        }
    }

    fn draw_line(&mut self, command: &Command) {
        assert!(command.w == 1 || command.h == 1);
        let Command { x, y, w, h, fill } = *command;
        for i in range(x, x+w) {
            for j in range(y, y+h) {
                self.set(i, j, fill);
            }
        }
    }
}

#[test]
fn simple_parse() {
    assert_eq!(Grid::from_str("...").unwrap(),
               Grid {width: 3, height: 1, chars: "...".chars().collect() });
    assert_eq!(Grid::from_str("...\n").unwrap(),
               Grid {width: 3, height: 1, chars: "...".chars().collect() });
    assert_eq!(Grid::from_str("...\n...\n").unwrap(),
               Grid {width: 3, height: 2, chars: "......".chars().collect() });
    assert_eq!(Grid::from_str("...\n...").unwrap(),
               Grid {width: 3, height: 2, chars: "......".chars().collect() });
    assert_eq!(Grid::from_str("abc\ndef\n").unwrap(),
               Grid {width: 3, height: 2, chars: "abcdef".chars().collect() });
}

#[test]
fn premature_line_end() {
    assert_eq!(Grid::from_str("abc\nd"),
               Err(PrematureLineEnd(2, "d".to_string(), 3)));
}

#[test]
fn unexpected_terminator() {
    assert_eq!(Grid::from_str("abc\ndefg"),
               Err(BadTerminationChar(2, "def".to_string(), 'g')))
}
<|endoftext|>


<commit_before>extern crate kafka;

use std::sync::Arc;
use std::sync::mpsc;
use std::thread;
use std::io::Error;

use kafka::protocol::*;
use kafka::connection::tcp_connection::ConnectionMessage;

use ::fixtures::*;

//Receives a request message and sends a response message with the same correlation id
pub fn respond(req: ConnectionMessage<MyRequest, MyResponse>) -> Result<ConnectionMessage<MyRequest, MyResponse>, Error> {
	match req {
		ConnectionMessage::Request::<MyRequest, MyResponse>(tx, req) => {
			let res = Arc::new(ApiResponseMessage {
				response: MyResponse {
					id: req.request.id,
					content: "my response content".to_string()
				},
				correlation_id: req.correlation_id
			});

			tx.send(res.clone()).unwrap();

			Ok(ConnectionMessage::Response(res.clone()))
		},
		_ => panic!("unexpected connection message. Was waiting for a ConnectionMessage::Request")
	}
}

#[test]
fn can_wrap_request_and_response_in_connection_message() {
	let correlation_id = 42;

	//Create a request message
	let req = ApiRequestMessage {
		request: MyRequest {
			id: 1,
			content: "my request content".to_string()
		},
		api_key: 1,
		api_version: 1,
		correlation_id: correlation_id,
		client_id: "some id".to_string()
	};

	//Create a channel to send and receive the response on
	let (tx, rx) = mpsc::channel();

	//Create a request, and pass in the channel
	//This takes ownership of the request, which is no longer 'valid' once it's been sent
	let handle = thread::spawn(move || {
		respond(ConnectionMessage::Request(tx, req)).unwrap();
	});

	//Wait for a response to be received
	let res = rx.recv().unwrap();
	handle.join().unwrap();

	assert!(res.correlation_id == correlation_id);
}<commit_msg>Update mod.rs<commit_after>extern crate kafka;

use std::sync::Arc;
use std::sync::mpsc;
use std::thread;
use std::io::Error;

use kafka::protocol::*;
use kafka::connection::tcp_connection::ConnectionMessage;

use ::fixtures::*;

//TODO: Make this loop able to work on accepting non-generic enums
//Receives a request message and sends a response message with the same correlation id
pub fn respond(req: ConnectionMessage<MyRequest, MyResponse>) -> Result<ConnectionMessage<MyRequest, MyResponse>, Error> {
	match req {
		ConnectionMessage::Request::<MyRequest, MyResponse>(tx, req) => {
			let res = Arc::new(ApiResponseMessage {
				response: MyResponse {
					id: req.request.id,
					content: "my response content".to_string()
				},
				correlation_id: req.correlation_id
			});

			tx.send(res.clone()).unwrap();

			Ok(ConnectionMessage::Response(res.clone()))
		},
		_ => panic!("unexpected connection message. Was waiting for a ConnectionMessage::Request")
	}
}

#[test]
fn can_wrap_request_and_response_in_connection_message() {
	let correlation_id = 42;

	//Create a request message
	let req = ApiRequestMessage {
		request: MyRequest {
			id: 1,
			content: "my request content".to_string()
		},
		api_key: 1,
		api_version: 1,
		correlation_id: correlation_id,
		client_id: "some id".to_string()
	};

	//Create a channel to send and receive the response on
	let (tx, rx) = mpsc::channel();

	//Create a request, and pass in the channel
	//This takes ownership of the request, which is no longer 'valid' once it's been sent
	let handle = thread::spawn(move || {
		respond(ConnectionMessage::Request(tx, req)).unwrap();
	});

	//Wait for a response to be received
	let res = rx.recv().unwrap();
	handle.join().unwrap();

	assert!(res.correlation_id == correlation_id);
}
<|endoftext|>