<commit_before>use std::collections::HashMap;
use uuid::Uuid;

use graphics::*;
use graphics::vecmath::Matrix2d;

use event::GenericEvent;
use ai_behavior::{
    Behavior,
    State,
    Running,
};

use sprite::Sprite;

use animation::{
    Animation,
    AnimationState,
};

/// A scene is used to manage sprite's life and run animation with sprite
pub struct Scene<I: ImageSize> {
    children: Vec<Sprite<I>>,
    children_index: HashMap<Uuid, usize>,
    running: HashMap<Uuid,
        Vec<(Behavior<Animation>, State<Animation, AnimationState>, bool)>>,
}

impl<I: ImageSize> Scene<I> {
    /// Create a new scene
    pub fn new() -> Scene<I> {
        Scene {
            children: Vec::new(),
            children_index: HashMap::new(),
            running: HashMap::new(),
        }
    }

    /// Update animation's state
    pub fn event<E>(&mut self, e: &E) where E: GenericEvent {
        // regenerate the animations and their states
        let running = self.running.clone();
        self.running.clear();

        for (id, animations) in running.into_iter() {
            let mut new_animations = Vec::new();

            for (b, mut a, paused) in animations.into_iter() {
                if paused {
                    new_animations.push((b, a, paused));
                    continue;
                }

                let sprite = self.child_mut(&id).unwrap();
                let (status, _) = a.event(e, &mut |_, dt, animation, s| {
                    let (state, status, remain) = {
                        let start_state;
                        let state = match *s {
                            None => { start_state = animation.to_state(sprite); &start_state },
                            Some(ref state) => state,
                        };
                        state.update(sprite, dt)
                    };
                    *s = state;
                    (status, remain)
                });

                match status {
                    // the behavior is still running, add it for next update
                    Running => {
                        new_animations.push((b, a, paused));
                    },
                    _ => {},
                }
            }

            if new_animations.len() > 0 {
                self.running.insert(id, new_animations);
            }
        }
    }

    /// Render this scene
    pub fn draw<B: BackEnd<Texture = I>>(&self, t: Matrix2d, b: &mut B) {
        for child in self.children.iter() {
            child.draw(t, b);
        }
    }

    /// Register animation with sprite
    pub fn run(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        use std::collections::hash_map::Entry::{ Vacant, Occupied };
        let animations = match self.running.entry(sprite_id) {
            Vacant(entry) => entry.insert(Vec::new()),
            Occupied(entry) => entry.into_mut()
        };
        let state = State::new(animation.clone());
        animations.push((animation.clone(), state, false));
    }

    fn find(&self, sprite_id: &Uuid, animation: &Behavior<Animation>) -> Option<usize> {
        let mut index = None;
        if let Some(animations) = self.running.get(&sprite_id) {
            for i in 0..animations.len() {
                let (ref b, _, _) = animations[i];
                if b == animation {
                    index = Some(i);
                    break;
                }
            }
        }
        index
    }

    /// Pause a running animation of the sprite
    pub fn pause(&mut self, sprite_id: &Uuid, animation: &Behavior<Animation>) {
        if let Some(index) = self.find(sprite_id, animation) {
            let animations = self.running.get_mut(&sprite_id).unwrap();
            let (b, s, _) = animations.remove(index);
            animations.push((b, s, true));
        }
    }

    /// Resume a paused animation of the sprite
    pub fn resume(&mut self, sprite_id: &Uuid, animation: &Behavior<Animation>) {
        if let Some(index) = self.find(sprite_id, animation) {
            let animations = self.running.get_mut(&sprite_id).unwrap();
            let (b, s, _) = animations.remove(index);
            animations.push((b, s, false));
        }
    }

    /// Toggle an animation of the sprite
    pub fn toggle(&mut self, sprite_id: &Uuid, animation: &Behavior<Animation>) {
        if let Some(index) = self.find(sprite_id, animation) {
            let animations = self.running.get_mut(&sprite_id).unwrap();
            let (b, s, paused) = animations.remove(index);
            animations.push((b, s, !paused));
        }
    }

    /// Stop a running animation of the sprite
    pub fn stop(&mut self, sprite_id: &Uuid, animation: &Behavior<Animation>) {
        if let Some(index) = self.find(sprite_id, animation) {
            self.running.get_mut(&sprite_id).unwrap().remove(index);
        }
    }

    /// Stop all running animations of the sprite
    pub fn stop_all(&mut self, sprite_id: &Uuid) {
        self.running.remove(&sprite_id);
    }

    /// Get all the running animations in the scene
    pub fn running(&self) -> usize {
        let mut total = 0;
        for (_, animations) in self.running.iter() {
            total += animations.len();
        }
        total
    }

    /// Add sprite to scene
    pub fn add_child(&mut self, sprite: Sprite<I>) -> Uuid {
        let id = sprite.id();
        self.children.push(sprite);
        self.children_index.insert(id.clone(), self.children.len() - 1);
        id
    }

    fn stop_all_including_children(&mut self, sprite: &Sprite<I>) {
        self.stop_all(&sprite.id());
        for child in sprite.children().iter() {
            self.stop_all_including_children(child);
        }
    }

    /// Remove the child by `id` from the scene's children or grandchild
    /// will stop all the animations run by this child
    pub fn remove_child(&mut self, id: &Uuid) -> Option<Sprite<I>> {
        let removed = if let Some(index) = self.children_index.remove(id) {
            let removed = self.children.remove(index);
            // Removing a element of vector will alter the index,
            // update the mapping from uuid to index.
            for i in index..self.children.len() {
                let uuid = self.children[i].id();
                self.children_index.insert(uuid, i);
            }
            Some(removed)
        } else {
            for child in self.children.iter_mut() {
                if let Some(c) = child.remove_child(id.clone()) {
                    return Some(c);
                }
            }
            None
        };

        if removed.is_some() {
            self.stop_all_including_children(removed.as_ref().unwrap());
        }

        removed
    }

    /// Find the child by `id` from the scene's children or grandchild
    pub fn child(&self, id: &Uuid) -> Option<&Sprite<I>> {
        if let Some(index) = self.children_index.get(id) {
            Some(&self.children[*index])
        } else {
            for child in self.children.iter() {
                if let Some(c) = child.child(id.clone()) {
                    return Some(c);
                }
            }
            None
        }
    }

    /// Find the child by `id` from this sprite's children or grandchild, mutability
    pub fn child_mut(&mut self, id: &Uuid) -> Option<&mut Sprite<I>> {
        if let Some(index) = self.children_index.get(id) {
            Some(&mut self.children[*index])
        } else {
            for child in self.children.iter_mut() {
                if let Some(c) = child.child_mut(id.clone()) {
                    return Some(c);
                }
            }
            None
        }
    }
}
<commit_msg>added lifetimes<commit_after>use std::collections::HashMap;
use uuid::Uuid;

use graphics::*;
use graphics::vecmath::Matrix2d;

use event::GenericEvent;
use ai_behavior::{
    Behavior,
    State,
    Running,
};

use sprite::Sprite;

use animation::{
    Animation,
    AnimationState,
};

/// A scene is used to manage sprite's life and run animation with sprite
pub struct Scene<'a, I: ImageSize> {
    children: Vec<Sprite<I>>,
    children_index: HashMap<Uuid, usize>,
    running: HashMap<&'a Uuid,
        Vec<(Behavior<Animation>, State<Animation, AnimationState>, bool)>>,
}

impl<'a, I: ImageSize> Scene<'a, I> {
    /// Create a new scene
    pub fn new() -> Scene<'a, I> {
        Scene {
            children: Vec::new(),
            children_index: HashMap::new(),
            running: HashMap::new(),
        }
    }

    /// Update animation's state
    pub fn event<E>(&mut self, e: &E) where E: GenericEvent {
        // regenerate the animations and their states
        let running = self.running.clone();
        self.running.clear();

        for (id, animations) in running.into_iter() {
            let mut new_animations = Vec::new();

            for (b, mut a, paused) in animations.into_iter() {
                if paused {
                    new_animations.push((b, a, paused));
                    continue;
                }

                let sprite = self.child_mut(&id).unwrap();
                let (status, _) = a.event(e, &mut |_, dt, animation, s| {
                    let (state, status, remain) = {
                        let start_state;
                        let state = match *s {
                            None => { start_state = animation.to_state(sprite); &start_state },
                            Some(ref state) => state,
                        };
                        state.update(sprite, dt)
                    };
                    *s = state;
                    (status, remain)
                });

                match status {
                    // the behavior is still running, add it for next update
                    Running => {
                        new_animations.push((b, a, paused));
                    },
                    _ => {},
                }
            }

            if new_animations.len() > 0 {
                self.running.insert(id, new_animations);
            }
        }
    }

    /// Render this scene
    pub fn draw<B: BackEnd<Texture = I>>(&self, t: Matrix2d, b: &mut B) {
        for child in self.children.iter() {
            child.draw(t, b);
        }
    }

    /// Register animation with sprite
    pub fn run<'b>(&'b mut self, sprite_id: &'a Uuid, animation: &'b Behavior<Animation>) {
        use std::collections::hash_map::Entry::{ Vacant, Occupied };
        let animations = match self.running.entry(sprite_id) {
            Vacant(entry) => entry.insert(Vec::new()),
            Occupied(entry) => entry.into_mut()
        };
        let state = State::new(animation.clone());
        animations.push((animation.clone(), state, false));
    }

    fn find(&self, sprite_id: &Uuid, animation: &Behavior<Animation>) -> Option<usize> {
        let mut index = None;
        if let Some(animations) = self.running.get(sprite_id) {
            for i in 0..animations.len() {
                let (ref b, _, _) = animations[i];
                if b == animation {
                    index = Some(i);
                    break;
                }
            }
        }
        index
    }

    /// Pause a running animation of the sprite
    pub fn pause(&mut self, sprite_id: &Uuid, animation: &Behavior<Animation>) {
        if let Some(index) = self.find(sprite_id, animation) {
            let animations = self.running.get_mut(&sprite_id).unwrap();
            let (b, s, _) = animations.remove(index);
            animations.push((b, s, true));
        }
    }

    /// Resume a paused animation of the sprite
    pub fn resume(&mut self, sprite_id: &Uuid, animation: &Behavior<Animation>) {
        if let Some(index) = self.find(sprite_id, animation) {
            let animations = self.running.get_mut(&sprite_id).unwrap();
            let (b, s, _) = animations.remove(index);
            animations.push((b, s, false));
        }
    }

    /// Toggle an animation of the sprite
    pub fn toggle(&mut self, sprite_id: &Uuid, animation: &Behavior<Animation>) {
        if let Some(index) = self.find(sprite_id, animation) {
            let animations = self.running.get_mut(&sprite_id).unwrap();
            let (b, s, paused) = animations.remove(index);
            animations.push((b, s, !paused));
        }
    }

    /// Stop a running animation of the sprite
    pub fn stop(&mut self, sprite_id: &Uuid, animation: &Behavior<Animation>) {
        if let Some(index) = self.find(sprite_id, animation) {
            self.running.get_mut(&sprite_id).unwrap().remove(index);
        }
    }

    /// Stop all running animations of the sprite
    pub fn stop_all(&mut self, sprite_id: &Uuid) {
        self.running.remove(&sprite_id);
    }

    /// Get all the running animations in the scene
    pub fn running(&self) -> usize {
        let mut total = 0;
        for (_, animations) in self.running.iter() {
            total += animations.len();
        }
        total
    }

    /// Add sprite to scene
    pub fn add_child(&mut self, sprite: Sprite<I>) -> Uuid {
        let id = sprite.id();
        self.children.push(sprite);
        self.children_index.insert(id.clone(), self.children.len() - 1);
        id
    }

    fn stop_all_including_children(&mut self, sprite: &Sprite<I>) {
        self.stop_all(&sprite.id());
        for child in sprite.children().iter() {
            self.stop_all_including_children(child);
        }
    }

    /// Remove the child by `id` from the scene's children or grandchild
    /// will stop all the animations run by this child
    pub fn remove_child(&mut self, id: &Uuid) -> Option<Sprite<I>> {
        let removed = if let Some(index) = self.children_index.remove(id) {
            let removed = self.children.remove(index);
            // Removing a element of vector will alter the index,
            // update the mapping from uuid to index.
            for i in index..self.children.len() {
                let uuid = self.children[i].id();
                self.children_index.insert(uuid, i);
            }
            Some(removed)
        } else {
            for child in self.children.iter_mut() {
                if let Some(c) = child.remove_child(id.clone()) {
                    return Some(c);
                }
            }
            None
        };

        if removed.is_some() {
            self.stop_all_including_children(removed.as_ref().unwrap());
        }

        removed
    }

    /// Find the child by `id` from the scene's children or grandchild
    pub fn child(&self, id: &Uuid) -> Option<&Sprite<I>> {
        if let Some(index) = self.children_index.get(id) {
            Some(&self.children[*index])
        } else {
            for child in self.children.iter() {
                if let Some(c) = child.child(id.clone()) {
                    return Some(c);
                }
            }
            None
        }
    }

    /// Find the child by `id` from this sprite's children or grandchild, mutability
    pub fn child_mut(&mut self, id: &Uuid) -> Option<&mut Sprite<I>> {
        if let Some(index) = self.children_index.get(id) {
            Some(&mut self.children[*index])
        } else {
            for child in self.children.iter_mut() {
                if let Some(c) = child.child_mut(id.clone()) {
                    return Some(c);
                }
            }
            None
        }
    }
}
<|endoftext|>


