<commit_before>use std::collections::HashMap;
use std::collections::hash_map;
use tensor::*;
use autograd::variable::Variable;
use nn::Parameter;

// placeholder
struct TorchBackend {}

pub trait ModuleStruct {
    fn init_module(&mut self);
}

pub struct Module<T> {
    pub _name: String,
    pub training: bool,
    _backend: TorchBackend,

    _buffers: HashMap<String, Tensor<T>>,
    //	_backward_hooks:
    //	_forward_hooks:
    _params: HashMap<String, *mut Parameter<T>>,
    _modules: HashMap<String, *mut Module<T>>,
}
pub struct PtrIterMut<'a, T: 'a> {
    //mod_iter: linked_hash_map::IterMut<'a, &'a str, *mut T>,
    mod_iter: hash_map::IterMut<'a, String, *mut T>,
}
pub struct PtrIter<'a, T: 'a> {
    //mod_iter: linked_hash_map::IterMut<'a, &'a str, *mut T>,
    mod_iter: hash_map::Iter<'a, String, *mut T>,
}

impl<'a, T> Iterator for PtrIterMut<'a, T> {
    type Item = (&'a String, &'a mut T);
    fn next(&mut self) -> Option<Self::Item> {
        if let Some((name, t)) = self.mod_iter.next() {
            Some((name, unsafe { &mut **t as &mut T }))
        } else {
            None
        }
    }
}

impl<'a, T> Iterator for PtrIter<'a, T> {
    type Item = (&'a str, &'a T);
    fn next(&mut self) -> Option<Self::Item> {
        if let Some((name, t)) = self.mod_iter.next() {
            Some((name, unsafe { &**t as &T }))
        } else {
            None
        }
    }
}

impl<T> Module<T> {
    pub fn new() -> Module<T> {
        Module {
            _name: String::from(""),
            _backend: TorchBackend {},
            _buffers: HashMap::new(),
            _params: HashMap::new(),
            _modules: HashMap::new(),
            training: true,
        }
    }
    #[inline]
    fn as_mut_ptr(&mut self) -> *mut Module<T> {
        self as *mut Module<T>
    }
    pub fn add_module(&mut self, module: &mut ModIntf<T>) {
        let m = module.delegate();
        self._modules.insert(m._name.clone(), m.as_mut_ptr());

    }
    pub fn add_param(&mut self, name: &str, param: &mut Parameter<T>) {
        let s = String::from(name);
        self._params.insert(s, param.as_mut_ptr());

    }
    pub fn modules_iter_mut(&mut self) -> PtrIterMut<Module<T>> {
        PtrIterMut { mod_iter: self._modules.iter_mut() }
    }
    pub fn modules_iter(&mut self) -> PtrIter<Module<T>> {
        PtrIter { mod_iter: self._modules.iter() }
    }
    pub fn params_iter_mut(&mut self) -> PtrIterMut<Parameter<T>> {
        PtrIterMut { mod_iter: self._params.iter_mut() }
    }
    pub fn register_buffer(&mut self, name: &str, tensor: &mut Tensor<T>) {
        self._buffers.insert(String::from(name), tensor.clone());
    }
    fn _apply(&mut self, callback: fn(&mut Tensor<T>)) {
        for (_, module) in self.modules_iter_mut() {
            module._apply(callback)
        }
        for (_, param) in self.params_iter_mut() {
            param.apply(callback)
            /*
			if let Some(g) = p._grad {
					callback(g.data)
			}
			*/
            /* see also _buffers */
        }
    }
    fn apply(&mut self, callback: fn(&mut Self)) {
        for (_, module) in self.modules_iter_mut() {
            module.apply(callback)
        }
        callback(self)
    }
    pub fn repr(&mut self) -> String {
        let mut tmpstr = format!("{} (\n", self._name);
        for (key, module) in self.modules_iter_mut() {
            let modstr = module.repr();
            let modstr = format!("  {}", modstr);
            tmpstr = format!("{} ({}): {}\n", tmpstr, key, modstr);
        }
        tmpstr = format!("{})", tmpstr);
        tmpstr
    }
    pub fn eval(&mut self) {
        self.train(false)
    }
    fn train(&mut self, mode: bool) {
        self.training = mode;
        for (_, module) in self.modules_iter_mut() {
            module.train(mode)
        }

    }
}

pub trait ModIntf<T> {
    fn delegate(&mut self) -> &mut Module<T>;
    fn forward(&mut self, input: &mut Variable<T>) -> Variable<T>;
    fn forwardv(&mut self, input: &mut Vec<Variable<T>>) -> Vec<Variable<T>>;
    fn f(&mut self, input: &mut Variable<T>) -> Variable<T> {
        {
            let mut m = self.delegate();
            // do pre-forward hooks
        }
        let output = self.forward(input);
        {
            let mut m = self.delegate();
            // do post-forward hooks
        }
        output
    }
    fn fv(&mut self, input: &mut Vec<Variable<T>>) -> Vec<Variable<T>> {
        {
            let mut m = self.delegate();
            // do pre-forward hooks
        }
        let output = self.forwardv(input);
        {
            let mut m = self.delegate();
            // do post-forward hooks
        }
        output
    }
}
<commit_msg>add train / eval functions<commit_after>use std::collections::HashMap;
use std::collections::hash_map;
use tensor::*;
use autograd::variable::Variable;
use nn::Parameter;

// placeholder
struct TorchBackend {}

pub trait ModuleStruct {
    fn init_module(&mut self);
}

pub struct Module<T> {
    pub _name: String,
    pub training: bool,
    _backend: TorchBackend,

    _buffers: HashMap<String, Tensor<T>>,
    //	_backward_hooks:
    //	_forward_hooks:
    _params: HashMap<String, *mut Parameter<T>>,
    _modules: HashMap<String, *mut Module<T>>,
}
pub struct PtrIterMut<'a, T: 'a> {
    //mod_iter: linked_hash_map::IterMut<'a, &'a str, *mut T>,
    mod_iter: hash_map::IterMut<'a, String, *mut T>,
}
pub struct PtrIter<'a, T: 'a> {
    //mod_iter: linked_hash_map::IterMut<'a, &'a str, *mut T>,
    mod_iter: hash_map::Iter<'a, String, *mut T>,
}

impl<'a, T> Iterator for PtrIterMut<'a, T> {
    type Item = (&'a String, &'a mut T);
    fn next(&mut self) -> Option<Self::Item> {
        if let Some((name, t)) = self.mod_iter.next() {
            Some((name, unsafe { &mut **t as &mut T }))
        } else {
            None
        }
    }
}

impl<'a, T> Iterator for PtrIter<'a, T> {
    type Item = (&'a str, &'a T);
    fn next(&mut self) -> Option<Self::Item> {
        if let Some((name, t)) = self.mod_iter.next() {
            Some((name, unsafe { &**t as &T }))
        } else {
            None
        }
    }
}

impl<T> Module<T> {
    pub fn new() -> Module<T> {
        Module {
            _name: String::from(""),
            _backend: TorchBackend {},
            _buffers: HashMap::new(),
            _params: HashMap::new(),
            _modules: HashMap::new(),
            training: true,
        }
    }
    #[inline]
    fn as_mut_ptr(&mut self) -> *mut Module<T> {
        self as *mut Module<T>
    }
    pub fn add_module(&mut self, module: &mut ModIntf<T>) {
        let m = module.delegate();
        self._modules.insert(m._name.clone(), m.as_mut_ptr());

    }
    pub fn add_param(&mut self, name: &str, param: &mut Parameter<T>) {
        let s = String::from(name);
        self._params.insert(s, param.as_mut_ptr());

    }
    pub fn modules_iter_mut(&mut self) -> PtrIterMut<Module<T>> {
        PtrIterMut { mod_iter: self._modules.iter_mut() }
    }
    pub fn modules_iter(&mut self) -> PtrIter<Module<T>> {
        PtrIter { mod_iter: self._modules.iter() }
    }
    pub fn params_iter_mut(&mut self) -> PtrIterMut<Parameter<T>> {
        PtrIterMut { mod_iter: self._params.iter_mut() }
    }
    pub fn register_buffer(&mut self, name: &str, tensor: &mut Tensor<T>) {
        self._buffers.insert(String::from(name), tensor.clone());
    }
    fn _apply(&mut self, callback: fn(&mut Tensor<T>)) {
        for (_, module) in self.modules_iter_mut() {
            module._apply(callback)
        }
        for (_, param) in self.params_iter_mut() {
            param.apply(callback)
            /*
			if let Some(g) = p._grad {
					callback(g.data)
			}
			*/
            /* see also _buffers */
        }
    }
    fn apply(&mut self, callback: fn(&mut Self)) {
        for (_, module) in self.modules_iter_mut() {
            module.apply(callback)
        }
        callback(self)
    }
    pub fn repr(&mut self) -> String {
        let mut tmpstr = format!("{} (\n", self._name);
        for (key, module) in self.modules_iter_mut() {
            let modstr = module.repr();
            let modstr = format!("  {}", modstr);
            tmpstr = format!("{} ({}): {}\n", tmpstr, key, modstr);
        }
        tmpstr = format!("{})", tmpstr);
        tmpstr
    }
    pub fn eval(&mut self) {
        self.train(false)
    }
    fn train(&mut self, mode: bool) {
        self.training = mode;
        for (_, module) in self.modules_iter_mut() {
            module.train(mode)
        }

    }
}

pub trait ModIntf<T> {
    fn delegate(&mut self) -> &mut Module<T>;
    fn forward(&mut self, input: &mut Variable<T>) -> Variable<T>;
    fn forwardv(&mut self, input: &mut Vec<Variable<T>>) -> Vec<Variable<T>>;
    fn f(&mut self, input: &mut Variable<T>) -> Variable<T> {
        {
            let mut m = self.delegate();
            // do pre-forward hooks
        }
        let output = self.forward(input);
        {
            let mut m = self.delegate();
            // do post-forward hooks
        }
        output
    }
    fn fv(&mut self, input: &mut Vec<Variable<T>>) -> Vec<Variable<T>> {
        {
            let mut m = self.delegate();
            // do pre-forward hooks
        }
        let output = self.forwardv(input);
        {
            let mut m = self.delegate();
            // do post-forward hooks
        }
        output
    }
    fn train(&mut self) {
        self.delegate().train(true)
    }
    fn eval(&mut self) {
        self.delegate().train(false)
    }
}
<|endoftext|>