<commit_before>use std::rand::Rng;
use calx::dijkstra::Dijkstra;
use world;
use location::{Location};
use dir6::Dir6;
use flags;
use mob;
use mob::{Status, Intrinsic, MobType};
use geom::HexGeom;
use spatial::Place;
use action;
use fov::Fov;
use rng;
use msg;

/// Game object handle.
#[deriving(PartialEq, Eq, Clone, Hash, Show, Decodable, Encodable)]
pub struct Entity(pub uint);

impl Entity {
    /// Place the entity in a location in the game world.
    pub fn place(self, loc: Location) {
        world::with_mut(|w| w.spatial.insert_at(self, loc));
        self.on_move_to(loc);
    }

    /// Remove the entity from all the game world systems. THE ENTITY VALUE
    /// WILL BE INVALID FROM HERE ON AND USING IT WILL LEAD TO BUGS. THE
    /// CALLER IS RESPONSIBLE FOR ENSUING THAT AN ENTITY WILL NOT BE
    /// USED FROM ANYWHERE AFTER THE DELETE OPERATION.
    pub fn delete(self) {
        // LABYRINTH OF COMPONENTS
        // This needs to call every toplevel component system.
        world::with_mut(|w| w.comp.remove(self));
        world::with_mut(|w| w.spatial.remove(self));
        world::with_mut(|w| w.ecs.delete(self));
    }

    pub fn blocks_walk(self) -> bool { self.is_mob() }

    /// Return the kind of the entity.
    pub fn kind(self) -> ::EntityKind {
        // XXX: Will crash if an entity has no kind specified.
        world::with(|w| *w.comp.kind.get(self).unwrap())
    }

// Spatial methods /////////////////////////////////////////////////////

    pub fn can_enter(self, loc: Location) -> bool {
        if self.is_mob() && loc.has_mobs() { return false; }
        if loc.terrain().is_door() && !self.has_intrinsic(Intrinsic::Hands) {
            // Can't open doors without hands.
            return false;
        }
        if loc.blocks_walk() { return false; }
        true
    }

    /// Return whether the entity can move in a direction.
    pub fn can_step(self, dir: Dir6) -> bool {
        let place = world::with(|w| w.spatial.get(self));
        if let Some(Place::At(loc)) = place {
            let new_loc = loc + dir.to_v2();
            return self.can_enter(new_loc);
        }
        return false;
    }

    /// Try to move the entity in direction.
    pub fn step(self, dir: Dir6) {
        let place = world::with(|w| w.spatial.get(self));
        if let Some(Place::At(loc)) = place {
            let new_loc = loc + dir.to_v2();
            if self.can_enter(new_loc) {
                world::with_mut(|w| w.spatial.insert_at(self, new_loc));
                self.on_move_to(new_loc);
            }
        }
    }

    pub fn location(self) -> Option<Location> {
        match world::with(|w| w.spatial.get(self)) {
            Some(Place::At(loc)) => Some(loc),
            Some(Place::In(e)) => e.location(),
            _ => None
        }
    }

    pub fn distance_from(self, other: Entity) -> Option<int> {
        if let (Some(loc1), Some(loc2)) = (self.location(), other.location()) {
            loc1.distance_from(loc2)
        } else {
            None
        }
    }

// Damage and lifetime /////////////////////////////////////////////////

    pub fn damage(self, amount: int) {
        if amount == 0 { return; }

        let (_amount, kill) = world::with_mut(|w| {
            if let Some(&mut mob) = w.comp.mob.get_mut(self) {
                mob.hp -= amount;
                if mob.hp <= 0 {
                    // Remember this when we're out of the borrow.
                    return (amount, true);
                }
            } else {
                panic!("Damaging a non-mob");
            };
            (amount, false)
        });

        msg::push_msg(::Msg::Damage(self));
        if kill {
            self.kill();
        }
    }

    /// Do any game logic stuff related to this entity dying violently before
    /// deleting it.
    pub fn kill(self) {
        msg::push_msg(::Msg::Gib(self.location().unwrap()));
        self.delete();
    }

// Mob methods /////////////////////////////////////////////////////////

    pub fn is_mob(self) -> bool {
        world::with(|w| {
            if let Some(&::EntityKind::Mob(_)) = w.comp.kind.get(self) {
                return true;
            }
            return false;
        })
    }

    /// Return whether this mob is the player avatar.
    pub fn is_player(self) -> bool {
        world::with(|w| {
            if let Some(&::EntityKind::Mob(MobType::Player)) = w.comp.kind.get(self) {
                return true;
            }
            return false;
        })
    }

    pub fn has_status(self, status: Status) -> bool {
        world::with(|w| {
            if let Some(&mob) = w.comp.mob.get(self) {
                return mob.has_status(status);
            }
            return false;
        })
    }

    pub fn add_status(self, status: Status) {
        if !self.is_mob() { return; }
        world::with_mut(|w| w.comp.mob.get_mut(self).unwrap().add_status(status));
        assert!(self.has_status(status));
    }

    pub fn remove_status(self, status: Status) {
        if !self.is_mob() { return; }
        world::with_mut(|w| w.comp.mob.get_mut(self).unwrap().remove_status(status));
        assert!(!self.has_status(status));
    }

    pub fn has_intrinsic(self, intrinsic: Intrinsic) -> bool {
        world::with(|w| {
            if let Some(&::EntityKind::Mob(mt)) = w.comp.kind.get(self) {
                return mob::MOB_SPECS[mt as uint].intrinsics & intrinsic as int != 0;
            }
            return false;
        })
    }

    /// Return whether this entity is an awake mob.
    pub fn is_active(self) -> bool {
        self.is_mob() && !self.has_status(Status::Asleep)
    }

    /// Return if the entity is a mob that should get an update this frame
    /// based on its speed properties. Does not check for status effects like
    /// sleep that might prevent actual action.
    pub fn ticks_this_frame(self) -> bool {
        if !self.is_mob() { return false; }

        let tick = flags::get_tick();
        // Go through a cycle of 5 phases to get 4 possible speeds.
        // System idea from Jeff Lait.
        let phase = tick % 5;
        match phase {
            0 => return true,
            1 => return self.has_intrinsic(Intrinsic::Fast),
            2 => return true,
            3 => return self.has_status(Status::Quick),
            4 => return !self.has_intrinsic(Intrinsic::Slow)
                        && !self.has_status(Status::Slow),
            _ => panic!("Invalid action phase"),
        }
    }

    /// Return whether the entity is a mob that will act this frame.
    pub fn acts_this_frame(self) -> bool {
        if !self.is_active() { return false; }
        return self.ticks_this_frame();
    }

    /// Return whether the entity is an awake non-player mob and should be
    /// animated with a bob.
    pub fn is_bobbing(self) -> bool {
        self.is_active() && !self.is_player()
    }

    pub fn melee(self, dir: Dir6) {
        let loc = self.location().unwrap() + dir.to_v2();
        if let Some(e) = loc.mob_at() {
            // Attack power
            let p = world::with(|w| w.comp.mob.get(self).unwrap().power);
            if p == 0 {
                // No fight capacity.
                return;
            }

            // Every five points of power is one certain hit.
            let full = p / 5;
            // The fractional points are one probabilistic hit.
            let partial = (p % 5) as f64 / 5.0;

            let damage = full + if rng::p(partial) { 1 } else { 0 };
            e.damage(damage)
        }
    }

// AI methods /////////////////////////////////////////////////////////

    /// Top-level method called each frame to update the entity.
    pub fn update(self) {
        if self.is_mob() && !self.is_player() && self.ticks_this_frame() {
            self.mob_ai();
        }
    }

    /// AI routine for autonomous mobs.
    fn mob_ai(self) {
        assert!(self.is_mob());
        assert!(!self.is_player());
        assert!(self.ticks_this_frame());

        if self.has_status(Status::Asleep) {
            if let Some(p) = action::player() {
                // TODO: Line-of-sight, stealth concerns, other enemies than
                // player etc.
                if let Some(d) = p.distance_from(self) {
                    if d < 6 {
                        self.remove_status(Status::Asleep);
                    }
                }
            }

            return;
        }

        if let Some(p) = action::player() {
            let loc = self.location().unwrap();

            let vec_to_enemy = loc.v2_at(p.location().unwrap());
            if let Some(v) = vec_to_enemy {
                if v.hex_dist() == 1 {
                    // Melee range, hit.
                    self.melee(Dir6::from_v2(v));
                } else {
                    // Walk towards.
                    let pathing_depth = 16;
                    let pathing = Dijkstra::new(
                        vec![p.location().unwrap()], |&loc| !loc.blocks_walk(),
                        pathing_depth);

                    let steps = pathing.sorted_neighbors(&loc);
                    if steps.len() > 0 {
                        self.step(loc.dir6_towards(steps[0]).unwrap());
                    } else {
                        self.step(rng::with(|ref mut rng| rng.gen::<Dir6>()));
                        // TODO: Fall asleep if things get boring.
                    }
                }
            }
        }
    }

// Callbacks ///////////////////////////////////////////////////////////

    /// Called after the entity is moved to a new location.
    pub fn on_move_to(self, loc: Location) {
        self.do_fov();

        if self.is_player() {
            if loc.terrain().is_exit() {
                action::next_level();
            }
        }
    }

// Misc ////////////////////////////////////////////////////////////////

    fn has_map_memory(self) -> bool {
        world::with(|w| w.comp.map_memory.get(self).is_some())
    }

    fn do_fov(self) {
        let range = 12u;
        if let Some(loc) = self.location() {
            if self.has_map_memory() {
                let seen: Vec<Location> = Fov::new(
                    |pt| (loc + pt).blocks_sight(), range)
                    .map(|pt| loc + pt)
                    .collect();
                world::with_mut(|w| {
                    if let Some(ref mut mm) = w.comp.map_memory.get_mut(self) {
                        mm.seen.clear();
                        mm.seen.extend(seen.clone().into_iter());
                        mm.remembered.extend(seen.iter().map(|&x| x));
                    } else {
                        panic!("Couldn't bind map memory");
                    }
                });
            }
        }
    }

    pub fn forget_map(self) {
        if self.has_map_memory() {
            world::with_mut(|w| {
                if let Some(ref mut mm) = w.comp.map_memory.get_mut(self) {
                    mm.seen.clear();
                    mm.remembered.clear();
                } else {
                    panic!("Couldn't bind map memory");
                }
            });
        }
    }
}
<commit_msg>Damage dealt in combat actually sticks<commit_after>use std::rand::Rng;
use calx::dijkstra::Dijkstra;
use world;
use location::{Location};
use dir6::Dir6;
use flags;
use mob;
use mob::{Status, Intrinsic, MobType};
use geom::HexGeom;
use spatial::Place;
use action;
use fov::Fov;
use rng;
use msg;

/// Game object handle.
#[deriving(PartialEq, Eq, Clone, Hash, Show, Decodable, Encodable)]
pub struct Entity(pub uint);

impl Entity {
    /// Place the entity in a location in the game world.
    pub fn place(self, loc: Location) {
        world::with_mut(|w| w.spatial.insert_at(self, loc));
        self.on_move_to(loc);
    }

    /// Remove the entity from all the game world systems. THE ENTITY VALUE
    /// WILL BE INVALID FROM HERE ON AND USING IT WILL LEAD TO BUGS. THE
    /// CALLER IS RESPONSIBLE FOR ENSUING THAT AN ENTITY WILL NOT BE
    /// USED FROM ANYWHERE AFTER THE DELETE OPERATION.
    pub fn delete(self) {
        // LABYRINTH OF COMPONENTS
        // This needs to call every toplevel component system.
        world::with_mut(|w| w.comp.remove(self));
        world::with_mut(|w| w.spatial.remove(self));
        world::with_mut(|w| w.ecs.delete(self));
    }

    pub fn blocks_walk(self) -> bool { self.is_mob() }

    /// Return the kind of the entity.
    pub fn kind(self) -> ::EntityKind {
        // XXX: Will crash if an entity has no kind specified.
        world::with(|w| *w.comp.kind.get(self).unwrap())
    }

// Spatial methods /////////////////////////////////////////////////////

    pub fn can_enter(self, loc: Location) -> bool {
        if self.is_mob() && loc.has_mobs() { return false; }
        if loc.terrain().is_door() && !self.has_intrinsic(Intrinsic::Hands) {
            // Can't open doors without hands.
            return false;
        }
        if loc.blocks_walk() { return false; }
        true
    }

    /// Return whether the entity can move in a direction.
    pub fn can_step(self, dir: Dir6) -> bool {
        let place = world::with(|w| w.spatial.get(self));
        if let Some(Place::At(loc)) = place {
            let new_loc = loc + dir.to_v2();
            return self.can_enter(new_loc);
        }
        return false;
    }

    /// Try to move the entity in direction.
    pub fn step(self, dir: Dir6) {
        let place = world::with(|w| w.spatial.get(self));
        if let Some(Place::At(loc)) = place {
            let new_loc = loc + dir.to_v2();
            if self.can_enter(new_loc) {
                world::with_mut(|w| w.spatial.insert_at(self, new_loc));
                self.on_move_to(new_loc);
            }
        }
    }

    pub fn location(self) -> Option<Location> {
        match world::with(|w| w.spatial.get(self)) {
            Some(Place::At(loc)) => Some(loc),
            Some(Place::In(e)) => e.location(),
            _ => None
        }
    }

    pub fn distance_from(self, other: Entity) -> Option<int> {
        if let (Some(loc1), Some(loc2)) = (self.location(), other.location()) {
            loc1.distance_from(loc2)
        } else {
            None
        }
    }

// Damage and lifetime /////////////////////////////////////////////////

    pub fn damage(self, amount: int) {
        if amount == 0 { return; }

        let (_amount, kill) = world::with_mut(|w| {
            if let Some(ref mut mob) = w.comp.mob.get_mut(self) {
                mob.hp -= amount;
                if mob.hp <= 0 {
                    // Remember this when we're out of the borrow.
                    return (amount, true);
                }
            } else {
                panic!("Damaging a non-mob");
            };
            (amount, false)
        });

        msg::push_msg(::Msg::Damage(self));
        if kill {
            self.kill();
        }
    }

    /// Do any game logic stuff related to this entity dying violently before
    /// deleting it.
    pub fn kill(self) {
        msg::push_msg(::Msg::Gib(self.location().unwrap()));
        self.delete();
    }

// Mob methods /////////////////////////////////////////////////////////

    pub fn is_mob(self) -> bool {
        world::with(|w| {
            if let Some(&::EntityKind::Mob(_)) = w.comp.kind.get(self) {
                return true;
            }
            return false;
        })
    }

    /// Return whether this mob is the player avatar.
    pub fn is_player(self) -> bool {
        world::with(|w| {
            if let Some(&::EntityKind::Mob(MobType::Player)) = w.comp.kind.get(self) {
                return true;
            }
            return false;
        })
    }

    pub fn has_status(self, status: Status) -> bool {
        world::with(|w| {
            if let Some(&mob) = w.comp.mob.get(self) {
                return mob.has_status(status);
            }
            return false;
        })
    }

    pub fn add_status(self, status: Status) {
        if !self.is_mob() { return; }
        world::with_mut(|w| w.comp.mob.get_mut(self).unwrap().add_status(status));
        assert!(self.has_status(status));
    }

    pub fn remove_status(self, status: Status) {
        if !self.is_mob() { return; }
        world::with_mut(|w| w.comp.mob.get_mut(self).unwrap().remove_status(status));
        assert!(!self.has_status(status));
    }

    pub fn has_intrinsic(self, intrinsic: Intrinsic) -> bool {
        world::with(|w| {
            if let Some(&::EntityKind::Mob(mt)) = w.comp.kind.get(self) {
                return mob::MOB_SPECS[mt as uint].intrinsics & intrinsic as int != 0;
            }
            return false;
        })
    }

    /// Return whether this entity is an awake mob.
    pub fn is_active(self) -> bool {
        self.is_mob() && !self.has_status(Status::Asleep)
    }

    /// Return if the entity is a mob that should get an update this frame
    /// based on its speed properties. Does not check for status effects like
    /// sleep that might prevent actual action.
    pub fn ticks_this_frame(self) -> bool {
        if !self.is_mob() { return false; }

        let tick = flags::get_tick();
        // Go through a cycle of 5 phases to get 4 possible speeds.
        // System idea from Jeff Lait.
        let phase = tick % 5;
        match phase {
            0 => return true,
            1 => return self.has_intrinsic(Intrinsic::Fast),
            2 => return true,
            3 => return self.has_status(Status::Quick),
            4 => return !self.has_intrinsic(Intrinsic::Slow)
                        && !self.has_status(Status::Slow),
            _ => panic!("Invalid action phase"),
        }
    }

    /// Return whether the entity is a mob that will act this frame.
    pub fn acts_this_frame(self) -> bool {
        if !self.is_active() { return false; }
        return self.ticks_this_frame();
    }

    /// Return whether the entity is an awake non-player mob and should be
    /// animated with a bob.
    pub fn is_bobbing(self) -> bool {
        self.is_active() && !self.is_player()
    }

    pub fn melee(self, dir: Dir6) {
        let loc = self.location().unwrap() + dir.to_v2();
        if let Some(e) = loc.mob_at() {
            // Attack power
            let p = world::with(|w| w.comp.mob.get(self).unwrap().power);
            if p == 0 {
                // No fight capacity.
                return;
            }

            // Every five points of power is one certain hit.
            let full = p / 5;
            // The fractional points are one probabilistic hit.
            let partial = (p % 5) as f64 / 5.0;

            let damage = full + if rng::p(partial) { 1 } else { 0 };
            e.damage(damage)
        }
    }

// AI methods /////////////////////////////////////////////////////////

    /// Top-level method called each frame to update the entity.
    pub fn update(self) {
        if self.is_mob() && !self.is_player() && self.ticks_this_frame() {
            self.mob_ai();
        }
    }

    /// AI routine for autonomous mobs.
    fn mob_ai(self) {
        assert!(self.is_mob());
        assert!(!self.is_player());
        assert!(self.ticks_this_frame());

        if self.has_status(Status::Asleep) {
            if let Some(p) = action::player() {
                // TODO: Line-of-sight, stealth concerns, other enemies than
                // player etc.
                if let Some(d) = p.distance_from(self) {
                    if d < 6 {
                        self.remove_status(Status::Asleep);
                    }
                }
            }

            return;
        }

        if let Some(p) = action::player() {
            let loc = self.location().unwrap();

            let vec_to_enemy = loc.v2_at(p.location().unwrap());
            if let Some(v) = vec_to_enemy {
                if v.hex_dist() == 1 {
                    // Melee range, hit.
                    self.melee(Dir6::from_v2(v));
                } else {
                    // Walk towards.
                    let pathing_depth = 16;
                    let pathing = Dijkstra::new(
                        vec![p.location().unwrap()], |&loc| !loc.blocks_walk(),
                        pathing_depth);

                    let steps = pathing.sorted_neighbors(&loc);
                    if steps.len() > 0 {
                        self.step(loc.dir6_towards(steps[0]).unwrap());
                    } else {
                        self.step(rng::with(|ref mut rng| rng.gen::<Dir6>()));
                        // TODO: Fall asleep if things get boring.
                    }
                }
            }
        }
    }

// Callbacks ///////////////////////////////////////////////////////////

    /// Called after the entity is moved to a new location.
    pub fn on_move_to(self, loc: Location) {
        self.do_fov();

        if self.is_player() {
            if loc.terrain().is_exit() {
                action::next_level();
            }
        }
    }

// Misc ////////////////////////////////////////////////////////////////

    fn has_map_memory(self) -> bool {
        world::with(|w| w.comp.map_memory.get(self).is_some())
    }

    fn do_fov(self) {
        let range = 12u;
        if let Some(loc) = self.location() {
            if self.has_map_memory() {
                let seen: Vec<Location> = Fov::new(
                    |pt| (loc + pt).blocks_sight(), range)
                    .map(|pt| loc + pt)
                    .collect();
                world::with_mut(|w| {
                    if let Some(ref mut mm) = w.comp.map_memory.get_mut(self) {
                        mm.seen.clear();
                        mm.seen.extend(seen.clone().into_iter());
                        mm.remembered.extend(seen.iter().map(|&x| x));
                    } else {
                        panic!("Couldn't bind map memory");
                    }
                });
            }
        }
    }

    pub fn forget_map(self) {
        if self.has_map_memory() {
            world::with_mut(|w| {
                if let Some(ref mut mm) = w.comp.map_memory.get_mut(self) {
                    mm.seen.clear();
                    mm.remembered.clear();
                } else {
                    panic!("Couldn't bind map memory");
                }
            });
        }
    }
}
<|endoftext|>


<commit_before>use ffi::h5::hsize_t;
use ffi::h5i::{H5I_DATASPACE, hid_t};
use ffi::h5s::{H5S_UNLIMITED, H5Sget_simple_extent_dims, H5Sget_simple_extent_ndims,
               H5Screate_simple};

use error::Result;
use handle::{Handle, ID, get_id_type};
use object::Object;

use std::ptr;
use libc::c_int;

pub type Ix = usize;

pub trait Dimension {
    fn ndim(&self) -> usize;
    fn dims(&self) -> Vec<Ix>;

    fn size(&self) -> Ix {
        let dims = self.dims();
        if dims.is_empty() { 0 } else { dims.iter().fold(1, |acc, &el| acc * el) }
    }
}

impl<'a, T: Dimension> Dimension for &'a T {
    fn ndim(&self) -> usize { Dimension::ndim(*self) }
    fn dims(&self) -> Vec<Ix> { Dimension::dims(*self) }
}

impl Dimension for Vec<Ix> {
    fn ndim(&self) -> usize { self.len() }
    fn dims(&self) -> Vec<Ix> { self.clone() }
}

impl Dimension for () {
    fn ndim(&self) -> usize { 0 }
    fn dims(&self) -> Vec<Ix> { vec![] }
}