<commit_before>mod entities;
mod input;
mod updates;
mod util;

use chrono::{DateTime, Duration as OldDuration, Utc};
use log::{error, trace};
use rand_core::{OsRng, RngCore};
use serde_derive::Serialize;
use std::collections::HashMap;
use std::mem;

pub use self::entities::*;
pub use self::input::*;
pub use self::updates::*;
pub use self::util::*;

use crate::server::{ArenaId, ArenaLine, ArenaPoint, Direction, Player, PlayerId};

const ARENA_WIDTH: f64 = 560.0;
const ARENA_HEIGHT: f64 = 560.0;
const ARENA_MAX_PLAYERS: usize = 8;
const ARENA_START_TIMER_SECONDS: i64 = 1;
const LIGHTCYCLE_SPEED: f64 = 55.0;
// const LIGHTCYCLE_BRAKE_SPEED: f64 = 40.0;
// const LIGHTCYCLE_BOOST_SPEED: f64 = 70.0;

#[derive(Debug, Clone, Serialize)]
pub struct Arena {
    pub id: ArenaId,
    pub name: String,
    pub width: f64,
    pub height: f64,
    pub max_players: usize,

    pub started: Option<DateTime<Utc>>,
    pub winner: Option<PlayerId>,

    pub players: HashMap<PlayerId, Player>,
    pub lightcycles: HashMap<PlayerId, Lightcycle>,
    pub lightribbons: HashMap<PlayerId, Lightribbon>,

    #[serde(skip)]
    pub updates: Vec<ArenaUpdate>,
    #[serde(skip)]
    updates_applied_so_far: usize,
}

impl Arena {
    pub fn with_name(name: &str) -> Self {
        Self {
            name: name.to_uppercase(),
            ..Default::default()
        }
    }

    pub fn add_player(&mut self, player: Player) {
        self.updates.push(ArenaUpdate::AddPlayer(player.id, player));
    }

    pub fn remove_player(&mut self, player_id: PlayerId) {
        self.updates.push(ArenaUpdate::RemovePlayer(player_id));
    }

    pub fn clear_updates(&mut self) {
        self.updates.clear();
        self.updates_applied_so_far = 0;
    }

    pub fn apply_updates(&mut self) -> &mut Self {
        let updates = mem::take(&mut self.updates);
        for update in updates.iter().skip(self.updates_applied_so_far) {
            update.apply(self);
            self.updates_applied_so_far += 1;
        }
        self.updates = updates;

        self
    }

    pub fn process_input(&mut self, player_id: PlayerId, input_event: ArenaInput) {
        input_event
            .process_into_updates(self, player_id)
            .drain(..)
            .for_each(|update| self.updates.push(update));
    }

    pub fn update(&mut self, delta_time: f64) {
        // apply process_input updates
        self.apply_updates();

        let started = match self.started {
            Some(started) => started,
            None => return,
        };

        let now = Utc::now();
        if now < started {
            return;
        }

        self.update_lightcycle_positions(delta_time)
            .apply_updates()
            .calculate_lightcycle_collisions(delta_time)
            .apply_updates()
            .update_lightribbon_positions()
            .apply_updates()
            .test_win_condition()
            .apply_updates()
            .test_round_end()
            .apply_updates();
    }

    //
    // update helpers
    //

    fn update_lightcycle_positions(&mut self, delta_time: f64) -> &mut Self {
        for (id, lightcycle) in self.lightcycles.iter() {
            if lightcycle.dead {
                continue;
            };

            self.updates.push(ArenaUpdate::UpdateLightcyclePosition(
                *id,
                lightcycle.position
                    + lightcycle.direction.as_velocity() * lightcycle.speed * delta_time,
            ))
        }
        self
    }

    fn calculate_lightcycle_collisions(&mut self, delta_time: f64) -> &mut Self {
        'next_lightcycle: for (id, lightcycle) in self.lightcycles.iter() {
            if lightcycle.dead {
                continue 'next_lightcycle;
            };

            let last_position = lightcycle.position
                - lightcycle.direction.as_velocity() * lightcycle.speed * delta_time;

            let travelled = ArenaLine {
                from: last_position.to_untyped(),
                to: lightcycle.position.to_untyped(),
            };

            // test for lightribbon collisions
            for lightribbon in self.lightribbons.values() {
                for line in lightribbon.points.windows(2) {
                    let line = ArenaLine {
                        from: line[0].to_untyped(),
                        to: line[1].to_untyped(),
                    };

                    if travelled.overlaps_segment(&line) {
                        self.updates
                            .push(ArenaUpdate::UpdateLightcycleApplyDeath(*id));
                        continue 'next_lightcycle;
                    }

                    if let Some(intersection) = travelled.intersection(&line) {
                        self.updates.push(ArenaUpdate::UpdateLightcyclePosition(
                            *id,
                            ArenaPoint::from_untyped(intersection),
                        ));
                        self.updates
                            .push(ArenaUpdate::UpdateLightcycleApplyDeath(*id));
                        continue 'next_lightcycle;
                    }
                }
            }

            // test for arena bounds collisions
            if lightcycle.position.x < 0.0
                || lightcycle.position.y < 0.0
                || lightcycle.position.x > self.width
                || lightcycle.position.y > self.height
            {
                self.updates
                    .push(ArenaUpdate::UpdateLightcycleApplyDeath(*id));
                continue 'next_lightcycle;
            }

            // test for collisions with other lightcycles
            if self
                .lightcycles
                .iter()
                .filter(|(_, other_lightcycle)| !other_lightcycle.dead)
                .filter(|(other_id, _)| id != *other_id)
                .any(|(_, other_lightcycle)| lightcycle.position == other_lightcycle.position)
            {
                self.updates
                    .push(ArenaUpdate::UpdateLightcycleApplyDeath(*id));
                continue 'next_lightcycle;
            }
        }
        self
    }

    fn update_lightribbon_positions(&mut self) -> &mut Self {
        for id in self.lightribbons.keys() {
            let latest_point = match self.lightcycles.get(id) {
                Some(lightcycle) => {
                    if lightcycle.dead {
                        continue;
                    };

                    lightcycle.position
                }
                None => {
                    error!(
                        "Failed to update lightribbon position: No lightcycle with id {}",
                        id
                    );
                    continue;
                }
            };

            self.updates
                .push(ArenaUpdate::UpdateLightribbonReplaceLatestPoint(
                    *id,
                    latest_point,
                ));
        }
        self
    }

    fn test_win_condition(&mut self) -> &mut Self {
        if self.lightcycles.iter().count() <= 1 {
            return self;
        }

        let mut alive_lightcycles = self
            .lightcycles
            .iter()
            .filter(|(_, lightcycle)| !lightcycle.dead);

        if let (Some((player_id, _)), None) = (alive_lightcycles.next(), alive_lightcycles.next()) {
            self.updates.push(ArenaUpdate::SetWinner(Some(*player_id)));
        }

        self
    }

    fn test_round_end(&mut self) -> &mut Self {
        if self.lightcycles.values().all(|lightcycle| lightcycle.dead) {
            self.updates.push(ArenaUpdate::End);
        }
        self
    }
}

impl Default for Arena {
    fn default() -> Self {
        Self {
            id: Default::default(),
            name: Default::default(),
            width: ARENA_WIDTH,
            height: ARENA_HEIGHT,
            max_players: ARENA_MAX_PLAYERS,

            started: None,
            winner: None,

            players: Default::default(),
            lightcycles: Default::default(),
            lightribbons: Default::default(),

            updates: Default::default(),
            updates_applied_so_far: 0,
        }
    }
}

/// ArenaOverview represents an overview of an Arena for the arena selection screen.
#[derive(Debug, Clone, Serialize)]
pub struct ArenaOverview {
    id: ArenaId,
    name: String,
    max_players: usize,
    started: Option<DateTime<Utc>>,
    players: HashMap<PlayerId, Player>,
}

impl From<&Arena> for ArenaOverview {
    fn from(arena: &Arena) -> Self {
        Self {
            id: arena.id,
            name: arena.name.clone(),
            max_players: arena.max_players,
            started: arena.started,
            players: arena.players.clone(),
        }
    }
}
<commit_msg>fixed win condition firing every update<commit_after>mod entities;
mod input;
mod updates;
mod util;

use chrono::{DateTime, Duration as OldDuration, Utc};
use log::{error, trace};
use rand_core::{OsRng, RngCore};
use serde_derive::Serialize;
use std::collections::HashMap;
use std::mem;

pub use self::entities::*;
pub use self::input::*;
pub use self::updates::*;
pub use self::util::*;

use crate::server::{ArenaId, ArenaLine, ArenaPoint, Direction, Player, PlayerId};

const ARENA_WIDTH: f64 = 560.0;
const ARENA_HEIGHT: f64 = 560.0;
const ARENA_MAX_PLAYERS: usize = 8;
const ARENA_START_TIMER_SECONDS: i64 = 1;
const LIGHTCYCLE_SPEED: f64 = 55.0;
// const LIGHTCYCLE_BRAKE_SPEED: f64 = 40.0;
// const LIGHTCYCLE_BOOST_SPEED: f64 = 70.0;

#[derive(Debug, Clone, Serialize)]
pub struct Arena {
    pub id: ArenaId,
    pub name: String,
    pub width: f64,
    pub height: f64,
    pub max_players: usize,

    pub started: Option<DateTime<Utc>>,
    pub winner: Option<PlayerId>,

    pub players: HashMap<PlayerId, Player>,
    pub lightcycles: HashMap<PlayerId, Lightcycle>,
    pub lightribbons: HashMap<PlayerId, Lightribbon>,

    #[serde(skip)]
    pub updates: Vec<ArenaUpdate>,
    #[serde(skip)]
    updates_applied_so_far: usize,
}