impl Dimension for Ix {
    fn ndim(&self) -> usize { 1 }
    fn dims(&self) -> Vec<Ix> { vec![*self] }
}

impl Dimension for (Ix,) {
    fn ndim(&self) -> usize { 1 }
    fn dims(&self) -> Vec<Ix> { vec![self.0] }
}

impl Dimension for (Ix, Ix) {
    fn ndim(&self) -> usize { 2 }
    fn dims(&self) -> Vec<Ix> { vec![self.0, self.1] }
}

pub struct Dataspace {
    handle: Handle,
}

impl Dataspace {
    pub fn new<D: Dimension>(d: D) -> Result<Dataspace> {
        let rank = d.ndim();
        let mut dims: Vec<hsize_t> = vec![];
        let mut max_dims: Vec<hsize_t> = vec![];
        for dim in d.dims().iter() {
            dims.push(*dim as hsize_t);
            max_dims.push(H5S_UNLIMITED);
        }
        Dataspace::from_id(h5try!(H5Screate_simple(rank as c_int, dims.as_ptr(),
                                                   max_dims.as_ptr())))
    }
}

impl Dimension for Dataspace {
    fn ndim(&self) -> usize {
        h5call!(H5Sget_simple_extent_ndims(self.id())).unwrap_or(0) as usize
    }

    fn dims(&self) -> Vec<Ix> {
        let ndim = self.ndim();
        if ndim > 0 {
            let mut dims: Vec<hsize_t> = Vec::with_capacity(ndim);
            unsafe { dims.set_len(ndim); }
            if h5call!(H5Sget_simple_extent_dims(self.id(), dims.as_mut_ptr(),
                                                 ptr::null_mut())).is_ok() {
                return dims.iter().cloned().map(|x| x as usize).collect();
            }
        }
        vec![]
    }
}

impl ID for Dataspace {
    fn id(&self) -> hid_t {
        self.handle.id()
    }

    fn from_id(id: hid_t) -> Result<Dataspace> {
        match get_id_type(id) {
            H5I_DATASPACE => Ok(Dataspace { handle: try!(Handle::new(id)) }),
            _             => Err(From::from(format!("Invalid dataspace id: {}", id))),
        }
    }
}

impl Object for Dataspace {}

#[cfg(test)]
mod tests {
    use super::{Dimension, Ix};

    #[test]
    pub fn test_dimension() {
        fn f<D: Dimension>(d: D) -> (usize, Vec<Ix>, Ix) { (d.ndim(), d.dims(), d.size()) }

        assert_eq!(f(()), (0, vec![], 0));
        assert_eq!(f(&()), (0, vec![], 0));
        assert_eq!(f(2), (1, vec![2], 2));
        assert_eq!(f(&3), (1, vec![3], 3));
        assert_eq!(f((4,)), (1, vec![4], 4));
        assert_eq!(f(&(5,)), (1, vec![5], 5));
        assert_eq!(f((1, 2)), (2, vec![1, 2], 2));
        assert_eq!(f(&(3, 4)), (2, vec![3, 4], 12));
        assert_eq!(f(vec![2, 3]), (2, vec![2, 3], 6));
        assert_eq!(f(&vec![4, 5]), (2, vec![4, 5], 20));
    }
}
<commit_msg>Implement Debug and Display for Dataspace<commit_after>use ffi::h5::hsize_t;
use ffi::h5i::{H5I_DATASPACE, hid_t};
use ffi::h5s::{H5S_UNLIMITED, H5Sget_simple_extent_dims, H5Sget_simple_extent_ndims,
               H5Screate_simple};

use error::Result;
use handle::{Handle, ID, get_id_type};
use object::Object;

use std::fmt;
use std::ptr;
use libc::c_int;

pub type Ix = usize;

pub trait Dimension {
    fn ndim(&self) -> usize;
    fn dims(&self) -> Vec<Ix>;

    fn size(&self) -> Ix {
        let dims = self.dims();
        if dims.is_empty() { 0 } else { dims.iter().fold(1, |acc, &el| acc * el) }
    }
}

impl<'a, T: Dimension> Dimension for &'a T {
    fn ndim(&self) -> usize { Dimension::ndim(*self) }
    fn dims(&self) -> Vec<Ix> { Dimension::dims(*self) }
}

impl Dimension for Vec<Ix> {
    fn ndim(&self) -> usize { self.len() }
    fn dims(&self) -> Vec<Ix> { self.clone() }
}

impl Dimension for () {
    fn ndim(&self) -> usize { 0 }
    fn dims(&self) -> Vec<Ix> { vec![] }
}

impl Dimension for Ix {
    fn ndim(&self) -> usize { 1 }
    fn dims(&self) -> Vec<Ix> { vec![*self] }
}

impl Dimension for (Ix,) {
    fn ndim(&self) -> usize { 1 }
    fn dims(&self) -> Vec<Ix> { vec![self.0] }
}

impl Dimension for (Ix, Ix) {
    fn ndim(&self) -> usize { 2 }
    fn dims(&self) -> Vec<Ix> { vec![self.0, self.1] }
}

pub struct Dataspace {
    handle: Handle,
}

impl Dataspace {
    pub fn new<D: Dimension>(d: D) -> Result<Dataspace> {
        let rank = d.ndim();
        let mut dims: Vec<hsize_t> = vec![];
        let mut max_dims: Vec<hsize_t> = vec![];
        for dim in d.dims().iter() {
            dims.push(*dim as hsize_t);
            max_dims.push(H5S_UNLIMITED);
        }
        Dataspace::from_id(h5try!(H5Screate_simple(rank as c_int, dims.as_ptr(),
                                                   max_dims.as_ptr())))
    }
}

impl Dimension for Dataspace {
    fn ndim(&self) -> usize {
        h5call!(H5Sget_simple_extent_ndims(self.id())).unwrap_or(0) as usize
    }

    fn dims(&self) -> Vec<Ix> {
        let ndim = self.ndim();
        if ndim > 0 {
            let mut dims: Vec<hsize_t> = Vec::with_capacity(ndim);
            unsafe { dims.set_len(ndim); }
            if h5call!(H5Sget_simple_extent_dims(self.id(), dims.as_mut_ptr(),
                                                 ptr::null_mut())).is_ok() {
                return dims.iter().cloned().map(|x| x as usize).collect();
            }
        }
        vec![]
    }
}

impl ID for Dataspace {
    fn id(&self) -> hid_t {
        self.handle.id()
    }

    fn from_id(id: hid_t) -> Result<Dataspace> {
        match get_id_type(id) {
            H5I_DATASPACE => Ok(Dataspace { handle: try!(Handle::new(id)) }),
            _             => Err(From::from(format!("Invalid dataspace id: {}", id))),
        }
    }
}

impl Object for Dataspace {}

impl fmt::Debug for Dataspace {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }
}

impl fmt::Display for Dataspace {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if !self.is_valid() {
            return "<HDF5 dataspace: invalid id>".fmt(f);
        }
        let mut dims = String::new();
        for (i, dim) in self.dims().iter().enumerate() {
            if i > 0 {
                dims.push_str(", ");
            }
            dims.push_str(&format!("{}", dim));
        }
        if self.ndim() == 1 {
            dims.push_str(",");
        }
        format!("<HDF5 dataspace: ({})>", dims).fmt(f)
    }
}

#[cfg(test)]
mod tests {
    use super::{Dimension, Ix, Dataspace};

    #[test]
    pub fn test_dimension() {
        fn f<D: Dimension>(d: D) -> (usize, Vec<Ix>, Ix) { (d.ndim(), d.dims(), d.size()) }

        assert_eq!(f(()), (0, vec![], 0));
        assert_eq!(f(&()), (0, vec![], 0));
        assert_eq!(f(2), (1, vec![2], 2));
        assert_eq!(f(&3), (1, vec![3], 3));
        assert_eq!(f((4,)), (1, vec![4], 4));
        assert_eq!(f(&(5,)), (1, vec![5], 5));
        assert_eq!(f((1, 2)), (2, vec![1, 2], 2));
        assert_eq!(f(&(3, 4)), (2, vec![3, 4], 12));
        assert_eq!(f(vec![2, 3]), (2, vec![2, 3], 6));
        assert_eq!(f(&vec![4, 5]), (2, vec![4, 5], 20));
    }

    #[test]
    pub fn test_debug_display() {
        assert_eq!(format!("{}", Dataspace::new(()).unwrap()), "<HDF5 dataspace: ()>");
        assert_eq!(format!("{:?}", Dataspace::new(()).unwrap()), "<HDF5 dataspace: ()>");
        assert_eq!(format!("{}", Dataspace::new(3).unwrap()), "<HDF5 dataspace: (3,)>");
        assert_eq!(format!("{:?}", Dataspace::new(3).unwrap()), "<HDF5 dataspace: (3,)>");
        assert_eq!(format!("{}", Dataspace::new((1, 2)).unwrap()), "<HDF5 dataspace: (1, 2)>");
        assert_eq!(format!("{:?}", Dataspace::new((1, 2)).unwrap()), "<HDF5 dataspace: (1, 2)>");
    }
}
<|endoftext|>


<commit_before>use std::f64;
use std::f64::consts::PI;

use radians::Radians;
use {Distance};

/// Represents the various supported speeds that the turtle can move at
///
/// See [`Turtle::set_speed` method](struct.Turtle.html#method.set_speed) for more information.
#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
pub enum Speed {
    One,
    Two,
    Three,
    Four,
    Five,
    Six,
    Seven,
    Eight,
    Nine,
    Ten,
    Instant,
}

impl Speed {
    /// Converts a speed to its value as pixels per second
    pub fn to_absolute(self) -> Distance {
        use self::Speed::*;
        // Arbitrary values that can be tweaked
        // Just make sure to keep invariants like Five > Three, etc.
        match self {
            One => 10.,
            Two => 20.,
            Three => 30.,
            Four => 40.,
            Five => 50.,
            Six => 60.,
            Seven => 70.,
            Eight => 80.,
            Nine => 90.,
            Ten => 100.,
            Instant => f64::INFINITY,
        }
    }

    /// Converts a speed to its value as radians per second
    pub fn to_rotation(self) -> Radians {
        use self::Speed::*;
        // Arbitrary values that can be tweaked
        // Just make sure to keep invariants like Five > Three, etc.
        Radians::from_radians_value(match self {
            One => PI / 16.,
            Two => PI / 14.,
            Three => PI / 12.,
            Four => PI / 10.,
            Five =>  PI / 8.,
            Six => PI / 6.,
            Seven => PI / 4.,
            Eight => PI / 3.,
            Nine => PI / 2.,
            Ten => PI / 1.,
            Instant => f64::INFINITY,
        })
    }
}

impl<'a> From<&'a str> for Speed {
    fn from(s: &'a str) -> Self {
        use Speed::*;

        match s {
            "slowest" => One,
            "slow" => Three,
            "normal" => Six,
            "fast" => Ten,
            "fastest" => Instant,
            _ => panic!("Invalid speed specified, use one of the words: 'slowest', 'slow', 'normal', 'fast', 'fastest'"),
        }
    }
}

impl From<i32> for Speed {
    fn from(n: i32) -> Self {
        use Speed::*;

        match n {
            1 => One,
            2 => Two,
            3 => Three,
            4 => Four,
            5 => Five,
            6 => Six,
            7 => Seven,
            8 => Eight,
            9 => Nine,
            10 => Ten,
            _ => Instant,
        }
    }
}
<commit_msg>Adjusting speeds<commit_after>use std::f64;
use std::f64::consts::PI;

use radians::Radians;
use {Distance};

/// Represents the various supported speeds that the turtle can move at
///
/// See [`Turtle::set_speed` method](struct.Turtle.html#method.set_speed) for more information.
#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
pub enum Speed {
    One,
    Two,
    Three,
    Four,
    Five,
    Six,
    Seven,
    Eight,
    Nine,
    Ten,
    Instant,
}

impl Speed {
    /// Converts a speed to its value as pixels per second
    pub fn to_absolute(self) -> Distance {
        use self::Speed::*;
        // Arbitrary values that can be tweaked
        // Just make sure to keep invariants like Five > Three, etc.
        match self {
            One => 10.,
            Two => 50.,
            Three => 100.,
            Four => 150.,
            Five => 200.,
            Six => 250.,
            Seven => 300.,
            Eight => 350.,
            Nine => 400.,
            Ten => 500.,
            Instant => f64::INFINITY,
        }
    }

    /// Converts a speed to its value as radians per second
    pub fn to_rotation(self) -> Radians {
        use self::Speed::*;
        // Arbitrary values that can be tweaked
        // Just make sure to keep invariants like Five > Three, etc.
        Radians::from_radians_value(match self {
            One => 0.3 * PI,
            Two => 0.6 * PI,
            Three => 0.9 * PI,
            Four => 1.2 * PI,
            Five =>  1.5 * PI,
            Six => 1.8 * PI,
            Seven => 2.1 * PI,
            Eight => 2.4 * PI,
            Nine => 2.7 * PI,
            Ten => 3.0 * PI,
            Instant => f64::INFINITY,
        })
    }
}

impl<'a> From<&'a str> for Speed {
    fn from(s: &'a str) -> Self {
        use Speed::*;

        match s {
            "slowest" => One,
            "slow" => Three,
            "normal" => Six,
            "fast" => Ten,
            "fastest" => Instant,
            _ => panic!("Invalid speed specified, use one of the words: 'slowest', 'slow', 'normal', 'fast', 'fastest'"),
        }
    }
}

impl From<i32> for Speed {
    fn from(n: i32) -> Self {
        use Speed::*;

        match n {
            1 => One,
            2 => Two,
            3 => Three,
            4 => Four,
            5 => Five,
            6 => Six,
            7 => Seven,
            8 => Eight,
            9 => Nine,
            10 => Ten,
            _ => Instant,
        }
    }
}
<|endoftext|>


<commit_before>use UndoCmd;

/// `UndoStack` maintains a stack of `UndoCmd`s that can be undone and redone by using methods
/// on the `UndoStack`.
///
/// `UndoStack` will notice when it's state changes to either dirty or clean, and the user can
/// set methods that should be called for either state change. This is useful for example if
/// you want to automatically enable or disable undo or redo buttons based on there are any
/// more actions that can be undone or redone.
pub struct UndoStack<'a> {
    // All commands on the stack.
    stack: Vec<Box<UndoCmd + 'a>>,
    // Current position in the stack.
    len: usize,
    // Called when the state changes from dirty to clean.
    on_clean: Option<Box<FnMut() + 'a>>,
    // Called when the state changes from clean to dirty.
    on_dirty: Option<Box<FnMut() + 'a>>,
}

impl<'a> UndoStack<'a> {
    /// Creates a new `UndoStack`.
    #[inline]
    pub fn new() -> Self {
        UndoStack {
            stack: Vec::new(),
            len: 0,
            on_clean: None,
            on_dirty: None,
        }
    }

    /// Creates a new `UndoStack` with the specified capacity.
    #[inline]
    pub fn with_capacity(capacity: usize) -> Self {
        UndoStack {
            stack: Vec::with_capacity(capacity),
            len: 0,
            on_clean: None,
            on_dirty: None,
        }
    }

    /// Returns the capacity of the `UndoStack`.
    #[inline]
    pub fn capacity(&self) -> usize {
        self.stack.capacity()
    }

    /// Reserves capacity for at least `additional` more commands to be inserted in the given stack.
    /// The stack may reserve more space to avoid frequent reallocations.
    ///
    /// # Panics
    /// Panics if the new capacity overflows usize.
    #[inline]
    pub fn reserve(&mut self, additional: usize) {
        self.stack.reserve(additional);
    }

    /// Shrinks the capacity of the `UndoStack` as much as possible.
    #[inline]
    pub fn shrink_to_fit(&mut self) {
        self.stack.shrink_to_fit();
    }

    /// Sets what should happen if the state changes from dirty to clean.
    /// By default the `UndoStack` does nothing when the state changes.
    ///
    /// Note: An empty stack is clean, so the first push will not trigger this method.
    ///
    /// # Examples
    /// ```
    /// # use undo::UndoStack;
    /// let mut x = 0;
    /// let stack = UndoStack::new()
    ///     .on_clean(|| x += 1);
    /// ```
    #[inline]
    pub fn on_clean<F>(mut self, f: F) -> Self
        where F: FnMut() + 'a,
    {
        self.on_clean = Some(Box::new(f));
        self
    }

    /// Sets what should happen if the state changes from clean to dirty.
    /// By default the `UndoStack` does nothing when the state changes.
    ///
    /// # Examples
    /// ```
    /// # use undo::UndoStack;
    /// let mut x = 0;
    /// let stack = UndoStack::new()
    ///     .on_dirty(|| x += 1);
    /// ```
    #[inline]
    pub fn on_dirty<F>(mut self, f: F) -> Self
        where F: FnMut() + 'a,
    {
        self.on_dirty = Some(Box::new(f));
        self
    }

    /// Returns `true` if the state of the stack is clean, `false` otherwise.
    #[inline]
    pub fn is_clean(&self) -> bool {
        self.len == self.stack.len()
    }

    /// Returns `true` if the state of the stack is dirty, `false` otherwise.
    #[inline]
    pub fn is_dirty(&self) -> bool {
        !self.is_clean()
    }

    /// Pushes a `UndoCmd` to the top of the `UndoStack` and executes its [`redo`] method.
    /// This pops off all `UndoCmd`s that is above the active command from the `UndoStack`.
    ///
    /// If `cmd`s id is equal to the current top command, the two commands are merged.
    ///
    /// [`redo`]: trait.UndoCmd.html#tymethod.redo
    pub fn push<T>(&mut self, mut cmd: T)
        where T: UndoCmd + 'a,
    {
        let is_dirty = self.is_dirty();
        let len = self.len;
        // Pop off all elements after len from stack.
        self.stack.truncate(len);
        cmd.redo();

        // Check if we should merge cmd with the top command on stack.
        let id = cmd.id();
        if len > 0 && id.is_some() && id == unsafe { self.stack.get_unchecked(len - 1).id() } {

            // MergeCmd is the result of the merging.
            struct MergeCmd<'a> {
                cmd1: Box<UndoCmd + 'a>,
                cmd2: Box<UndoCmd + 'a>,
            }

            impl<'a> UndoCmd for MergeCmd<'a> {
                #[inline]
                fn redo(&mut self) {
                    self.cmd1.redo();
                    self.cmd2.redo();
                }

                #[inline]
                fn undo(&mut self) {
                    self.cmd2.undo();
                    self.cmd1.undo();
                }

                #[inline]
                fn id(&self) -> Option<u64> {
                    self.cmd1.id()
                }
            }

            // Merge the command with the one on the top of the stack.
            let cmd = MergeCmd {
                cmd1: unsafe {
                    // Unchecked pop.
                    self.stack.set_len(len - 1);
                    ::std::ptr::read(self.stack.get_unchecked(self.stack.len()))
                },
                cmd2: Box::new(cmd),
            };
            self.stack.push(Box::new(cmd));
        } else {
            self.stack.push(Box::new(cmd));
            self.len += 1;
        }

        // State is always clean after a push, check if it was dirty before.
        if is_dirty {
            if let Some(ref mut f) = self.on_clean {
                f();
            }
        }
    }

    /// Calls the [`redo`] method for the active `UndoCmd` and sets the next `UndoCmd` as the new
    /// active one.
    ///
    /// Calling this method when there are no more commands to redo does nothing.
    ///
    /// [`redo`]: trait.UndoCmd.html#tymethod.redo
    pub fn redo(&mut self) {
        if self.len < self.stack.len() {
            let is_dirty = self.is_dirty();
            unsafe {
                let cmd = self.stack.get_unchecked_mut(self.len);
                cmd.redo();
            }
            self.len += 1;
            // Check if stack went from dirty to clean.
            if is_dirty && self.is_clean() {
                if let Some(ref mut f) = self.on_clean {
                    f();
                }
            }
        }
    }

    /// Calls the [`undo`] method for the active `UndoCmd` and sets the previous `UndoCmd` as the
    /// new active one.
    ///
    /// Calling this method when there are no more commands to undo does nothing.
    ///
    /// [`undo`]: trait.UndoCmd.html#tymethod.undo
    pub fn undo(&mut self) {
        if self.len > 0 {
            let is_clean = self.is_clean();
            self.len -= 1;
            unsafe {
                let cmd = self.stack.get_unchecked_mut(self.len);
                cmd.undo();
            }
            // Check if stack went from clean to dirty.
            if is_clean && self.is_dirty() {
                if let Some(ref mut f) = self.on_dirty {
                    f();
                }
            }
        }
    }
}

#[cfg(test)]
mod test {
    use {UndoStack, UndoCmd};

    #[test]
    fn pop() {
        use std::rc::Rc;
        use std::cell::{Cell, RefCell};

        /// Pops an element from a vector.
        #[derive(Clone)]
        struct PopCmd {
            vec: Rc<RefCell<Vec<i32>>>,
            e: Option<i32>,
        }

        impl UndoCmd for PopCmd {
            fn redo(&mut self) {
                self.e = self.vec.borrow_mut().pop();
            }

            fn undo(&mut self) {
                self.vec.borrow_mut().push(self.e.unwrap());
                self.e = None;
            }
        }

        let a = Cell::new(0);
        let b = Cell::new(0);
        // We need to use Rc<RefCell> since all commands are going to mutate the vec.
        let vec = Rc::new(RefCell::new(vec![1, 2, 3]));
        let mut undo_stack = UndoStack::with_capacity(3)
            .on_clean(|| a.set(1))
            .on_dirty(|| b.set(1));

        let cmd = PopCmd { vec: vec.clone(), e: None };
        undo_stack.push(cmd.clone());
        undo_stack.push(cmd.clone());
        undo_stack.push(cmd.clone());

        assert!(vec.borrow().is_empty());

        assert_eq!(b.get(), 0);
        undo_stack.undo();
        assert_eq!(b.get(), 1);
        b.set(0);

        undo_stack.undo();
        undo_stack.undo();

        assert_eq!(vec, Rc::new(RefCell::new(vec![1, 2, 3])));

        assert_eq!(a.get(), 0);
        undo_stack.push(cmd.clone());
        assert_eq!(a.get(), 1);
        a.set(0);

        assert_eq!(vec, Rc::new(RefCell::new(vec![1, 2])));

        assert_eq!(b.get(), 0);
        undo_stack.undo();
        assert_eq!(b.get(), 1);
        b.set(0);

        assert_eq!(vec, Rc::new(RefCell::new(vec![1, 2, 3])));

        assert_eq!(a.get(), 0);
        undo_stack.redo();
        assert_eq!(a.get(), 1);
        a.set(0);

        assert_eq!(vec, Rc::new(RefCell::new(vec![1, 2])));
    }
}
<commit_msg>Allow unused variables in examples<commit_after>use UndoCmd;

/// `UndoStack` maintains a stack of `UndoCmd`s that can be undone and redone by using methods
/// on the `UndoStack`.
///
/// `UndoStack` will notice when it's state changes to either dirty or clean, and the user can
/// set methods that should be called for either state change. This is useful for example if
/// you want to automatically enable or disable undo or redo buttons based on there are any
/// more actions that can be undone or redone.
pub struct UndoStack<'a> {
    // All commands on the stack.
    stack: Vec<Box<UndoCmd + 'a>>,
    // Current position in the stack.
    len: usize,
    // Called when the state changes from dirty to clean.
    on_clean: Option<Box<FnMut() + 'a>>,
    // Called when the state changes from clean to dirty.
    on_dirty: Option<Box<FnMut() + 'a>>,
}