impl Arena {
    pub fn with_name(name: &str) -> Self {
        Self {
            name: name.to_uppercase(),
            ..Default::default()
        }
    }

    pub fn add_player(&mut self, player: Player) {
        self.updates.push(ArenaUpdate::AddPlayer(player.id, player));
    }

    pub fn remove_player(&mut self, player_id: PlayerId) {
        self.updates.push(ArenaUpdate::RemovePlayer(player_id));
    }

    pub fn clear_updates(&mut self) {
        self.updates.clear();
        self.updates_applied_so_far = 0;
    }

    pub fn apply_updates(&mut self) -> &mut Self {
        let updates = mem::take(&mut self.updates);
        for update in updates.iter().skip(self.updates_applied_so_far) {
            update.apply(self);
            self.updates_applied_so_far += 1;
        }
        self.updates = updates;

        self
    }

    pub fn process_input(&mut self, player_id: PlayerId, input_event: ArenaInput) {
        input_event
            .process_into_updates(self, player_id)
            .drain(..)
            .for_each(|update| self.updates.push(update));
    }

    pub fn update(&mut self, delta_time: f64) {
        // apply process_input updates
        self.apply_updates();

        let started = match self.started {
            Some(started) => started,
            None => return,
        };

        let now = Utc::now();
        if now < started {
            return;
        }

        self.update_lightcycle_positions(delta_time)
            .apply_updates()
            .calculate_lightcycle_collisions(delta_time)
            .apply_updates()
            .update_lightribbon_positions()
            .apply_updates()
            .test_win_condition()
            .apply_updates()
            .test_round_end()
            .apply_updates();
    }

    //
    // update helpers
    //

    fn update_lightcycle_positions(&mut self, delta_time: f64) -> &mut Self {
        for (id, lightcycle) in self.lightcycles.iter() {
            if lightcycle.dead {
                continue;
            };

            self.updates.push(ArenaUpdate::UpdateLightcyclePosition(
                *id,
                lightcycle.position
                    + lightcycle.direction.as_velocity() * lightcycle.speed * delta_time,
            ))
        }
        self
    }

    fn calculate_lightcycle_collisions(&mut self, delta_time: f64) -> &mut Self {
        'next_lightcycle: for (id, lightcycle) in self.lightcycles.iter() {
            if lightcycle.dead {
                continue 'next_lightcycle;
            };

            let last_position = lightcycle.position
                - lightcycle.direction.as_velocity() * lightcycle.speed * delta_time;

            let travelled = ArenaLine {
                from: last_position.to_untyped(),
                to: lightcycle.position.to_untyped(),
            };

            // test for lightribbon collisions
            for lightribbon in self.lightribbons.values() {
                for line in lightribbon.points.windows(2) {
                    let line = ArenaLine {
                        from: line[0].to_untyped(),
                        to: line[1].to_untyped(),
                    };

                    if travelled.overlaps_segment(&line) {
                        self.updates
                            .push(ArenaUpdate::UpdateLightcycleApplyDeath(*id));
                        continue 'next_lightcycle;
                    }

                    if let Some(intersection) = travelled.intersection(&line) {
                        self.updates.push(ArenaUpdate::UpdateLightcyclePosition(
                            *id,
                            ArenaPoint::from_untyped(intersection),
                        ));
                        self.updates
                            .push(ArenaUpdate::UpdateLightcycleApplyDeath(*id));
                        continue 'next_lightcycle;
                    }
                }
            }

            // test for arena bounds collisions
            if lightcycle.position.x < 0.0
                || lightcycle.position.y < 0.0
                || lightcycle.position.x > self.width
                || lightcycle.position.y > self.height
            {
                self.updates
                    .push(ArenaUpdate::UpdateLightcycleApplyDeath(*id));
                continue 'next_lightcycle;
            }

            // test for collisions with other lightcycles
            if self
                .lightcycles
                .iter()
                .filter(|(_, other_lightcycle)| !other_lightcycle.dead)
                .filter(|(other_id, _)| id != *other_id)
                .any(|(_, other_lightcycle)| lightcycle.position == other_lightcycle.position)
            {
                self.updates
                    .push(ArenaUpdate::UpdateLightcycleApplyDeath(*id));
                continue 'next_lightcycle;
            }
        }
        self
    }

    fn update_lightribbon_positions(&mut self) -> &mut Self {
        for id in self.lightribbons.keys() {
            let latest_point = match self.lightcycles.get(id) {
                Some(lightcycle) => {
                    if lightcycle.dead {
                        continue;
                    };

                    lightcycle.position
                }
                None => {
                    error!(
                        "Failed to update lightribbon position: No lightcycle with id {}",
                        id
                    );
                    continue;
                }
            };

            self.updates
                .push(ArenaUpdate::UpdateLightribbonReplaceLatestPoint(
                    *id,
                    latest_point,
                ));
        }
        self
    }

    fn test_win_condition(&mut self) -> &mut Self {
        if self.winner.is_some() {
            return self;
        }

        if self.lightcycles.iter().count() <= 1 {
            return self;
        }

        let mut alive_lightcycles = self
            .lightcycles
            .iter()
            .filter(|(_, lightcycle)| !lightcycle.dead);

        if let (Some((player_id, _)), None) = (alive_lightcycles.next(), alive_lightcycles.next()) {
            self.updates.push(ArenaUpdate::SetWinner(Some(*player_id)));
        }

        self
    }

    fn test_round_end(&mut self) -> &mut Self {
        if self.lightcycles.values().all(|lightcycle| lightcycle.dead) {
            self.updates.push(ArenaUpdate::End);
        }
        self
    }
}

impl Default for Arena {
    fn default() -> Self {
        Self {
            id: Default::default(),
            name: Default::default(),
            width: ARENA_WIDTH,
            height: ARENA_HEIGHT,
            max_players: ARENA_MAX_PLAYERS,

            started: None,
            winner: None,

            players: Default::default(),
            lightcycles: Default::default(),
            lightribbons: Default::default(),

            updates: Default::default(),
            updates_applied_so_far: 0,
        }
    }
}

/// ArenaOverview represents an overview of an Arena for the arena selection screen.
#[derive(Debug, Clone, Serialize)]
pub struct ArenaOverview {
    id: ArenaId,
    name: String,
    max_players: usize,
    started: Option<DateTime<Utc>>,
    players: HashMap<PlayerId, Player>,
}

impl From<&Arena> for ArenaOverview {
    fn from(arena: &Arena) -> Self {
        Self {
            id: arena.id,
            name: arena.name.clone(),
            max_players: arena.max_players,
            started: arena.started,
            players: arena.players.clone(),
        }
    }
}
<|endoftext|>


<commit_before>extern crate time;
extern crate url;
extern crate rand;

use self::url::{FORM_URLENCODED_ENCODE_SET, utf8_percent_encode};
use self::time::now_utc;
use self::rand::{OsRng, Rng};
use std::fmt;

pub mod session;
pub mod temporary_credentials;

#[derive(Copy, Debug, PartialEq, Eq, Clone)]
#[unstable]
pub enum HTTPMethod {
    GET,
    POST,
    DELETE,
    PUT,
    HEAD
}

impl fmt::Display for HTTPMethod {
    fn fmt(&self, f : &mut fmt::Formatter) -> fmt::Result{
        let out = match *self {
            HTTPMethod::GET     => {"GET"},
            HTTPMethod::POST    => {"POST"},
            HTTPMethod::DELETE  => {"DELETE"},
            HTTPMethod::PUT     => {"PUT"},
            HTTPMethod::HEAD   => {"HEAD"}
        };
        write!(f, "{}", out)
    }
}

pub trait AuthorizationHeader {
    fn get_header(&self) -> String;
}

// TODO: add to crypto library?
// TODO: Should we have a longer nonce than 10?
fn generate_nonce() -> String {
    OsRng::new().unwrap()
                .gen_ascii_chars()
                .take(10)
                .collect()
}

fn generate_timestamp() -> String{
    now_utc().to_timespec().sec.to_string()
}

pub trait BaseString {
    // Returns a base string URI, ecnoded with [RFC3986]. This gets used to
    // generate the `oauth_signature`. It takes a different path dependent
    // on the signature type
    fn get_base_string(&self, method: HTTPMethod, base_url: &str, data: Vec<(&str, &str)>) -> String {
        format!("{}&{}&{}", method,
                utf8_percent_encode(base_url.as_slice(), FORM_URLENCODED_ENCODE_SET),
                utf8_percent_encode(self.get_base_parameters(data).as_slice(), FORM_URLENCODED_ENCODE_SET))
    }

    fn get_self_paramaters(&self) -> Vec<String>;

    fn get_base_parameters(&self, data: Vec<(&str, &str)>) -> String {
        let to_pair = |&: (key, value) : (&str, &str) | -> String {
            format!("{}={}", key, value)};

        let mut params = self.get_self_paramaters();
        params.append(&mut (data.into_iter().map(to_pair).collect::<Vec<String>>()));
        params.sort();
        concat(params.as_slice(), "&")
    }
}

/// Concatenate all values in `data`, seperated by `sep`
///
/// ```
/// use rust_oauth::oauth1::client::concat;
/// let values = vec!["cat".to_string(), "dog".to_string(), "bird".to_string()];
/// let concatenated = concat(values.as_slice(), " ");
/// assert_eq!(concatenated, "cat dog bird".to_string());
/// ```
pub fn concat(data: &[String], sep : &str) -> String {
    match data {
        []              => String::new(),
        [ref param]         => format!("{}", param),
        [ref param, rest..]  => format!("{}{}{}", param, sep, concat(rest, sep))
    }
}

#[cfg(test)]
mod test {
    use super::{concat, generate_nonce};

    #[test]
    fn concat_test_multiple_items() {
        let data = vec!["alpha".to_string(), "beta".to_string(), "gamma".to_string()];
        assert_eq!(concat(data.as_slice(), "&"), "alpha&beta&gamma".to_string())
    }

    #[test]
    fn concat_test_empty_vec() {
        let data = vec![];
        assert_eq!(concat(data.as_slice(), "&"), String::new())
    }

    #[test]
    fn concat_test_single() {
        let data = vec!["alpha".to_string()];
        assert_eq!(concat(data.as_slice(), "&"), "alpha".to_string())
    }

    #[test]
    fn generate_nonce_unique(){
        let mut nonces = Vec::new();
        for _ in 0..1000 {
            nonces.push(generate_nonce())
        }
        let len = nonces.len();
        nonces.dedup();
        assert_eq!(len, nonces.len());
    }
}
<commit_msg>changed nonce length to 32<commit_after>extern crate time;
extern crate url;
extern crate rand;

use self::url::{FORM_URLENCODED_ENCODE_SET, utf8_percent_encode};
use self::time::now_utc;
use self::rand::{OsRng, Rng};
use std::fmt;

pub mod session;
pub mod temporary_credentials;

#[derive(Copy, Debug, PartialEq, Eq, Clone)]
#[unstable]
pub enum HTTPMethod {
    GET,
    POST,
    DELETE,
    PUT,
    HEAD
}

impl fmt::Display for HTTPMethod {
    fn fmt(&self, f : &mut fmt::Formatter) -> fmt::Result{
        let out = match *self {
            HTTPMethod::GET     => {"GET"},
            HTTPMethod::POST    => {"POST"},
            HTTPMethod::DELETE  => {"DELETE"},
            HTTPMethod::PUT     => {"PUT"},
            HTTPMethod::HEAD   => {"HEAD"}
        };
        write!(f, "{}", out)
    }
}

pub trait AuthorizationHeader {
    fn get_header(&self) -> String;
}

// TODO: add to crypto library?
// TODO: Should we have a longer nonce than 10?
fn generate_nonce() -> String {
    OsRng::new().unwrap()
                .gen_ascii_chars()
                .take(32)
                .collect()
}

fn generate_timestamp() -> String{
    now_utc().to_timespec().sec.to_string()
}

pub trait BaseString {
    // Returns a base string URI, ecnoded with [RFC3986]. This gets used to
    // generate the `oauth_signature`. It takes a different path dependent
    // on the signature type
    fn get_base_string(&self, method: HTTPMethod, base_url: &str, data: Vec<(&str, &str)>) -> String {
        format!("{}&{}&{}", method,
                utf8_percent_encode(base_url.as_slice(), FORM_URLENCODED_ENCODE_SET),
                utf8_percent_encode(self.get_base_parameters(data).as_slice(), FORM_URLENCODED_ENCODE_SET))
    }

    fn get_self_paramaters(&self) -> Vec<String>;

    fn get_base_parameters(&self, data: Vec<(&str, &str)>) -> String {
        let to_pair = |&: (key, value) : (&str, &str) | -> String {
            format!("{}={}", key, value)};

        let mut params = self.get_self_paramaters();
        params.append(&mut (data.into_iter().map(to_pair).collect::<Vec<String>>()));
        params.sort();
        concat(params.as_slice(), "&")
    }
}

/// Concatenate all values in `data`, seperated by `sep`
///
/// ```
/// use rust_oauth::oauth1::client::concat;
/// let values = vec!["cat".to_string(), "dog".to_string(), "bird".to_string()];
/// let concatenated = concat(values.as_slice(), " ");
/// assert_eq!(concatenated, "cat dog bird".to_string());
/// ```
pub fn concat(data: &[String], sep : &str) -> String {
    match data {
        []              => String::new(),
        [ref param]         => format!("{}", param),
        [ref param, rest..]  => format!("{}{}{}", param, sep, concat(rest, sep))
    }
}

#[cfg(test)]
mod test {
    use super::{concat, generate_nonce};

    #[test]
    fn concat_test_multiple_items() {
        let data = vec!["alpha".to_string(), "beta".to_string(), "gamma".to_string()];
        assert_eq!(concat(data.as_slice(), "&"), "alpha&beta&gamma".to_string())
    }

    #[test]
    fn concat_test_empty_vec() {
        let data = vec![];
        assert_eq!(concat(data.as_slice(), "&"), String::new())
    }

    #[test]
    fn concat_test_single() {
        let data = vec!["alpha".to_string()];
        assert_eq!(concat(data.as_slice(), "&"), "alpha".to_string())
    }

    #[test]
    fn generate_nonce_unique(){
        let mut nonces = Vec::new();
        for _ in 0..1000 {
            nonces.push(generate_nonce())
        }
        let len = nonces.len();
        nonces.dedup();
        assert_eq!(len, nonces.len());
    }
}
<|endoftext|>


<commit_before>#![crate_name = "platform"]
#![crate_type = "rlib"]
#![no_std]
#![feature(core_intrinsics,lang_items)]

extern crate hotel;
extern crate hil;
extern crate support;

pub struct Firestorm;

macro_rules! static_init {
   ($V:ident : $T:ty = $e:expr) => {
        let $V : &mut $T = {
            use core::mem::transmute;
            // Waiting out for size_of to be available at compile-time to avoid
            // hardcoding an abitrary large size...
            static mut BUF : [u8; 1024] = [0; 1024];
            let mut tmp : &mut $T = transmute(&mut BUF);
            *tmp = $e;
            tmp
        };
   }
}

const LED : u32 = 0;
const LED_GPIO : u16 = 1;

pub unsafe fn init<'a>() -> &'a mut Firestorm {
    use core::intrinsics::{volatile_load,volatile_store};
    use hotel::pmu::*;

    let uart_clock =
            Clock::new(PeripheralClock::Bank1(PeripheralClock1::Uart0Timer));
    let gpio_clock =
            Clock::new(PeripheralClock::Bank0(PeripheralClock0::Gpio0));

    /* ********************
     * UART
     * ********************/

    // Turn on UART0 clock
    uart_clock.enable();

    // Drive DIOA0 from TX
    let pinmux_dioa0_sel : *mut u16 = 0x40060028 as *mut u16;
    volatile_store(pinmux_dioa0_sel, 70);

    // Setup baud rate
    let nco = 5300; // 2^20 * 115200 / 24000000
    let uart_nco : *mut u16 = 0x40600008 as *mut u16;
    volatile_store(uart_nco, nco);

    // Enable TX
    let uart_ctrl : *mut u16 = 0x4060000C as *mut u16;
    volatile_store(uart_ctrl, 1);

    unsafe fn write_char(c : char) {
        let uart_state : *mut u32 = 0x40600014 as *mut u32;
        let uart_wdata : *mut u8 = 0x40600004 as *mut u8;

        while volatile_load(uart_state) & 1 != 0 {}

        volatile_store(uart_wdata, c as u8);
    }

    unsafe fn write_str(s : &str) {
        for c in s.chars() {
            write_char(c);
        }
    }

    write_str("Hello from Rust!\n");

    /* ********************
     * Blink
     * ********************/

    // Turn on GPIO clocks
    gpio_clock.enable();

    // Driver DIOM4 from GPIO0_0
    let pinmux_diom4_sel : *mut u16 = 0x40060020 as *mut u16;
    volatile_store(pinmux_diom4_sel, LED_GPIO);

    // Enable output on GPIO0_0
    let gpio0_outen : *mut u32 = 0x40200010 as *mut u32;
    volatile_store(gpio0_outen, 1 << LED);

    // Set GPIO0_0
    let gpio0_out : *mut u32 = 0x40200004 as *mut u32;
    volatile_store(gpio0_out, 1 << LED);

    loop {
        for _ in 0..3000000 {
            support::nop();
        }
        volatile_store(gpio0_out, 0 << LED);
        for _ in 0..3000000 {
            support::nop();
        }
        volatile_store(gpio0_out, 1 << LED);
    }

    static_init!(firestorm : Firestorm = Firestorm);
    firestorm
}

impl Firestorm {
    pub unsafe fn service_pending_interrupts(&mut self) {
    }

    pub unsafe fn has_pending_interrupts(&mut self) -> bool {
        // FIXME: The wfi call from main() blocks forever if no interrupts are generated. For now,
        // pretend we have interrupts to avoid blocking.
        true
    }

    #[inline(never)]
    pub fn with_driver<F, R>(&mut self, driver_num: usize, f: F) -> R where
            F: FnOnce(Option<&hil::Driver>) -> R {
        match driver_num {
            //1 => f(Some(self.gpio)),
            _ => f(None)
        }
    }
}

use core::fmt::Arguments;
#[cfg(not(test))]
#[lang="panic_fmt"]
#[no_mangle]
pub unsafe extern fn rust_begin_unwind(_args: &Arguments,
    _file: &'static str, _line: usize) -> ! {
    loop {}
}
<commit_msg>Hotel: Use GPIO Module in lib.rs<commit_after>#![crate_name = "platform"]
#![crate_type = "rlib"]
#![no_std]
#![feature(core_intrinsics,lang_items)]

extern crate hotel;
extern crate hil;
extern crate support;

pub struct Firestorm;

macro_rules! static_init {
   ($V:ident : $T:ty = $e:expr) => {
        let $V : &mut $T = {
            use core::mem::transmute;
            // Waiting out for size_of to be available at compile-time to avoid
            // hardcoding an abitrary large size...
            static mut BUF : [u8; 1024] = [0; 1024];
            let mut tmp : &mut $T = transmute(&mut BUF);
            *tmp = $e;
            tmp
        };
   }
}

const LED : u32 = 0;
const LED_GPIO : u16 = 1;