impl<'a> UndoStack<'a> {
    /// Creates a new `UndoStack`.
    #[inline]
    pub fn new() -> Self {
        UndoStack {
            stack: Vec::new(),
            len: 0,
            on_clean: None,
            on_dirty: None,
        }
    }

    /// Creates a new `UndoStack` with the specified capacity.
    #[inline]
    pub fn with_capacity(capacity: usize) -> Self {
        UndoStack {
            stack: Vec::with_capacity(capacity),
            len: 0,
            on_clean: None,
            on_dirty: None,
        }
    }

    /// Returns the capacity of the `UndoStack`.
    #[inline]
    pub fn capacity(&self) -> usize {
        self.stack.capacity()
    }

    /// Reserves capacity for at least `additional` more commands to be inserted in the given stack.
    /// The stack may reserve more space to avoid frequent reallocations.
    ///
    /// # Panics
    /// Panics if the new capacity overflows usize.
    #[inline]
    pub fn reserve(&mut self, additional: usize) {
        self.stack.reserve(additional);
    }

    /// Shrinks the capacity of the `UndoStack` as much as possible.
    #[inline]
    pub fn shrink_to_fit(&mut self) {
        self.stack.shrink_to_fit();
    }

    /// Sets what should happen if the state changes from dirty to clean.
    /// By default the `UndoStack` does nothing when the state changes.
    ///
    /// Note: An empty stack is clean, so the first push will not trigger this method.
    ///
    /// # Examples
    /// ```
    /// # #![allow(unused_variables)]
    /// # use undo::UndoStack;
    /// let mut x = 0;
    /// let stack = UndoStack::new()
    ///     .on_clean(|| x += 1);
    /// ```
    #[inline]
    pub fn on_clean<F>(mut self, f: F) -> Self
        where F: FnMut() + 'a,
    {
        self.on_clean = Some(Box::new(f));
        self
    }

    /// Sets what should happen if the state changes from clean to dirty.
    /// By default the `UndoStack` does nothing when the state changes.
    ///
    /// # Examples
    /// ```
    /// # #![allow(unused_variables)]
    /// # use undo::UndoStack;
    /// let mut x = 0;
    /// let stack = UndoStack::new()
    ///     .on_dirty(|| x += 1);
    /// ```
    #[inline]
    pub fn on_dirty<F>(mut self, f: F) -> Self
        where F: FnMut() + 'a,
    {
        self.on_dirty = Some(Box::new(f));
        self
    }

    /// Returns `true` if the state of the stack is clean, `false` otherwise.
    #[inline]
    pub fn is_clean(&self) -> bool {
        self.len == self.stack.len()
    }

    /// Returns `true` if the state of the stack is dirty, `false` otherwise.
    #[inline]
    pub fn is_dirty(&self) -> bool {
        !self.is_clean()
    }

    /// Pushes a `UndoCmd` to the top of the `UndoStack` and executes its [`redo`] method.
    /// This pops off all `UndoCmd`s that is above the active command from the `UndoStack`.
    ///
    /// If `cmd`s id is equal to the current top command, the two commands are merged.
    ///
    /// [`redo`]: trait.UndoCmd.html#tymethod.redo
    pub fn push<T>(&mut self, mut cmd: T)
        where T: UndoCmd + 'a,
    {
        let is_dirty = self.is_dirty();
        let len = self.len;
        // Pop off all elements after len from stack.
        self.stack.truncate(len);
        cmd.redo();

        // Check if we should merge cmd with the top command on stack.
        let id = cmd.id();
        if len > 0 && id.is_some() && id == unsafe { self.stack.get_unchecked(len - 1).id() } {

            // MergeCmd is the result of the merging.
            struct MergeCmd<'a> {
                cmd1: Box<UndoCmd + 'a>,
                cmd2: Box<UndoCmd + 'a>,
            }

            impl<'a> UndoCmd for MergeCmd<'a> {
                #[inline]
                fn redo(&mut self) {
                    self.cmd1.redo();
                    self.cmd2.redo();
                }

                #[inline]
                fn undo(&mut self) {
                    self.cmd2.undo();
                    self.cmd1.undo();
                }

                #[inline]
                fn id(&self) -> Option<u64> {
                    self.cmd1.id()
                }
            }

            // Merge the command with the one on the top of the stack.
            let cmd = MergeCmd {
                cmd1: unsafe {
                    // Unchecked pop.
                    self.stack.set_len(len - 1);
                    ::std::ptr::read(self.stack.get_unchecked(self.stack.len()))
                },
                cmd2: Box::new(cmd),
            };
            self.stack.push(Box::new(cmd));
        } else {
            self.stack.push(Box::new(cmd));
            self.len += 1;
        }

        // State is always clean after a push, check if it was dirty before.
        if is_dirty {
            if let Some(ref mut f) = self.on_clean {
                f();
            }
        }
    }

    /// Calls the [`redo`] method for the active `UndoCmd` and sets the next `UndoCmd` as the new
    /// active one.
    ///
    /// Calling this method when there are no more commands to redo does nothing.
    ///
    /// [`redo`]: trait.UndoCmd.html#tymethod.redo
    pub fn redo(&mut self) {
        if self.len < self.stack.len() {
            let is_dirty = self.is_dirty();
            unsafe {
                let cmd = self.stack.get_unchecked_mut(self.len);
                cmd.redo();
            }
            self.len += 1;
            // Check if stack went from dirty to clean.
            if is_dirty && self.is_clean() {
                if let Some(ref mut f) = self.on_clean {
                    f();
                }
            }
        }
    }

    /// Calls the [`undo`] method for the active `UndoCmd` and sets the previous `UndoCmd` as the
    /// new active one.
    ///
    /// Calling this method when there are no more commands to undo does nothing.
    ///
    /// [`undo`]: trait.UndoCmd.html#tymethod.undo
    pub fn undo(&mut self) {
        if self.len > 0 {
            let is_clean = self.is_clean();
            self.len -= 1;
            unsafe {
                let cmd = self.stack.get_unchecked_mut(self.len);
                cmd.undo();
            }
            // Check if stack went from clean to dirty.
            if is_clean && self.is_dirty() {
                if let Some(ref mut f) = self.on_dirty {
                    f();
                }
            }
        }
    }
}

#[cfg(test)]
mod test {
    use {UndoStack, UndoCmd};

    #[test]
    fn pop() {
        use std::rc::Rc;
        use std::cell::{Cell, RefCell};

        /// Pops an element from a vector.
        #[derive(Clone)]
        struct PopCmd {
            vec: Rc<RefCell<Vec<i32>>>,
            e: Option<i32>,
        }

        impl UndoCmd for PopCmd {
            fn redo(&mut self) {
                self.e = self.vec.borrow_mut().pop();
            }

            fn undo(&mut self) {
                self.vec.borrow_mut().push(self.e.unwrap());
                self.e = None;
            }
        }

        let a = Cell::new(0);
        let b = Cell::new(0);
        // We need to use Rc<RefCell> since all commands are going to mutate the vec.
        let vec = Rc::new(RefCell::new(vec![1, 2, 3]));
        let mut undo_stack = UndoStack::with_capacity(3)
            .on_clean(|| a.set(1))
            .on_dirty(|| b.set(1));

        let cmd = PopCmd { vec: vec.clone(), e: None };
        undo_stack.push(cmd.clone());
        undo_stack.push(cmd.clone());
        undo_stack.push(cmd.clone());

        assert!(vec.borrow().is_empty());

        assert_eq!(b.get(), 0);
        undo_stack.undo();
        assert_eq!(b.get(), 1);
        b.set(0);

        undo_stack.undo();
        undo_stack.undo();

        assert_eq!(vec, Rc::new(RefCell::new(vec![1, 2, 3])));

        assert_eq!(a.get(), 0);
        undo_stack.push(cmd.clone());
        assert_eq!(a.get(), 1);
        a.set(0);

        assert_eq!(vec, Rc::new(RefCell::new(vec![1, 2])));

        assert_eq!(b.get(), 0);
        undo_stack.undo();
        assert_eq!(b.get(), 1);
        b.set(0);

        assert_eq!(vec, Rc::new(RefCell::new(vec![1, 2, 3])));

        assert_eq!(a.get(), 0);
        undo_stack.redo();
        assert_eq!(a.get(), 1);
        a.set(0);

        assert_eq!(vec, Rc::new(RefCell::new(vec![1, 2])));
    }
}
<|endoftext|>


<commit_before>use std::slice::{Iter, IterMut};

#[derive(Clone)]
pub struct Stack<T> {
    vec: Vec<T>,
    focus: Option<usize>,
}

impl<T> Stack<T> {
    pub fn new() -> Stack<T> {
        Stack {
            vec: Vec::new(),
            focus: None,
        }
    }

    pub fn push(&mut self, value: T) {
        self.vec.push(value);
        self.ensure_focus();
    }

    pub fn remove<P>(&mut self, p: P) -> T
        where P: FnMut(&T) -> bool
    {
        let position = self.vec
            .iter()
            .position(p)
            .expect("No element in stack matches predicate");
        let element = self.vec.remove(position);
        // We might have removed the focus element. A non-empty stack should always
        // focus something.
        self.ensure_focus();
        element
    }

    pub fn iter(&self) -> Iter<T> {
        self.vec.iter()
    }

    pub fn iter_mut(&mut self) -> IterMut<T> {
        self.vec.iter_mut()
    }

    pub fn focused(&self) -> Option<&T> {
        self.focus.and_then(|idx| self.vec.get(idx))
    }

    pub fn focused_mut(&mut self) -> Option<&mut T> {
        self.focus.and_then(move |idx| self.vec.get_mut(idx))
    }

    /// Focuses the first element in the stack that matches the predicate.
    ///
    /// Panics if no element matches the predicate.
    pub fn focus<P>(&mut self, p: P)
        where P: FnMut(&T) -> bool
    {
        let position = self.vec
            .iter()
            .position(p)
            .expect("No element in stack matches predicate");
        self.focus = Some(position);
    }

    fn ensure_focus(&mut self) {
        self.focus = self.focus
            .or(if self.vec.is_empty() { None } else { Some(0) });
    }

    fn next_index(&self, index: usize) -> usize {
        (index + 1) % self.vec.len()
    }

    fn previous_index(&self, index: usize) -> usize {
        if index == 0 {
            self.vec.len() - 1
        } else {
            (index - 1) % self.vec.len()
        }
    }

    pub fn focus_next(&mut self) {
        self.focus = self.focus.map(|idx| self.next_index(idx));
    }

    pub fn focus_previous(&mut self) {
        self.focus = self.focus.map(|idx| self.previous_index(idx));
    }

    pub fn shuffle_next(&mut self) {
        if let Some(current_idx) = self.focus {
            let next_idx = self.next_index(current_idx);
            if next_idx == 0 {
                let item = self.vec.remove(current_idx);
                self.vec.insert(0, item);
            } else {
                self.vec.swap(current_idx, next_idx);
            }
            self.focus = Some(next_idx);
        }
    }

    pub fn shuffle_previous(&mut self) {
        if let Some(current_idx) = self.focus {
            let prev_idx = self.previous_index(current_idx);
            if prev_idx == self.vec.len() - 1 {
                let item = self.vec.remove(current_idx);
                self.vec.push(item);
            } else {
                self.vec.swap(current_idx, prev_idx);
            }
            self.focus = Some(prev_idx);
        }
    }
}

impl<T> From<Vec<T>> for Stack<T> {
    fn from(vec: Vec<T>) -> Self {
        let mut stack = Stack {
            vec: vec,
            focus: None,
        };
        stack.ensure_focus();
        stack
    }
}

#[cfg(test)]
mod test {

    use super::Stack;
    use std::fmt::Debug;
    use std::rc::Rc;