pub unsafe fn init<'a>() -> &'a mut Firestorm {
    use core::intrinsics::{volatile_load,volatile_store};
    use hotel::pmu::*;
    use hotel::gpio;

    let uart_clock =
            Clock::new(PeripheralClock::Bank1(PeripheralClock1::Uart0Timer));
    let gpio_clock =
            Clock::new(PeripheralClock::Bank0(PeripheralClock0::Gpio0));

    // Drive DIOA0 from TX
    let pinmux_dioa0_sel : *mut u16 = 0x40060028 as *mut u16;
    volatile_store(pinmux_dioa0_sel, 70);

    // Drive DIOM4 from GPIO0_0
    let pinmux_diom4_sel : *mut u16 = 0x40060020 as *mut u16;
    volatile_store(pinmux_diom4_sel, LED_GPIO);

    /* ********************
     * UART
     * ********************/

    // Turn on UART0 clock
    uart_clock.enable();

    // Setup baud rate
    let nco = 5300; // 2^20 * 115200 / 24000000
    let uart_nco : *mut u16 = 0x40600008 as *mut u16;
    volatile_store(uart_nco, nco);

    // Enable TX
    let uart_ctrl : *mut u16 = 0x4060000C as *mut u16;
    volatile_store(uart_ctrl, 1);

    unsafe fn write_char(c : char) {
        let uart_state : *mut u32 = 0x40600014 as *mut u32;
        let uart_wdata : *mut u8 = 0x40600004 as *mut u8;

        while volatile_load(uart_state) & 1 != 0 {}

        volatile_store(uart_wdata, c as u8);
    }

    unsafe fn write_str(s : &str) {
        for c in s.chars() {
            write_char(c);
        }
    }

    write_str("Hello from Rust!\n");

    /* ********************
     * Blink
     * ********************/

    // Turn on GPIO clocks
    gpio_clock.enable();

    let led = &gpio::GPIOPin::new(gpio::GPIO0_BASE, gpio::Pin::P0);

    led.enable_output();

    loop {
        for _ in 0..3000000 {
            support::nop();
        }
        led.toggle();
    }

    static_init!(firestorm : Firestorm = Firestorm);
    firestorm
}

impl Firestorm {
    pub unsafe fn service_pending_interrupts(&mut self) {
    }

    pub unsafe fn has_pending_interrupts(&mut self) -> bool {
        // FIXME: The wfi call from main() blocks forever if no interrupts are generated. For now,
        // pretend we have interrupts to avoid blocking.
        true
    }

    #[inline(never)]
    pub fn with_driver<F, R>(&mut self, driver_num: usize, f: F) -> R where
            F: FnOnce(Option<&hil::Driver>) -> R {
        match driver_num {
            //1 => f(Some(self.gpio)),
            _ => f(None)
        }
    }
}

use core::fmt::Arguments;
#[cfg(not(test))]
#[lang="panic_fmt"]
#[no_mangle]
pub unsafe extern fn rust_begin_unwind(_args: &Arguments,
    _file: &'static str, _line: usize) -> ! {
    loop {}
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;

extern crate pretty_env_logger;

extern crate clap;
extern crate cabot;

use std::io;
use std::io::Write;
use std::fs::File;

use clap::{App, Arg};

use cabot::results::{CabotResult, CabotError};
use cabot::http;
use cabot::request::RequestBuilder;

const VERSION: &'static str = "0.1.0";

pub fn run() -> CabotResult<()> {
    let matches = App::new("cabot")
        .version(VERSION)
        .author("Guillaume Gauvrit <guillaume@gauvr.it>")
        .about("http(s) client")
        .arg(Arg::with_name("URL")
            .index(1)
            .required(true)
            .help("URL to request"))
        .arg(Arg::with_name("REQUEST")
            .short("X")
            .long("request")
            .default_value("GET")
            .help("Specify request command to use"))
        .arg(Arg::with_name("LINE")
            .short("H")
            .long("header")
            .takes_value(true)
            .multiple(true)
            .help("Pass custom header LINE to server"))
        .arg(Arg::with_name("FILE")
            .short("o")
            .long("output")
            .takes_value(true)
            .help("Write to FILE instead of stdout"))
        .arg(Arg::with_name("VERBOSE")
            .short("v")
            .long("verbose")
            .help("Make the operation more talkative"))
        .get_matches();

    let url = matches.value_of("URL").unwrap();
    let http_method = matches.value_of("REQUEST").unwrap();
    let verbose = matches.is_present("VERBOSE");

    let headers: Vec<&str> = match matches.values_of("LINE") {
        Some(headers) => headers.collect(),
        None => Vec::new(),
    };

    let request = RequestBuilder::new(url).set_http_method(http_method)
        .add_headers(&headers.as_slice())
        .build()?;

    if let Some(path) = matches.value_of("FILE") {
        let mut f = File::create(path).unwrap();
        http::http_query(&request, &mut f, verbose)?;
    } else {
        http::http_query(&request, &mut io::stdout(), verbose)?;
    };

    Ok(())
}

fn main() {
    pretty_env_logger::init().unwrap();
    debug!("Starting cabot");
    match run() {
        Ok(()) => {
            debug!("Command cabot ended succesfully");
        }
        Err(CabotError::SchemeError(scheme)) => {
            let _ = writeln!(&mut std::io::stderr(), "Unamanaged scheme: {}", scheme);
            std::process::exit(1);
        }
        Err(CabotError::OpaqueUrlError(err)) => {
            let _ = writeln!(&mut std::io::stderr(), "Opaque URL Error:{}", err);
            std::process::exit(1);
        }
        Err(CabotError::UrlParseError(err)) => {
            let _ = writeln!(&mut std::io::stderr(), "URL Parse Error:{}", err);
            std::process::exit(1);
        }
        Err(CabotError::IOError(err)) => {
            let _ = writeln!(&mut std::io::stderr(), "IOError:{}", err);
            std::process::exit(1);
        }
        Err(CabotError::CertificateError(err)) => {
            let _ = writeln!(&mut std::io::stderr(), "CertificateError: {}", err);
            std::process::exit(1);
        }
    }
}
<commit_msg>Use OpenOptions for the output file<commit_after>#[macro_use]
extern crate log;

extern crate pretty_env_logger;

extern crate clap;
extern crate cabot;

use std::io;
use std::io::Write;
use std::fs::OpenOptions;
use std::io::prelude::*;

use clap::{App, Arg};

use cabot::results::{CabotResult, CabotError};
use cabot::http;
use cabot::request::RequestBuilder;

const VERSION: &'static str = "0.1.0";

pub fn run() -> CabotResult<()> {
    let matches = App::new("cabot")
        .version(VERSION)
        .author("Guillaume Gauvrit <guillaume@gauvr.it>")
        .about("http(s) client")
        .arg(Arg::with_name("URL")
            .index(1)
            .required(true)
            .help("URL to request"))
        .arg(Arg::with_name("REQUEST")
            .short("X")
            .long("request")
            .default_value("GET")
            .help("Specify request command to use"))
        .arg(Arg::with_name("LINE")
            .short("H")
            .long("header")
            .takes_value(true)
            .multiple(true)
            .help("Pass custom header LINE to server"))
        .arg(Arg::with_name("FILE")
            .short("o")
            .long("output")
            .takes_value(true)
            .help("Write to FILE instead of stdout"))
        .arg(Arg::with_name("VERBOSE")
            .short("v")
            .long("verbose")
            .help("Make the operation more talkative"))
        .get_matches();

    let url = matches.value_of("URL").unwrap();
    let http_method = matches.value_of("REQUEST").unwrap();
    let verbose = matches.is_present("VERBOSE");

    let headers: Vec<&str> = match matches.values_of("LINE") {
        Some(headers) => headers.collect(),
        None => Vec::new(),
    };

    let request = RequestBuilder::new(url).set_http_method(http_method)
        .add_headers(&headers.as_slice())
        .build()?;

    if let Some(path) = matches.value_of("FILE") {
        let mut f = OpenOptions::new()
            .write(true)
            .create(true)
            .truncate(true)
            .open(path).unwrap();
        http::http_query(&request, &mut f, verbose)?;
    } else {
        http::http_query(&request, &mut io::stdout(), verbose)?;
    };

    Ok(())
}

fn main() {
    pretty_env_logger::init().unwrap();
    debug!("Starting cabot");
    match run() {
        Ok(()) => {
            debug!("Command cabot ended succesfully");
        }
        Err(CabotError::SchemeError(scheme)) => {
            let _ = writeln!(&mut std::io::stderr(), "Unamanaged scheme: {}", scheme);
            std::process::exit(1);
        }
        Err(CabotError::OpaqueUrlError(err)) => {
            let _ = writeln!(&mut std::io::stderr(), "Opaque URL Error:{}", err);
            std::process::exit(1);
        }
        Err(CabotError::UrlParseError(err)) => {
            let _ = writeln!(&mut std::io::stderr(), "URL Parse Error:{}", err);
            std::process::exit(1);
        }
        Err(CabotError::IOError(err)) => {
            let _ = writeln!(&mut std::io::stderr(), "IOError:{}", err);
            std::process::exit(1);
        }
        Err(CabotError::CertificateError(err)) => {
            let _ = writeln!(&mut std::io::stderr(), "CertificateError: {}", err);
            std::process::exit(1);
        }
    }
}
<|endoftext|>


<commit_before>extern crate rand;

use atty::Stream;
use std;
use rand::Rng;
use std::thread::sleep;
use std::time::Duration;

// A struct to contain info we need to print with every character
pub struct Control {
    pub seed: f64,
    pub spread: f64,
    pub frequency: f64,
    pub background_mode: bool,
    pub dialup_mode: bool,
}

pub fn print_lines_lol<I: Iterator<Item=S>, S: AsRef<str>>(lines: I, c: &mut Control) {
    for line in lines {
        print_chars_lol(line.as_ref().chars().chain(Some('\n')), c);
    }
}

// Takes in s an iterator over characters
// duplicates escape sequences, otherwise prints printable characters with colored_print
// Print newlines correctly
// TODO Adds the color to a color escape sequence
fn print_chars_lol<I: Iterator<Item=char>>(mut iter: I, c: &mut Control) {
    let original_seed = c.seed;
    let mut ignore_whitespace = c.background_mode;

    if !atty::is(Stream::Stdout) {
        for s in iter {
            print!("{}", s);
        }
        return;
    }

    while let Some(character) = iter.next() {
        match character {
        // Consume escape sequences
        '\x1b' => {
            // Escape sequences seem to be one of many different categories
            // CSI sequences are \e \[ [bytes in 0x30-0x3F] [bytes in 0x20-0x2F] [final byte in 0x40-0x7E]
            // nF Escape seq are \e [bytes in 0x20-0x2F] [byte in 0x30-0x7E]
            // Fp Escape seq are \e [byte in 0x30-0x3F] [I have no idea, but `sl` creates one where the next byte is the end of the escape sequence, so assume that]
            // Fe Escape seq are \e [byte in 0x40-0x5F] [I have no idea, '' though sl doesn't make one]
            // Fs Escape seq are \e [byte in 0x60-0x7E] [I have no idea, '' though sl doesn't make one]
            // Otherwise the next byte is the whole escape sequence (maybe? I can't exactly tell, but I will go with it)
            // We will consume up to, but not through, the next printable character
            // In addition, we print everything in the escape sequence, even if it is a color (that will be overriden)
            print!("\x1b");
            let mut escape_sequence_character = iter.next().expect("Escape character with no escape sequence after it");
            print!("{}", escape_sequence_character);
            match escape_sequence_character {
            '[' => {
                loop {
                    escape_sequence_character = iter.next().expect("CSI escape sequence did not terminate");
                    print!("{}", escape_sequence_character);
                    match escape_sequence_character {
                    '\x30' ..= '\x3F' => continue,
                    '\x20' ..= '\x2F' => {
                        loop {
                            escape_sequence_character = iter.next().expect("CSI escape sequence did not terminate");
                            print!("{}", escape_sequence_character);
                            match escape_sequence_character {
                            '\x20' ..= '\x2F' => continue,
                            '\x40' ..= '\x7E' => break,
                            _ => panic!("CSI escape sequence terminated with an incorrect value"),
                            }
                        }
                        break;
                    },
                    '\x40' ..= '\x7E' => break,
                    _ => panic!("CSI escape sequence terminated with an incorrect value"),
                    }
                }
            },
            '\x20' ..= '\x2F' => {
                loop {
                    escape_sequence_character = iter.next().expect("nF escape sequence did not terminate");
                    print!("{}", escape_sequence_character);
                    match escape_sequence_character {
                    '\x20' ..= '\x2F' => continue,
                    '\x30' ..= '\x7E' => break,
                    _ => panic!("nF escape sequence terminated with an incorrect value"),
                    }
                }
            },
//            '\x30' ..= '\x3F' => panic!("Fp escape sequences are not supported"),
//            '\x40' ..= '\x5F' => panic!("Fe escape sequences are not supported"),
//            '\x60' ..= '\x7E' => panic!("Fs escape sequences are not supported"),
            // be lazy and assume in all other cases we consume exactly 1 byte
            _ => (),
            }
            continue;
        },
        // Newlines print escape sequences to end background prints, and in dialup mode sleep
        '\n' => {
            if atty::is(Stream::Stdout) {
                // Reset the background color if we should, since otherwise it will bleed all the way to the
                // end of the terminal
                if c.background_mode {
                    print!("\x1b[49m");
                }

                // Reset the foreground color, since we are at the end of the output, and print the last newline
                // This has to happen here, rather than only at the end of the program, because otherwise
                // newlines become weird
                print!("\x1b[39m");
            }
            println!();
            if c.dialup_mode {
                let stall = Duration::from_millis(rand::thread_rng().gen_range(30, 700));
                sleep(stall);
            }
        },
        _ => {
            // In background mode, don't print colorful whitespace until the first printable character
            if ignore_whitespace && character.is_whitespace() {
                print!("{}", character);
                continue;
            } else {
                ignore_whitespace = false;
            }

            colored_print(character, c);
            c.seed += 1.0;
        },
        }
    }

    c.seed = original_seed + 1.0; // Reset the seed, but bump it a bit
}

fn calc_fg_color(bg: (u8, u8, u8)) -> (u8, u8, u8) {
    // Currently, it only computes the forground clolor based on some threshold
    // on grayscale value.
    // TODO: Add a better algorithm for computing forground color
    if conv_grayscale(bg) > 0xA0_u8 {
        (0u8, 0u8, 0u8)
    } else {
        (0xffu8, 0xffu8, 0xffu8)
    }
}

fn linear_to_srgb(intensity: f64) -> f64 {
    if intensity <= 0.003_130_8 {
        12.92 * intensity
    } else {
        1.055 * intensity.powf(1.0 / 2.4) - 0.055
    }
}

fn srgb_to_linear(intensity: f64) -> f64 {
    if intensity < 0.04045 {
        intensity / 12.92
    } else {
        ((intensity + 0.055) / 1.055).powf(2.4)
    }
}

fn conv_grayscale(color: (u8, u8, u8)) -> u8 {
    // See https://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale
    const SCALE: f64 = 256.0;

    // Changing SRGB to Linear for gamma correction
    let red = srgb_to_linear(f64::from(color.0) / SCALE);
    let green = srgb_to_linear(f64::from(color.1) / SCALE);
    let blue = srgb_to_linear(f64::from(color.2) / SCALE);

    // Converting to grayscale
    let gray_linear = red * 0.299 + green * 0.587 + blue * 0.114;

    // Gamma correction
    let gray_srgb = linear_to_srgb(gray_linear);

    (gray_srgb * SCALE) as u8
}

fn colored_print(character: char, c: &mut Control) {
    if c.background_mode {
        let bg = get_color_tuple(c);
        let fg = calc_fg_color(bg);
        print!(
            "\x1b[38;2;{};{};{};48;2;{};{};{}m{}",
            fg.0, fg.1, fg.2, bg.0, bg.1, bg.2, character
        );
    } else {
        let fg = get_color_tuple(c);
        print!("\x1b[38;2;{};{};{}m{}", fg.0, fg.1, fg.2, character);
    }
}

fn get_color_tuple(c: &Control) -> (u8, u8, u8) {
    let i = c.frequency * c.seed / c.spread;
    let red = i.sin() * 127.00 + 128.00;
    let green = (i + (std::f64::consts::PI * 2.00 / 3.00)).sin() * 127.00 + 128.00;
    let blue = (i + (std::f64::consts::PI * 4.00 / 3.00)).sin() * 127.00 + 128.00;

    (red as u8, green as u8, blue as u8)
}
<commit_msg>Get ready to differentiate between constantly-flushed input (stdin) and not<commit_after>extern crate rand;

use atty::Stream;
use std;

use rand::Rng;

use std::thread::sleep;
use std::time::Duration;

use std::io::Write;
use std::io::stdout;

// A struct to contain info we need to print with every character
pub struct Control {
    pub seed: f64,
    pub spread: f64,
    pub frequency: f64,
    pub background_mode: bool,
    pub dialup_mode: bool,
}

// This used to have more of a reason to exist, however now all its functionality is in
// print_chars_lol(). Anyway, it takes in an iterator over lines and prints them all.
pub fn print_lines_lol<I: Iterator<Item=S>, S: AsRef<str>>(lines: I, c: &mut Control) {
    for line in lines {
        print_chars_lol(line.as_ref().chars().chain(Some('\n')), c, false);
    }
}

// Takes in s an iterator over characters
// duplicates escape sequences, otherwise prints printable characters with colored_print
// Print newlines correctly, resetting background
// If constantly_flush is on, it won't wait till a newline to flush stdout
// TODO Adds the color to a color escape sequence
fn print_chars_lol<I: Iterator<Item=char>>(mut iter: I, c: &mut Control, constantly_flush: bool) {
    let original_seed = c.seed;
    let mut ignore_whitespace = c.background_mode;

    if !atty::is(Stream::Stdout) {
        for s in iter {
            print!("{}", s);
        }
        return;
    }

    while let Some(character) = iter.next() {
        match character {
        // Consume escape sequences
        '\x1b' => {
            // Escape sequences seem to be one of many different categories
            // CSI sequences are \e \[ [bytes in 0x30-0x3F] [bytes in 0x20-0x2F] [final byte in 0x40-0x7E]
            // nF Escape seq are \e [bytes in 0x20-0x2F] [byte in 0x30-0x7E]
            // Fp Escape seq are \e [byte in 0x30-0x3F] [I have no idea, but `sl` creates one where the next byte is the end of the escape sequence, so assume that]
            // Fe Escape seq are \e [byte in 0x40-0x5F] [I have no idea, '' though sl doesn't make one]
            // Fs Escape seq are \e [byte in 0x60-0x7E] [I have no idea, '' though sl doesn't make one]
            // Otherwise the next byte is the whole escape sequence (maybe? I can't exactly tell, but I will go with it)
            // We will consume up to, but not through, the next printable character
            // In addition, we print everything in the escape sequence, even if it is a color (that will be overriden)
            print!("\x1b");
            let mut escape_sequence_character = iter.next().expect("Escape character with no escape sequence after it");
            print!("{}", escape_sequence_character);
            match escape_sequence_character {
            '[' => {
                loop {
                    escape_sequence_character = iter.next().expect("CSI escape sequence did not terminate");
                    print!("{}", escape_sequence_character);
                    match escape_sequence_character {
                    '\x30' ..= '\x3F' => continue,
                    '\x20' ..= '\x2F' => {
                        loop {
                            escape_sequence_character = iter.next().expect("CSI escape sequence did not terminate");
                            print!("{}", escape_sequence_character);
                            match escape_sequence_character {
                            '\x20' ..= '\x2F' => continue,
                            '\x40' ..= '\x7E' => break,
                            _ => panic!("CSI escape sequence terminated with an incorrect value"),
                            }
                        }
                        break;
                    },
                    '\x40' ..= '\x7E' => break,
                    _ => panic!("CSI escape sequence terminated with an incorrect value"),
                    }
                }
            },
            '\x20' ..= '\x2F' => {
                loop {
                    escape_sequence_character = iter.next().expect("nF escape sequence did not terminate");
                    print!("{}", escape_sequence_character);
                    match escape_sequence_character {
                    '\x20' ..= '\x2F' => continue,
                    '\x30' ..= '\x7E' => break,
                    _ => panic!("nF escape sequence terminated with an incorrect value"),
                    }
                }
            },
//            '\x30' ..= '\x3F' => panic!("Fp escape sequences are not supported"),
//            '\x40' ..= '\x5F' => panic!("Fe escape sequences are not supported"),
//            '\x60' ..= '\x7E' => panic!("Fs escape sequences are not supported"),
            // be lazy and assume in all other cases we consume exactly 1 byte
            _ => (),
            }
            continue;
        },
        // Newlines print escape sequences to end background prints, and in dialup mode sleep, and
        // reset the seed of the coloring
        '\n' => {
            if atty::is(Stream::Stdout) {
                // Reset the background color if we should, since otherwise it will bleed all the way to the
                // end of the terminal
                if c.background_mode {
                    print!("\x1b[49m");
                }

                // Reset the foreground color, since we are at the end of the output, and print the last newline
                // This has to happen here, rather than only at the end of the program, because otherwise
                // newlines become weird
                print!("\x1b[39m");
            }
            println!();
            if c.dialup_mode {
                let stall = Duration::from_millis(rand::thread_rng().gen_range(30, 700));
                sleep(stall);
            }
            c.seed = original_seed + 1.0; // Reset the seed, but bump it a bit
        },
        // If not an escape sequence or a newline, print a colorful escape sequence and then the
        // character
        _ => {
            // In background mode, don't print colorful whitespace until the first printable character
            if ignore_whitespace && character.is_whitespace() {
                print!("{}", character);
                continue;
            } else {
                ignore_whitespace = false;
            }

            colored_print(character, c);
            c.seed += 1.0;
        },
        }

        // If we should constantly flush, flush after each completed sequence
        if constantly_flush {
            stdout().flush().unwrap();
        }
    }
}

fn calc_fg_color(bg: (u8, u8, u8)) -> (u8, u8, u8) {
    // Currently, it only computes the forground clolor based on some threshold
    // on grayscale value.
    // TODO: Add a better algorithm for computing forground color
    if conv_grayscale(bg) > 0xA0_u8 {
        (0u8, 0u8, 0u8)
    } else {
        (0xffu8, 0xffu8, 0xffu8)
    }
}

fn linear_to_srgb(intensity: f64) -> f64 {
    if intensity <= 0.003_130_8 {
        12.92 * intensity
    } else {
        1.055 * intensity.powf(1.0 / 2.4) - 0.055
    }
}

fn srgb_to_linear(intensity: f64) -> f64 {
    if intensity < 0.04045 {
        intensity / 12.92
    } else {
        ((intensity + 0.055) / 1.055).powf(2.4)
    }
}

fn conv_grayscale(color: (u8, u8, u8)) -> u8 {
    // See https://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale
    const SCALE: f64 = 256.0;

    // Changing SRGB to Linear for gamma correction
    let red = srgb_to_linear(f64::from(color.0) / SCALE);
    let green = srgb_to_linear(f64::from(color.1) / SCALE);
    let blue = srgb_to_linear(f64::from(color.2) / SCALE);

    // Converting to grayscale
    let gray_linear = red * 0.299 + green * 0.587 + blue * 0.114;

    // Gamma correction
    let gray_srgb = linear_to_srgb(gray_linear);

    (gray_srgb * SCALE) as u8
}

fn colored_print(character: char, c: &mut Control) {
    if c.background_mode {
        let bg = get_color_tuple(c);
        let fg = calc_fg_color(bg);
        print!(
            "\x1b[38;2;{};{};{};48;2;{};{};{}m{}",
            fg.0, fg.1, fg.2, bg.0, bg.1, bg.2, character
        );
    } else {
        let fg = get_color_tuple(c);
        print!("\x1b[38;2;{};{};{}m{}", fg.0, fg.1, fg.2, character);
    }
}

fn get_color_tuple(c: &Control) -> (u8, u8, u8) {
    let i = c.frequency * c.seed / c.spread;
    let red = i.sin() * 127.00 + 128.00;
    let green = (i + (std::f64::consts::PI * 2.00 / 3.00)).sin() * 127.00 + 128.00;
    let blue = (i + (std::f64::consts::PI * 4.00 / 3.00)).sin() * 127.00 + 128.00;

    (red as u8, green as u8, blue as u8)
}
<|endoftext|>


<commit_before>use std::env;
use std::rc::Rc;
use std::cell::RefCell;
use sfml::graphics::{RenderWindow, RenderTarget, Font};
use sfml::window::{ContextSettings, VideoMode, Close};
use sfml::window::event;
use sfml::window::keyboard::Key;
use sfml::window::mouse::MouseButton;
use sfml::graphics::Color;
use sfml::system::vector2::Vector2i;
use na::{Pnt2, Pnt3, Iso2};
use na;
use nphysics::world::World;
use nphysics::object::RigidBody;
use nphysics::detection::joint::{Fixed, Anchor};
use camera::Camera;
use fps::Fps;
use engine::GraphicsManager;
use draw_helper;

fn usage(exe_name: &str) {
    println!("Usage: {} [OPTION] ", exe_name);
    println!("");
    println!("Options:");
    println!("    --help  - prints this help message and exits.");
    println!("    --pause - do not start the simulation right away.");
    println!("");
    println!("The following keyboard commands are supported:");
    println!("    t     - pause/continue the simulation.");
    println!("    s     - pause then execute only one simulation step.");
    println!("    space - display/hide contacts.");
}

#[derive(PartialEq)]
enum RunMode {
    Running,
    Stop,
    Step
}

pub struct Testbed<'a> {
    world:    World,
    window:   RenderWindow,
    graphics: GraphicsManager<'a>
}