    #[test]
    fn test_push() {
        let mut stack = Stack::<u8>::new();
        stack.push(2);
        assert_eq!(stack.vec, vec![2]);
    }

    #[test]
    fn test_remove() {
        let mut stack = Stack::<u8>::new();
        stack.push(2);
        stack.push(3);
        stack.push(4);
        stack.remove(|v| v == &3);
        assert_eq!(stack.vec, vec![2, 4]);
    }

    #[test]
    fn test_iter() {
        let mut stack = Stack::<u8>::new();
        stack.push(2);
        stack.push(3);
        stack.push(4);
        let mut iter = stack.iter();
        assert_eq!(iter.next(), Some(&2));
        assert_eq!(iter.next(), Some(&3));
        assert_eq!(iter.next(), Some(&4));
        assert_eq!(iter.next(), None);
    }

    #[test]
    fn test_set_get_focus() {
        let mut stack = Stack::<u8>::new();
        assert_eq!(stack.focused(), None);
        stack.push(2);
        stack.push(3);
        assert_eq!(stack.focused(), Some(&2));
        stack.remove(|v| v == &2);
        // A non-empty stack should always have something focused.
        assert_eq!(stack.focused(), Some(&3));
        stack.remove(|v| v == &3);
        assert_eq!(stack.focused(), None);
    }

    #[test]
    fn test_focus_next() {
        let mut stack = Stack::<u8>::new();
        stack.push(2);
        stack.push(3);
        stack.push(4);
        assert_eq!(stack.focused(), Some(&2));

        stack.focus_next();
        assert_eq!(stack.focused(), Some(&3));
        stack.focus_next();
        assert_eq!(stack.focused(), Some(&4));
        stack.focus_next();
        assert_eq!(stack.focused(), Some(&2));
    }

    #[test]
    fn test_focus_previous() {
        let mut stack = Stack::<u8>::new();
        stack.push(2);
        stack.push(3);
        stack.push(4);
        assert_eq!(stack.focused(), Some(&2));

        stack.focus_previous();
        assert_eq!(stack.focused(), Some(&4));
        stack.focus_previous();
        assert_eq!(stack.focused(), Some(&3));
        stack.focus_previous();
        assert_eq!(stack.focused(), Some(&2));
    }

    #[test]
    fn test_shuffle_next() {
        let mut stack = Stack::<u8>::new();
        stack.push(2);
        stack.push(3);
        stack.push(4);
        assert_eq!(stack.focused(), Some(&2));

        assert_eq!(stack.vec, vec![2, 3, 4]);
        stack.shuffle_next();
        assert_eq!(stack.vec, vec![3, 2, 4]);
        stack.shuffle_next();
        assert_eq!(stack.vec, vec![3, 4, 2]);
        stack.shuffle_next();
        assert_eq!(stack.vec, vec![2, 3, 4]);
    }

    #[test]
    fn test_shuffle_previous() {
        let mut stack = Stack::<u8>::new();
        stack.push(2);
        stack.push(3);
        stack.push(4);
        assert_eq!(stack.focused(), Some(&2));

        assert_eq!(stack.vec, vec![2, 3, 4]);
        stack.shuffle_previous();
        assert_eq!(stack.vec, vec![3, 4, 2]);
        stack.shuffle_previous();
        assert_eq!(stack.vec, vec![3, 2, 4]);
        stack.shuffle_previous();
        assert_eq!(stack.vec, vec![2, 3, 4]);
    }
}
<commit_msg>Add new test for Stack::from()<commit_after>use std::slice::{Iter, IterMut};

#[derive(Clone)]
pub struct Stack<T> {
    vec: Vec<T>,
    focus: Option<usize>,
}

impl<T> Stack<T> {
    pub fn new() -> Stack<T> {
        Stack {
            vec: Vec::new(),
            focus: None,
        }
    }

    pub fn push(&mut self, value: T) {
        self.vec.push(value);
        self.ensure_focus();
    }

    pub fn remove<P>(&mut self, p: P) -> T
        where P: FnMut(&T) -> bool
    {
        let position = self.vec
            .iter()
            .position(p)
            .expect("No element in stack matches predicate");
        let element = self.vec.remove(position);
        // We might have removed the focus element. A non-empty stack should always
        // focus something.
        self.ensure_focus();
        element
    }

    pub fn iter(&self) -> Iter<T> {
        self.vec.iter()
    }

    pub fn iter_mut(&mut self) -> IterMut<T> {
        self.vec.iter_mut()
    }

    pub fn focused(&self) -> Option<&T> {
        self.focus.and_then(|idx| self.vec.get(idx))
    }

    pub fn focused_mut(&mut self) -> Option<&mut T> {
        self.focus.and_then(move |idx| self.vec.get_mut(idx))
    }

    /// Focuses the first element in the stack that matches the predicate.
    ///
    /// Panics if no element matches the predicate.
    pub fn focus<P>(&mut self, p: P)
        where P: FnMut(&T) -> bool
    {
        let position = self.vec
            .iter()
            .position(p)
            .expect("No element in stack matches predicate");
        self.focus = Some(position);
    }

    fn ensure_focus(&mut self) {
        self.focus = self.focus
            .or(if self.vec.is_empty() { None } else { Some(0) });
    }

    fn next_index(&self, index: usize) -> usize {
        (index + 1) % self.vec.len()
    }

    fn previous_index(&self, index: usize) -> usize {
        if index == 0 {
            self.vec.len() - 1
        } else {
            (index - 1) % self.vec.len()
        }
    }

    pub fn focus_next(&mut self) {
        self.focus = self.focus.map(|idx| self.next_index(idx));
    }

    pub fn focus_previous(&mut self) {
        self.focus = self.focus.map(|idx| self.previous_index(idx));
    }

    pub fn shuffle_next(&mut self) {
        if let Some(current_idx) = self.focus {
            let next_idx = self.next_index(current_idx);
            if next_idx == 0 {
                let item = self.vec.remove(current_idx);
                self.vec.insert(0, item);
            } else {
                self.vec.swap(current_idx, next_idx);
            }
            self.focus = Some(next_idx);
        }
    }

    pub fn shuffle_previous(&mut self) {
        if let Some(current_idx) = self.focus {
            let prev_idx = self.previous_index(current_idx);
            if prev_idx == self.vec.len() - 1 {
                let item = self.vec.remove(current_idx);
                self.vec.push(item);
            } else {
                self.vec.swap(current_idx, prev_idx);
            }
            self.focus = Some(prev_idx);
        }
    }
}

impl<T> From<Vec<T>> for Stack<T> {
    fn from(vec: Vec<T>) -> Self {
        let mut stack = Stack {
            vec: vec,
            focus: None,
        };
        stack.ensure_focus();
        stack
    }
}

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

    #[test]
    fn test_from() {
        let vec = vec![1, 2, 3];
        let stack = Stack::from(vec.clone());
        assert_eq!(stack.vec, vec);
        assert_eq!(stack.focused(), Some(&vec[0]));
    }

    #[test]
    fn test_push() {
        let mut stack = Stack::<u8>::new();
        stack.push(2);
        assert_eq!(stack.vec, vec![2]);
    }

    #[test]
    fn test_remove() {
        let mut stack = Stack::<u8>::new();
        stack.push(2);
        stack.push(3);
        stack.push(4);
        stack.remove(|v| v == &3);
        assert_eq!(stack.vec, vec![2, 4]);
    }

    #[test]
    fn test_iter() {
        let mut stack = Stack::<u8>::new();
        stack.push(2);
        stack.push(3);
        stack.push(4);
        let mut iter = stack.iter();
        assert_eq!(iter.next(), Some(&2));
        assert_eq!(iter.next(), Some(&3));
        assert_eq!(iter.next(), Some(&4));
        assert_eq!(iter.next(), None);
    }

    #[test]
    fn test_set_get_focus() {
        let mut stack = Stack::<u8>::new();
        assert_eq!(stack.focused(), None);
        stack.push(2);
        stack.push(3);
        assert_eq!(stack.focused(), Some(&2));
        stack.remove(|v| v == &2);
        // A non-empty stack should always have something focused.
        assert_eq!(stack.focused(), Some(&3));
        stack.remove(|v| v == &3);
        assert_eq!(stack.focused(), None);
    }

    #[test]
    fn test_focus_next() {
        let mut stack = Stack::<u8>::new();
        stack.push(2);
        stack.push(3);
        stack.push(4);
        assert_eq!(stack.focused(), Some(&2));

        stack.focus_next();
        assert_eq!(stack.focused(), Some(&3));
        stack.focus_next();
        assert_eq!(stack.focused(), Some(&4));
        stack.focus_next();
        assert_eq!(stack.focused(), Some(&2));
    }

    #[test]
    fn test_focus_previous() {
        let mut stack = Stack::<u8>::new();
        stack.push(2);
        stack.push(3);
        stack.push(4);
        assert_eq!(stack.focused(), Some(&2));

        stack.focus_previous();
        assert_eq!(stack.focused(), Some(&4));
        stack.focus_previous();
        assert_eq!(stack.focused(), Some(&3));
        stack.focus_previous();
        assert_eq!(stack.focused(), Some(&2));
    }

    #[test]
    fn test_shuffle_next() {
        let mut stack = Stack::<u8>::new();
        stack.push(2);
        stack.push(3);
        stack.push(4);
        assert_eq!(stack.focused(), Some(&2));

        assert_eq!(stack.vec, vec![2, 3, 4]);
        stack.shuffle_next();
        assert_eq!(stack.vec, vec![3, 2, 4]);
        stack.shuffle_next();
        assert_eq!(stack.vec, vec![3, 4, 2]);
        stack.shuffle_next();
        assert_eq!(stack.vec, vec![2, 3, 4]);
    }

    #[test]
    fn test_shuffle_previous() {
        let mut stack = Stack::<u8>::new();
        stack.push(2);
        stack.push(3);
        stack.push(4);
        assert_eq!(stack.focused(), Some(&2));

        assert_eq!(stack.vec, vec![2, 3, 4]);
        stack.shuffle_previous();
        assert_eq!(stack.vec, vec![3, 4, 2]);
        stack.shuffle_previous();
        assert_eq!(stack.vec, vec![3, 2, 4]);
        stack.shuffle_previous();
        assert_eq!(stack.vec, vec![2, 3, 4]);
    }
}
<|endoftext|>


<commit_before>
//! A different way of thinking about states.
//!
//! All objects are stored in a state.
//!
//! You can either manually create states for different types,
//! or you can use a `StateMachine` to move between states of same type.

use HashMap = collections::HashMap;

pub mod state_machine;

/// Contains objects.
pub struct State<Object> {
    objects: HashMap<uint, Object>,
}

impl<T> State<T> {
    /// Moves an object from one state to another.
    pub fn move_to(&mut self, to: &mut State<T>, obj: uint) {
        let pop = self.objects.pop(&obj);
        match pop {
            None => {},
            Some(val) => { to.objects.insert(obj, val); }
        }
    }
}

/// Updates on delta information.
///
/// For any type implementing this trait,
/// there is a `State<T>` and `StateMachine<T>`
/// which also implements this trait.
pub trait UpdateDelta<D> {
    /// Updates all the objects with delta information.
    fn update(&mut self, delta: &D);
}

impl<T: UpdateDelta<D>, D>
UpdateDelta<D> for State<T> {
    fn update(&mut self, delta: &D) {
        for (_, obj) in self.objects.mut_iter() {
            obj.update(delta);
        }
    }
}

<commit_msg>Added get and get_mut<commit_after>
//! A different way of thinking about states.
//!
//! All objects are stored in a state.
//!
//! You can either manually create states for different types,
//! or you can use a `StateMachine` to move between states of same type.

use HashMap = collections::HashMap;

pub mod state_machine;

/// Contains objects.
pub struct State<Object> {
    objects: HashMap<uint, Object>,
}

impl<T> State<T> {
    /// Moves an object from one state to another.
    pub fn move_to(&mut self, to: &mut State<T>, obj: uint) {
        let pop = self.objects.pop(&obj);
        match pop {
            None => {},
            Some(val) => { to.objects.insert(obj, val); }
        }
    }

    /// Returns a readonly pointer to object.
    #[inline(always)]
    pub fn get<'a>(&'a self, obj: uint) -> &'a T {
        self.objects.get(&obj)
    }

    /// Returns a mutable pointer to object.
    #[inline(always)]
    pub fn get_mut<'a>(&'a mut self, obj: uint) -> &'a mut T {
        self.objects.get_mut(&obj)
    }
}

/// Updates on delta information.
///
/// For any type implementing this trait,
/// there is a `State<T>` and `StateMachine<T>`
/// which also implements this trait.
pub trait UpdateDelta<D> {
    /// Updates all the objects with delta information.
    fn update(&mut self, delta: &D);
}

impl<T: UpdateDelta<D>, D>
UpdateDelta<D> for State<T> {
    fn update(&mut self, delta: &D) {
        for (_, obj) in self.objects.mut_iter() {
            obj.update(delta);
        }
    }
}

<|endoftext|>


<commit_before>use std::str;
use std::hashmap::HashMap;

use log::{HTTPLogRecord, LogProcessor};

// TODO: Should be moved outside
static NUMBER_OF_ITEMS: uint = 8u;

struct ObjectStats {
    client: ~str,
    requests: uint,
    request_time: uint,
    sent_bytes: uint
}

pub struct LogStats {
    priv clients: HashMap<~str, ObjectStats>
}

impl LogStats {
    pub fn new() -> ~LogStats {
        ~LogStats{clients: HashMap::new()}
    }

    pub fn print(&self) {
        let mut sorted: ~[&ObjectStats] = self.clients.values().collect();
        sorted.sort_by(|a, b| b.requests.cmp(&a.requests));
        print_sorted(sorted, "By requests");
        sorted.sort_by(|a, b| b.request_time.cmp(&a.request_time));
        print_sorted(sorted, "By request time");
        sorted.sort_by(|a, b| b.sent_bytes.cmp(&a.sent_bytes));
        print_sorted(sorted, "By sent bytes");
    }
}

impl LogProcessor for LogStats {
    fn process(&mut self, record: HTTPLogRecord) {
        self.clients.insert_or_update_with(
            record.remote_addr.to_owned(),
            ObjectStats{
                client: record.remote_addr.to_owned(),
                requests: 1,
                request_time: record.request_time,
                sent_bytes: record.sent_bytes,
                },
            |_, stats| {
                stats.requests += 1;
                stats.request_time += record.request_time;
                stats.sent_bytes += record.sent_bytes;
            });
    }
}

fn print_sorted(sorted: &[&ObjectStats], message: &str) {
    println!("\n  {}", message);
    println!("=====================================================\
              =============");
    println!("Client                                 \
              Requests   Duration   Bytes");
    println!("-----------------------------------------------------\
              -------------");
    for stats in sorted.iter().take(NUMBER_OF_ITEMS) {
        println!("{: <40} {: >6} {: >10} {: >7}",
                 stats.client, stats.requests,
                 format_duration(stats.request_time),
                 format_bytes(stats.sent_bytes));
    }
}

fn format_duration(duration: uint) -> ~str {
    let (mut n, mut pos, modifier) = if duration < 1000 {
            (duration, 3, ~"s")
        } else if duration < 60 * 1000 {
            (duration / 100, 1, ~"s")
        } else if duration < 60 * 60 * 1000 {
            (duration / 6000, 1, ~"m")
        } else {
            (duration / 360000, 1, ~"h")
        };
    while pos > 0 && n % 10 == 0 {
        n /= 10;
        pos -= 1;
    }
    let int_part = (n / pow(10, pos)).to_str();
    let mut fract_part = str::with_capacity(pos + 1);
    if pos != 0 && n != 0 {
        fract_part.push_char('.');
        while pos > 0 {
            let digit = (n / pow(10, pos - 1)) % 10;
            fract_part.push_char((digit as u8 + '0' as u8) as char);
            pos -= 1;
        }
    }
    int_part + fract_part + modifier
}

fn pow(n: uint, p: uint) -> uint {
    let mut num = 1;
    for _ in range(0, p) {
        num *= n;
    }
    num
}

fn format_bytes(mut bytes: uint) -> ~str {
    static modifiers: [&'static str, ..4] = ["G", "M", "K", ""];
    let mut i = modifiers.len() - 1;
    while bytes >= 1024 && i != 0 {
        bytes /= 1024;
        i -= 1;
    }
    bytes.to_str() + modifiers[i]
}

/*
 * Tests
 */
#[cfg(test)]
mod test {
    use super::{format_duration, format_bytes};

    #[test]
    fn test_format_duration() {
        assert_eq!(~"0s", format_duration(0));
        assert_eq!(~"0.009s", format_duration(9));
        assert_eq!(~"0.09s", format_duration(90));
        assert_eq!(~"0.9s", format_duration(900));
        assert_eq!(~"0.999s", format_duration(999));
        assert_eq!(~"1s", format_duration(1000));
        assert_eq!(~"1s", format_duration(1009));
        assert_eq!(~"1.4s", format_duration(1400));
        assert_eq!(~"1.6s", format_duration(1600));
        assert_eq!(~"59s", format_duration(59000));
        assert_eq!(~"1m", format_duration(60000));
        assert_eq!(~"1.5m", format_duration(90000));
        assert_eq!(~"1h", format_duration(60 * 60 * 1000));
        assert_eq!(~"1.5h", format_duration(90 * 60 * 1000));
        assert_eq!(~"10h", format_duration(10 * 60 * 60 * 1000));
    }

    #[test]
    fn test_format_bytes() {
        assert_eq!(~"0", format_bytes(0));
        assert_eq!(~"9", format_bytes(9));
        assert_eq!(~"90", format_bytes(90));
        assert_eq!(~"900", format_bytes(900));
        assert_eq!(~"1000", format_bytes(1000));
        assert_eq!(~"1K", format_bytes(1024));
        assert_eq!(~"2K", format_bytes(2048));
        assert_eq!(~"4K", format_bytes(4096));
        assert_eq!(~"1M", format_bytes(1024 * 1024));
        assert_eq!(~"1G", format_bytes(1024 * 1024 * 1024));
        assert_eq!(~"1024G", format_bytes(1024 * 1024 * 1024 * 1024));
    }
}
<commit_msg>Remove 'client' field from ObjectStats struct<commit_after>use std::str;
use std::hashmap::HashMap;

use log::{HTTPLogRecord, LogProcessor};

// TODO: Should be moved outside
static NUMBER_OF_ITEMS: uint = 8u;

struct ObjectStats {
    requests: uint,
    request_time: uint,
    sent_bytes: uint
}

pub struct LogStats {
    priv clients: HashMap<~str, ObjectStats>
}

impl LogStats {
    pub fn new() -> ~LogStats {
        ~LogStats{clients: HashMap::new()}
    }

    pub fn print(&self) {
        let mut stats: ~[(&~str, &ObjectStats)] = self.clients.iter().collect();
        stats.sort_by(|&(_, a), &(_, b)| b.requests.cmp(&a.requests));
        print_sorted(stats, "By requests");
        stats.sort_by(|&(_, a), &(_, b)| b.request_time.cmp(&a.request_time));
        print_sorted(stats, "By request time");
        stats.sort_by(|&(_, a), &(_, b)| b.sent_bytes.cmp(&a.sent_bytes));
        print_sorted(stats, "By sent bytes");
    }
}

impl LogProcessor for LogStats {
    fn process(&mut self, record: HTTPLogRecord) {
        self.clients.insert_or_update_with(
            record.remote_addr.to_owned(),
            ObjectStats{
                requests: 1,
                request_time: record.request_time,
                sent_bytes: record.sent_bytes,
                },
            |_, stats| {
                stats.requests += 1;
                stats.request_time += record.request_time;
                stats.sent_bytes += record.sent_bytes;
            });
    }
}

fn print_sorted(sorted: &[(&~str, &ObjectStats)], message: &str) {
    println!("\n  {}", message);
    println!("=====================================================\
              =============");
    println!("Client                                 \
              Requests   Duration   Bytes");
    println!("-----------------------------------------------------\
              -------------");
    for &(client, stats) in sorted.iter().take(NUMBER_OF_ITEMS) {
        println!("{: <40} {: >6} {: >10} {: >7}",
                 *client, stats.requests,
                 format_duration(stats.request_time),
                 format_bytes(stats.sent_bytes));
    }
}

fn format_duration(duration: uint) -> ~str {
    let (mut n, mut pos, modifier) = if duration < 1000 {
            (duration, 3, ~"s")
        } else if duration < 60 * 1000 {
            (duration / 100, 1, ~"s")
        } else if duration < 60 * 60 * 1000 {
            (duration / 6000, 1, ~"m")
        } else {
            (duration / 360000, 1, ~"h")
        };
    while pos > 0 && n % 10 == 0 {
        n /= 10;
        pos -= 1;
    }
    let int_part = (n / pow(10, pos)).to_str();
    let mut fract_part = str::with_capacity(pos + 1);
    if pos != 0 && n != 0 {
        fract_part.push_char('.');
        while pos > 0 {
            let digit = (n / pow(10, pos - 1)) % 10;
            fract_part.push_char((digit as u8 + '0' as u8) as char);
            pos -= 1;
        }
    }
    int_part + fract_part + modifier
}

fn pow(n: uint, p: uint) -> uint {
    let mut num = 1;
    for _ in range(0, p) {
        num *= n;
    }
    num
}

fn format_bytes(mut bytes: uint) -> ~str {
    static modifiers: [&'static str, ..4] = ["G", "M", "K", ""];
    let mut i = modifiers.len() - 1;
    while bytes >= 1024 && i != 0 {
        bytes /= 1024;
        i -= 1;
    }
    bytes.to_str() + modifiers[i]
}

/*
 * Tests
 */
#[cfg(test)]
mod test {
    use super::{format_duration, format_bytes};

    #[test]
    fn test_format_duration() {
        assert_eq!(~"0s", format_duration(0));
        assert_eq!(~"0.009s", format_duration(9));
        assert_eq!(~"0.09s", format_duration(90));
        assert_eq!(~"0.9s", format_duration(900));
        assert_eq!(~"0.999s", format_duration(999));
        assert_eq!(~"1s", format_duration(1000));
        assert_eq!(~"1s", format_duration(1009));
        assert_eq!(~"1.4s", format_duration(1400));
        assert_eq!(~"1.6s", format_duration(1600));
        assert_eq!(~"59s", format_duration(59000));
        assert_eq!(~"1m", format_duration(60000));
        assert_eq!(~"1.5m", format_duration(90000));
        assert_eq!(~"1h", format_duration(60 * 60 * 1000));
        assert_eq!(~"1.5h", format_duration(90 * 60 * 1000));
        assert_eq!(~"10h", format_duration(10 * 60 * 60 * 1000));
    }

    #[test]
    fn test_format_bytes() {
        assert_eq!(~"0", format_bytes(0));
        assert_eq!(~"9", format_bytes(9));
        assert_eq!(~"90", format_bytes(90));
        assert_eq!(~"900", format_bytes(900));
        assert_eq!(~"1000", format_bytes(1000));
        assert_eq!(~"1K", format_bytes(1024));
        assert_eq!(~"2K", format_bytes(2048));
        assert_eq!(~"4K", format_bytes(4096));
        assert_eq!(~"1M", format_bytes(1024 * 1024));
        assert_eq!(~"1G", format_bytes(1024 * 1024 * 1024));
        assert_eq!(~"1024G", format_bytes(1024 * 1024 * 1024 * 1024));
    }
}
<|endoftext|>