struct TestbedState<'a> {
    running: RunMode,
    draw_colls: bool,
    camera: Camera,
    fps: Fps<'a>,
    grabbed_object: Option<Rc<RefCell<RigidBody>>>,
    grabbed_object_joint: Option<Rc<RefCell<Fixed>>>,
}

impl<'a> TestbedState<'a> {
    fn new(fnt: &'a Font) -> TestbedState<'a> {
        TestbedState{
            running: RunMode::Running,
            draw_colls: false,
            camera: Camera::new(),
            fps: Fps::new(&fnt),
            grabbed_object: None,
            grabbed_object_joint: None,
        }
    }
}

impl<'a> Testbed<'a> {
    pub fn new_empty() -> Testbed<'a> {
        let mode    = VideoMode::new_init(800, 600, 32);
        let setting = ContextSettings {
            depth_bits:         10,
            stencil_bits:       10,
            antialiasing_level: 2,
            major_version:      0,
            minor_version:      1
        };
        let window =
            match RenderWindow::new(mode, "nphysics 2d demo", Close, &setting) {
                Some(rwindow) => rwindow,
                None          => panic!("Error on creating the sfml window.")
            };
        let graphics = GraphicsManager::new();

        Testbed {
            world:    World::new(),
            window:   window,
            graphics: graphics
        }
    }

    pub fn new(world: World) -> Testbed<'a> {
        let mut res = Testbed::new_empty();

        res.set_world(world);

        res
    }

    pub fn set_world(&mut self, world: World) {
        self.world = world;
        self.graphics.clear();

        for rb in self.world.bodies() {
            self.graphics.add(rb.clone());
        }
    }

    pub fn set_color(&mut self, body: &Rc<RefCell<RigidBody>>, color: Pnt3<f32>) {
        let color = Pnt3::new(
            (color.x * 255.0) as u8,
            (color.y * 255.0) as u8,
            (color.z * 255.0) as u8
        );

        self.graphics.set_color(body, color);
    }

    pub fn run(&mut self) {
        let font_mem = include_bytes!("Inconsolata.otf");
        let     fnt  = Font::new_from_memory(font_mem).unwrap();

        let mut state = TestbedState::new(&fnt);

        let mut args    = env::args();

        if args.len() > 1 {
            let exname = args.next().unwrap();
            for arg in args {
                if &arg[..] == "--help" || &arg[..] == "-h" {
                    usage(&exname[..]);
                    return;
                }
                else if &arg[..] == "--pause" {
                    state.running = RunMode::Stop;
                }
            }
        }

        self.window.set_framerate_limit(60);

        self.foo(state);

        self.window.close();
    }

    fn foo(&mut self, mut state: TestbedState) {
        while self.window.is_open() {
            loop {
                match self.window.poll_event() {
                    event::KeyPressed{code, ..} => {
                        match code {
                            Key::Escape => self.window.close(),
                            Key::S      => state.running = RunMode::Step,
                            Key::Space  => state.draw_colls = !state.draw_colls,
                            Key::T      => {
                                if state.running == RunMode::Stop {
                                    state.running = RunMode::Running;
                                }
                                else {
                                    state.running = RunMode::Stop;
                                }
                            },
                            _                => { }
                        }
                    },
                    event::MouseButtonPressed{button, x, y} => {
                        match button {
                            MouseButton::MouseLeft => {
                                let mapped_coords = state.camera.map_pixel_to_coords(Vector2i::new(x, y));
                                let mapped_point = Pnt2::new(mapped_coords.x, mapped_coords.y);
                                self.world.interferences_with_point(&mapped_point, |b| {
                                    if b.borrow().can_move() {
                                        state.grabbed_object = Some(b.clone())
                                    }
                                });

                                match state.grabbed_object {
                                    Some(ref b) => {
                                        for node in self.graphics.body_to_scene_node(b).unwrap().iter_mut() {
                                            match state.grabbed_object_joint {
                                                Some(ref j) => self.world.remove_fixed(j),
                                                None        => { }
                                            }

                                            let _1: Iso2<f32> = na::one();
                                            let attach2 = na::append_translation(&_1, mapped_point.as_vec());
                                            let attach1 = na::inv(&na::transformation(b.borrow().position())).unwrap() * attach2;
                                            let anchor1 = Anchor::new(Some(state.grabbed_object.as_ref().unwrap().clone()), attach1);
                                            let anchor2 = Anchor::new(None, attach2);
                                            let joint = Fixed::new(anchor1, anchor2);
                                            state.grabbed_object_joint = Some(self.world.add_fixed(joint));
                                            node.select()
                                        }
                                    },
                                    None => { }
                                }
                            },
                            _ => {
                                state.camera.handle_event(&event::MouseButtonPressed{ button: button, x: x, y: y })
                            }
                        }
                    },
                    event::MouseButtonReleased{button, x, y} => {
                        match button {
                            MouseButton::MouseLeft => {
                                match state.grabbed_object {
                                    Some(ref b) => {
                                        for node in self.graphics.body_to_scene_node(b).unwrap().iter_mut() {
                                            node.unselect()
                                        }
                                    },
                                    None => { }
                                }

                                match state.grabbed_object_joint {
                                    Some(ref j) => self.world.remove_fixed(j),
                                    None => { }
                                }

                                state.grabbed_object = None;
                                state.grabbed_object_joint = None;
                            },
                            _ => {
                                state.camera.handle_event(&event::MouseButtonReleased{ button: button, x: x, y: y })
                            }
                        }
                    }
                    event::MouseMoved{x, y} => {
                        let mapped_coords = state.camera.map_pixel_to_coords(Vector2i::new(x, y));
                        let mapped_point = Pnt2::new(mapped_coords.x, mapped_coords.y);
                        let _1: Iso2<f32> = na::one();
                        let attach2 = na::append_translation(&_1, (mapped_point).as_vec());
                        match state.grabbed_object {
                            Some(_) => {
                                let joint = state.grabbed_object_joint.as_ref().unwrap();
                                joint.borrow_mut().set_local2(attach2);
                            },
                            None => state.camera.handle_event(&event::MouseMoved{x: x, y: y})
                        };
                    },
                    event::Closed  => self.window.close(),
                    event::NoEvent => break,
                    e              => state.camera.handle_event(&e)
                }
            }

            self.window.clear(&Color::black());

            state.fps.reset();

            if state.running != RunMode::Stop {
                self.world.step(0.016);
            }

            if state.running == RunMode::Step {
                state.running = RunMode::Stop;
            }
            state.fps.register_delta();
            self.graphics.draw(&mut self.window, &state.camera);

            state.camera.activate_scene(&mut self.window);
            if state.draw_colls {
                draw_helper::draw_colls(&mut self.window, &mut self.world);
            }

            state.camera.activate_ui(&mut self.window);
            state.fps.draw_registered(&mut self.window);

            self.window.display();
        }
    }
}
<commit_msg>Factored out another loop<commit_after>use std::env;
use std::rc::Rc;
use std::cell::RefCell;
use sfml::graphics::{RenderWindow, RenderTarget, Font};
use sfml::window::{ContextSettings, VideoMode, Close};
use sfml::window::event;
use sfml::window::keyboard::Key;
use sfml::window::mouse::MouseButton;
use sfml::graphics::Color;
use sfml::system::vector2::Vector2i;
use na::{Pnt2, Pnt3, Iso2};
use na;
use nphysics::world::World;
use nphysics::object::RigidBody;
use nphysics::detection::joint::{Fixed, Anchor};
use camera::Camera;
use fps::Fps;
use engine::GraphicsManager;
use draw_helper;

fn usage(exe_name: &str) {
    println!("Usage: {} [OPTION] ", exe_name);
    println!("");
    println!("Options:");
    println!("    --help  - prints this help message and exits.");
    println!("    --pause - do not start the simulation right away.");
    println!("");
    println!("The following keyboard commands are supported:");
    println!("    t     - pause/continue the simulation.");
    println!("    s     - pause then execute only one simulation step.");
    println!("    space - display/hide contacts.");
}

#[derive(PartialEq)]
enum RunMode {
    Running,
    Stop,
    Step
}

pub struct Testbed<'a> {
    world:    World,
    window:   RenderWindow,
    graphics: GraphicsManager<'a>
}

struct TestbedState<'a> {
    running: RunMode,
    draw_colls: bool,
    camera: Camera,
    fps: Fps<'a>,
    grabbed_object: Option<Rc<RefCell<RigidBody>>>,
    grabbed_object_joint: Option<Rc<RefCell<Fixed>>>,
}

impl<'a> TestbedState<'a> {
    fn new(fnt: &'a Font) -> TestbedState<'a> {
        TestbedState{
            running: RunMode::Running,
            draw_colls: false,
            camera: Camera::new(),
            fps: Fps::new(&fnt),
            grabbed_object: None,
            grabbed_object_joint: None,
        }
    }
}

impl<'a> Testbed<'a> {
    pub fn new_empty() -> Testbed<'a> {
        let mode    = VideoMode::new_init(800, 600, 32);
        let setting = ContextSettings {
            depth_bits:         10,
            stencil_bits:       10,
            antialiasing_level: 2,
            major_version:      0,
            minor_version:      1
        };
        let window =
            match RenderWindow::new(mode, "nphysics 2d demo", Close, &setting) {
                Some(rwindow) => rwindow,
                None          => panic!("Error on creating the sfml window.")
            };
        let graphics = GraphicsManager::new();

        Testbed {
            world:    World::new(),
            window:   window,
            graphics: graphics
        }
    }

    pub fn new(world: World) -> Testbed<'a> {
        let mut res = Testbed::new_empty();

        res.set_world(world);

        res
    }

    pub fn set_world(&mut self, world: World) {
        self.world = world;
        self.graphics.clear();

        for rb in self.world.bodies() {
            self.graphics.add(rb.clone());
        }
    }

    pub fn set_color(&mut self, body: &Rc<RefCell<RigidBody>>, color: Pnt3<f32>) {
        let color = Pnt3::new(
            (color.x * 255.0) as u8,
            (color.y * 255.0) as u8,
            (color.z * 255.0) as u8
        );

        self.graphics.set_color(body, color);
    }

    pub fn run(&mut self) {
        let font_mem = include_bytes!("Inconsolata.otf");
        let     fnt  = Font::new_from_memory(font_mem).unwrap();

        let mut state = TestbedState::new(&fnt);

        let mut args    = env::args();

        if args.len() > 1 {
            let exname = args.next().unwrap();
            for arg in args {
                if &arg[..] == "--help" || &arg[..] == "-h" {
                    usage(&exname[..]);
                    return;
                }
                else if &arg[..] == "--pause" {
                    state.running = RunMode::Stop;
                }
            }
        }

        self.window.set_framerate_limit(60);

        self.foo(state);

        self.window.close();
    }

    fn foo(&mut self, mut state: TestbedState) {
        while self.window.is_open() {
            self.foo_loop(&mut state);

            self.window.clear(&Color::black());

            state.fps.reset();

            if state.running != RunMode::Stop {
                self.world.step(0.016);
            }

            if state.running == RunMode::Step {
                state.running = RunMode::Stop;
            }
            state.fps.register_delta();
            self.graphics.draw(&mut self.window, &state.camera);

            state.camera.activate_scene(&mut self.window);
            if state.draw_colls {
                draw_helper::draw_colls(&mut self.window, &mut self.world);
            }

            state.camera.activate_ui(&mut self.window);
            state.fps.draw_registered(&mut self.window);

            self.window.display();
        }
    }

    fn foo_loop(&mut self, state: &mut TestbedState) {
        loop {
            match self.window.poll_event() {
                event::KeyPressed{code, ..} => {
                    match code {
                        Key::Escape => self.window.close(),
                        Key::S      => state.running = RunMode::Step,
                        Key::Space  => state.draw_colls = !state.draw_colls,
                        Key::T      => {
                            if state.running == RunMode::Stop {
                                state.running = RunMode::Running;
                            }
                            else {
                                state.running = RunMode::Stop;
                            }
                        },
                        _                => { }
                    }
                },
                event::MouseButtonPressed{button, x, y} => {
                    match button {
                        MouseButton::MouseLeft => {
                            let mapped_coords = state.camera.map_pixel_to_coords(Vector2i::new(x, y));
                            let mapped_point = Pnt2::new(mapped_coords.x, mapped_coords.y);
                            self.world.interferences_with_point(&mapped_point, |b| {
                                if b.borrow().can_move() {
                                    state.grabbed_object = Some(b.clone())
                                }
                            });

                            match state.grabbed_object {
                                Some(ref b) => {
                                    for node in self.graphics.body_to_scene_node(b).unwrap().iter_mut() {
                                        match state.grabbed_object_joint {
                                            Some(ref j) => self.world.remove_fixed(j),
                                            None        => { }
                                        }

                                        let _1: Iso2<f32> = na::one();
                                        let attach2 = na::append_translation(&_1, mapped_point.as_vec());
                                        let attach1 = na::inv(&na::transformation(b.borrow().position())).unwrap() * attach2;
                                        let anchor1 = Anchor::new(Some(state.grabbed_object.as_ref().unwrap().clone()), attach1);
                                        let anchor2 = Anchor::new(None, attach2);
                                        let joint = Fixed::new(anchor1, anchor2);
                                        state.grabbed_object_joint = Some(self.world.add_fixed(joint));
                                        node.select()
                                    }
                                },
                                None => { }
                            }
                        },
                        _ => {
                            state.camera.handle_event(&event::MouseButtonPressed{ button: button, x: x, y: y })
                        }
                    }
                },
                event::MouseButtonReleased{button, x, y} => {
                    match button {
                        MouseButton::MouseLeft => {
                            match state.grabbed_object {
                                Some(ref b) => {
                                    for node in self.graphics.body_to_scene_node(b).unwrap().iter_mut() {
                                        node.unselect()
                                    }
                                },
                                None => { }
                            }

                            match state.grabbed_object_joint {
                                Some(ref j) => self.world.remove_fixed(j),
                                None => { }
                            }

                            state.grabbed_object = None;
                            state.grabbed_object_joint = None;
                        },
                        _ => {
                            state.camera.handle_event(&event::MouseButtonReleased{ button: button, x: x, y: y })
                        }
                    }
                }
                event::MouseMoved{x, y} => {
                    let mapped_coords = state.camera.map_pixel_to_coords(Vector2i::new(x, y));
                    let mapped_point = Pnt2::new(mapped_coords.x, mapped_coords.y);
                    let _1: Iso2<f32> = na::one();
                    let attach2 = na::append_translation(&_1, (mapped_point).as_vec());
                    match state.grabbed_object {
                        Some(_) => {
                            let joint = state.grabbed_object_joint.as_ref().unwrap();
                            joint.borrow_mut().set_local2(attach2);
                        },
                        None => state.camera.handle_event(&event::MouseMoved{x: x, y: y})
                    };
                },
                event::Closed  => self.window.close(),
                event::NoEvent => break,
                e              => state.camera.handle_event(&e)
            }
        }
    }
}
<|endoftext|>