<commit_before>use FovStatus;
use Prefab;
use calx_ecs::Entity;
use calx_grid::{Dir6, HexGeom};
use components::{Alignment, BrainState, Icon};
use euclid::{Vector2D, vec2};
use form;
use item::{ItemType, Slot};
use location::Location;
use stats;
use stats::Intrinsic;
use std::collections::{HashSet, VecDeque};
use std::iter::FromIterator;
use std::slice;
use terraform::TerrainQuery;
use terrain::Terrain;
use world::Ecs;

/// Immutable querying of game world state.
pub trait Query: TerrainQuery + Sized {
    /// Return the location of an entity.
    ///
    /// Returns the location of the containing entity for entities inside
    /// containers. It is possible for entities to not have a location.
    fn location(&self, e: Entity) -> Option<Location>;

    /// Return the player entity if one exists.
    fn player(&self) -> Option<Entity>;

    /// Return current time of the world logic clock.
    fn tick(&self) -> u64;

    /// Return world RNG seed
    fn rng_seed(&self) -> u32;

    /// Return maximum health of an entity.
    fn max_hp(&self, e: Entity) -> i32 { self.stats(e).power }

    /// Return all entities in the world.
    fn entities(&self) -> slice::Iter<Entity>;

    // XXX: Would be nicer if entities_at returned an iterator. Probably want to wait for impl
    // Trait return types before jumping to this.

    /// Return entities at the given location.
    fn entities_at(&self, loc: Location) -> Vec<Entity>;

    /// Return reference to the world entity component system.
    fn ecs(&self) -> &Ecs;

    /// Return the item parent has equipped in slot.
    fn entity_equipped(&self, parent: Entity, slot: Slot) -> Option<Entity>;

    fn entity_contains(&self, parent: Entity, child: Entity) -> bool;

    /// Return the AI state of an entity.
    fn brain_state(&self, e: Entity) -> Option<BrainState> {
        self.ecs().brain.get(e).map_or(
            None,
            |brain| Some(brain.state),
        )
    }

    /// Return whether the entity is a mobile object (eg. active creature).
    fn is_mob(&self, e: Entity) -> bool { self.ecs().brain.contains(e) }

    fn is_item(&self, e: Entity) -> bool { self.ecs().item.contains(e) }

    /// Return the value for how a mob will react to other mobs.
    fn alignment(&self, e: Entity) -> Option<Alignment> {
        self.ecs().brain.get(e).map(|b| b.alignment)
    }

    /// Return current health of an entity.
    fn hp(&self, e: Entity) -> i32 {
        self.max_hp(e) -
            if self.ecs().health.contains(e) {
                self.ecs().health[e].wounds
            } else {
                0
            }
    }

    /// Return field of view for a location.
    fn fov_status(&self, loc: Location) -> Option<FovStatus> {
        if let Some(p) = self.player() {
            if self.ecs().map_memory.contains(p) {
                if self.ecs().map_memory[p].seen.contains(&loc) {
                    return Some(FovStatus::Seen);
                }
                if self.ecs().map_memory[p].remembered.contains(&loc) {
                    return Some(FovStatus::Remembered);
                }
                return None;
            }
        }
        // Just show everything by default.
        Some(FovStatus::Seen)
    }

    /// Return visual brush for an entity.
    fn entity_icon(&self, e: Entity) -> Option<Icon> { self.ecs().desc.get(e).map(|x| x.icon) }

    fn entity_name(&self, e: Entity) -> String {
        self.ecs().desc.get(e).map_or_else(
            || "N/A".to_string(),
            |x| x.name.clone(),
        )
    }

    /// Return the (composite) stats for an entity.
    ///
    /// Will return the default value for the Stats type (additive identity in the stat algebra)
    /// for entities that have no stats component defined.
    fn stats(&self, e: Entity) -> stats::Stats {
        self.ecs().composite_stats.get(e).map_or_else(
            || self.base_stats(e),
            |x| x.0,
        )
    }

    /// Return the base stats of the entity. Does not include any added effects.
    ///
    /// You usually want to use the `stats` method instead of this one.
    fn base_stats(&self, e: Entity) -> stats::Stats {
        self.ecs().stats.get(e).cloned().unwrap_or_default()
    }

    /// Return whether the entity can move in a direction.
    fn can_step(&self, e: Entity, dir: Dir6) -> bool {
        self.location(e).map_or(false, |loc| {
            self.can_enter(e, loc.jump(self, dir))
        })
    }

    /// Return whether location blocks line of sight.
    fn blocks_sight(&self, loc: Location) -> bool { self.terrain(loc).blocks_sight() }

    /// Return whether the entity can occupy a location.
    fn can_enter(&self, e: Entity, loc: Location) -> bool {
        if self.terrain(loc).is_door() && !self.has_intrinsic(e, Intrinsic::Hands) {
            // Can't open doors without hands.
            return false;
        }
        if self.blocks_walk(loc) {
            return false;
        }
        true
    }

    fn can_drop_item_at(&self, loc: Location) -> bool {
        if !self.is_valid_location(loc) {
            return false;
        }
        if self.terrain(loc).blocks_walk() {
            return false;
        }
        if self.terrain(loc).is_door() {
            return false;
        }
        true
    }

    /// Return whether the entity blocks movement of other entities.
    fn is_blocking_entity(&self, e: Entity) -> bool { self.is_mob(e) }

    /// Return whether the location obstructs entity movement.
    fn blocks_walk(&self, loc: Location) -> bool {
        if !self.is_valid_location(loc) {
            return true;
        }
        if self.terrain(loc).blocks_walk() {
            return true;
        }
        if self.entities_at(loc).into_iter().any(|e| {
            self.is_blocking_entity(e)
        })
        {
            return true;
        }
        false
    }

    /// Return whether a location contains mobs.
    fn has_mobs(&self, loc: Location) -> bool { self.mob_at(loc).is_some() }

    /// Return mob (if any) at given location.
    fn mob_at(&self, loc: Location) -> Option<Entity> {
        self.entities_at(loc).into_iter().find(|&e| self.is_mob(e))
    }

    /// Return first item at given location.
    fn item_at(&self, loc: Location) -> Option<Entity> {
        self.entities_at(loc).into_iter().find(|&e| self.is_item(e))
    }

    /// Return whether the entity has a specific intrinsic property (eg. poison resistance).
    fn has_intrinsic(&self, e: Entity, intrinsic: Intrinsic) -> bool {
        self.stats(e).intrinsics & intrinsic as u32 != 0
    }

    /// 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.
    fn ticks_this_frame(&self, e: Entity) -> bool {
        if !self.is_mob(e) || !self.is_alive(e) {
            return false;
        }

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

    /// Return whether the entity is dead and should be removed from the world.
    fn is_alive(&self, e: Entity) -> bool { self.location(e).is_some() }

    /// Return true if the game has ended and the player can make no further
    /// actions.
    fn game_over(&self) -> bool { self.player().is_none() }

    /// Return whether an entity is the player avatar mob.
    fn is_player(&self, e: Entity) -> bool {
        // TODO: Should this just check self.flags.player?
        self.brain_state(e) == Some(BrainState::PlayerControl) && self.is_alive(e)
    }

    /// Return whether the entity is an awake mob.
    fn is_active(&self, e: Entity) -> bool {
        match self.brain_state(e) {
            Some(BrainState::Asleep) => false,
            Some(_) => true,
            _ => false,
        }
    }

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

    /// Look for targets to shoot in a direction.
    fn find_target(&self, shooter: Entity, dir: Dir6, range: usize) -> Option<Entity> {
        let origin = self.location(shooter).unwrap();
        let mut loc = origin;
        for _ in 1..(range + 1) {
            loc = loc.jump(self, dir);
            if self.terrain(loc).blocks_shot() {
                break;
            }
            if let Some(e) = self.mob_at(loc) {
                if self.is_hostile_to(shooter, e) {
                    return Some(e);
                }
            }
        }
        None
    }

    /// Return whether the entity wants to fight the other entity.
    fn is_hostile_to(&self, e: Entity, other: Entity) -> bool {
        let (a, b) = (self.alignment(e), self.alignment(other));
        if a.is_none() || b.is_none() {
            return false;
        }

        // Chaotics fight everything, otherwise different alignments fight.
        a == Some(Alignment::Chaotic) || a != b
    }

    /// Return whether the entity should have an idle animation.
    fn is_bobbing(&self, e: Entity) -> bool { self.is_active(e) && !self.is_player(e) }

    fn item_type(&self, e: Entity) -> Option<ItemType> {
        self.ecs().item.get(e).map_or(
            None,
            |item| Some(item.item_type),
        )
    }

    /// Return terrain at location for drawing on screen.
    ///
    /// Terrain is sometimes replaced with a variant for visual effect, but
    /// this should not be reflected in the logical terrain.
    fn visual_terrain(&self, loc: Location) -> Terrain {
        use Terrain::*;

        let mut t = self.terrain(loc);
        // Floor terrain dot means "you can step here". So if the floor is outside the valid play
        // area, don't show the dot.
        //
        // XXX: Hardcoded set of floors, must be updated whenever a new floor type is added.
        if !self.is_valid_location(loc) && (t == Ground || t == Grass || t == Gate) {
            t = Empty;
        }

        // TODO: Might want a more generic method of specifying cosmetic terrain variants.
        if t == Grass && loc.noise() > 0.85 {
            // Grass is occasionally fancy.
            t = Grass2;
        }

        t
    }

    /// Return the name that can be used to spawn this entity.
    fn spawn_name(&self, e: Entity) -> Option<&str> {
        // TODO: Create a special component for this.
        self.ecs().desc.get(e).map_or(
            None,
            |desc| Some(&desc.name[..]),
        )
    }

    fn is_spawn_name(&self, spawn_name: &str) -> bool {
        form::FORMS.iter().any(|f| f.name() == Some(spawn_name))
    }

    fn extract_prefab<I: IntoIterator<Item = Location>>(&self, locs: I) -> Prefab {
        let mut map = Vec::new();
        let mut origin = None;

        for loc in locs {
            // Store first location as an arbitrary origin.
            let origin = match origin {
                None => {
                    origin = Some(loc);
                    loc
                }
                Some(origin) => origin,
            };

            let pos = origin.v2_at(loc).expect(
                "Trying to build prefab from multiple z-levels",
            );

            let terrain = self.terrain(loc);

            let entities = Vec::from_iter(self.entities_at(loc).into_iter().filter_map(|e| {
                self.spawn_name(e).map(|s| s.to_string())
            }));

            map.push((pos, (terrain, entities)));
        }

        Prefab::from_iter(map.into_iter())
    }

    fn free_bag_slot(&self, e: Entity) -> Option<Slot> {
        Slot::iter()
            .filter(|&&x| {
                !x.is_equipment_slot() && self.entity_equipped(e, x).is_none()
            })
            .next()
            .cloned()
    }

    /// Find a drop position for an item, trying to keep one item per cell.
    ///
    /// Dropping several items in the same location will cause them to spread out to the adjacent
    /// cells. If there is no room for the items to spread out, they will be stacked on the initial
    /// drop site.
    fn empty_item_drop_location(&self, starting_point: Location) -> Location {
        static MAX_SPREAD_DISTANCE: i32 = 8;
        let is_valid = |v: Vector2D<i32>| {
            self.can_drop_item_at(starting_point.jump(self, v)) && v.hex_dist() <= MAX_SPREAD_DISTANCE
        };
        let mut seen = HashSet::new();
        let mut incoming = VecDeque::new();
        incoming.push_back(vec2(0, 0));

        while let Some(offset) = incoming.pop_front() {
            if seen.contains(&offset) {
                continue;
            } else {
                seen.insert(offset);
            }

            let loc = starting_point.jump(self, offset);
            if self.item_at(loc).is_none() {
                return loc;
            }

            let current_dist = offset.hex_dist();
            for d in Dir6::iter() {
                let v = offset + d.to_v2();
                if v.hex_dist() > current_dist && !seen.contains(&v) && is_valid(v) {
                    incoming.push_back(v);
                }
            }
        }

        return starting_point;
    }
}
<commit_msg>Better variable name<commit_after>use FovStatus;
use Prefab;
use calx_ecs::Entity;
use calx_grid::{Dir6, HexGeom};
use components::{Alignment, BrainState, Icon};
use euclid::{Vector2D, vec2};
use form;
use item::{ItemType, Slot};
use location::Location;
use stats;
use stats::Intrinsic;
use std::collections::{HashSet, VecDeque};
use std::iter::FromIterator;
use std::slice;
use terraform::TerrainQuery;
use terrain::Terrain;
use world::Ecs;

/// Immutable querying of game world state.
pub trait Query: TerrainQuery + Sized {
    /// Return the location of an entity.
    ///
    /// Returns the location of the containing entity for entities inside
    /// containers. It is possible for entities to not have a location.
    fn location(&self, e: Entity) -> Option<Location>;

    /// Return the player entity if one exists.
    fn player(&self) -> Option<Entity>;

    /// Return current time of the world logic clock.
    fn tick(&self) -> u64;

    /// Return world RNG seed
    fn rng_seed(&self) -> u32;

    /// Return maximum health of an entity.
    fn max_hp(&self, e: Entity) -> i32 { self.stats(e).power }

    /// Return all entities in the world.
    fn entities(&self) -> slice::Iter<Entity>;

    // XXX: Would be nicer if entities_at returned an iterator. Probably want to wait for impl
    // Trait return types before jumping to this.

    /// Return entities at the given location.
    fn entities_at(&self, loc: Location) -> Vec<Entity>;

    /// Return reference to the world entity component system.
    fn ecs(&self) -> &Ecs;

    /// Return the item parent has equipped in slot.
    fn entity_equipped(&self, parent: Entity, slot: Slot) -> Option<Entity>;

    fn entity_contains(&self, parent: Entity, child: Entity) -> bool;

    /// Return the AI state of an entity.
    fn brain_state(&self, e: Entity) -> Option<BrainState> {
        self.ecs().brain.get(e).map_or(
            None,
            |brain| Some(brain.state),
        )
    }

    /// Return whether the entity is a mobile object (eg. active creature).
    fn is_mob(&self, e: Entity) -> bool { self.ecs().brain.contains(e) }

    fn is_item(&self, e: Entity) -> bool { self.ecs().item.contains(e) }

    /// Return the value for how a mob will react to other mobs.
    fn alignment(&self, e: Entity) -> Option<Alignment> {
        self.ecs().brain.get(e).map(|b| b.alignment)
    }

    /// Return current health of an entity.
    fn hp(&self, e: Entity) -> i32 {
        self.max_hp(e) -
            if self.ecs().health.contains(e) {
                self.ecs().health[e].wounds
            } else {
                0
            }
    }

    /// Return field of view for a location.
    fn fov_status(&self, loc: Location) -> Option<FovStatus> {
        if let Some(p) = self.player() {
            if self.ecs().map_memory.contains(p) {
                if self.ecs().map_memory[p].seen.contains(&loc) {
                    return Some(FovStatus::Seen);
                }
                if self.ecs().map_memory[p].remembered.contains(&loc) {
                    return Some(FovStatus::Remembered);
                }
                return None;
            }
        }
        // Just show everything by default.
        Some(FovStatus::Seen)
    }

    /// Return visual brush for an entity.
    fn entity_icon(&self, e: Entity) -> Option<Icon> { self.ecs().desc.get(e).map(|x| x.icon) }

    fn entity_name(&self, e: Entity) -> String {
        self.ecs().desc.get(e).map_or_else(
            || "N/A".to_string(),
            |x| x.name.clone(),
        )
    }

    /// Return the (composite) stats for an entity.
    ///
    /// Will return the default value for the Stats type (additive identity in the stat algebra)
    /// for entities that have no stats component defined.
    fn stats(&self, e: Entity) -> stats::Stats {
        self.ecs().composite_stats.get(e).map_or_else(
            || self.base_stats(e),
            |x| x.0,
        )
    }

    /// Return the base stats of the entity. Does not include any added effects.
    ///
    /// You usually want to use the `stats` method instead of this one.
    fn base_stats(&self, e: Entity) -> stats::Stats {
        self.ecs().stats.get(e).cloned().unwrap_or_default()
    }

    /// Return whether the entity can move in a direction.
    fn can_step(&self, e: Entity, dir: Dir6) -> bool {
        self.location(e).map_or(false, |loc| {
            self.can_enter(e, loc.jump(self, dir))
        })
    }

    /// Return whether location blocks line of sight.
    fn blocks_sight(&self, loc: Location) -> bool { self.terrain(loc).blocks_sight() }

    /// Return whether the entity can occupy a location.
    fn can_enter(&self, e: Entity, loc: Location) -> bool {
        if self.terrain(loc).is_door() && !self.has_intrinsic(e, Intrinsic::Hands) {
            // Can't open doors without hands.
            return false;
        }
        if self.blocks_walk(loc) {
            return false;
        }
        true
    }

    fn can_drop_item_at(&self, loc: Location) -> bool {
        if !self.is_valid_location(loc) {
            return false;
        }
        if self.terrain(loc).blocks_walk() {
            return false;
        }
        if self.terrain(loc).is_door() {
            return false;
        }
        true
    }

    /// Return whether the entity blocks movement of other entities.
    fn is_blocking_entity(&self, e: Entity) -> bool { self.is_mob(e) }

    /// Return whether the location obstructs entity movement.
    fn blocks_walk(&self, loc: Location) -> bool {
        if !self.is_valid_location(loc) {
            return true;
        }
        if self.terrain(loc).blocks_walk() {
            return true;
        }
        if self.entities_at(loc).into_iter().any(|e| {
            self.is_blocking_entity(e)
        })
        {
            return true;
        }
        false
    }

    /// Return whether a location contains mobs.
    fn has_mobs(&self, loc: Location) -> bool { self.mob_at(loc).is_some() }

    /// Return mob (if any) at given location.
    fn mob_at(&self, loc: Location) -> Option<Entity> {
        self.entities_at(loc).into_iter().find(|&e| self.is_mob(e))
    }

    /// Return first item at given location.
    fn item_at(&self, loc: Location) -> Option<Entity> {
        self.entities_at(loc).into_iter().find(|&e| self.is_item(e))
    }

    /// Return whether the entity has a specific intrinsic property (eg. poison resistance).
    fn has_intrinsic(&self, e: Entity, intrinsic: Intrinsic) -> bool {
        self.stats(e).intrinsics & intrinsic as u32 != 0
    }

    /// 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.
    fn ticks_this_frame(&self, e: Entity) -> bool {
        if !self.is_mob(e) || !self.is_alive(e) {
            return false;
        }

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

    /// Return whether the entity is dead and should be removed from the world.
    fn is_alive(&self, e: Entity) -> bool { self.location(e).is_some() }

    /// Return true if the game has ended and the player can make no further
    /// actions.
    fn game_over(&self) -> bool { self.player().is_none() }

    /// Return whether an entity is the player avatar mob.
    fn is_player(&self, e: Entity) -> bool {
        // TODO: Should this just check self.flags.player?
        self.brain_state(e) == Some(BrainState::PlayerControl) && self.is_alive(e)
    }

    /// Return whether the entity is an awake mob.
    fn is_active(&self, e: Entity) -> bool {
        match self.brain_state(e) {
            Some(BrainState::Asleep) => false,
            Some(_) => true,
            _ => false,
        }
    }

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

    /// Look for targets to shoot in a direction.
    fn find_target(&self, shooter: Entity, dir: Dir6, range: usize) -> Option<Entity> {
        let origin = self.location(shooter).unwrap();
        let mut loc = origin;
        for _ in 1..(range + 1) {
            loc = loc.jump(self, dir);
            if self.terrain(loc).blocks_shot() {
                break;
            }
            if let Some(e) = self.mob_at(loc) {
                if self.is_hostile_to(shooter, e) {
                    return Some(e);
                }
            }
        }
        None
    }

    /// Return whether the entity wants to fight the other entity.
    fn is_hostile_to(&self, e: Entity, other: Entity) -> bool {
        let (a, b) = (self.alignment(e), self.alignment(other));
        if a.is_none() || b.is_none() {
            return false;
        }

        // Chaotics fight everything, otherwise different alignments fight.
        a == Some(Alignment::Chaotic) || a != b
    }

    /// Return whether the entity should have an idle animation.
    fn is_bobbing(&self, e: Entity) -> bool { self.is_active(e) && !self.is_player(e) }

    fn item_type(&self, e: Entity) -> Option<ItemType> {
        self.ecs().item.get(e).map_or(
            None,
            |item| Some(item.item_type),
        )
    }

    /// Return terrain at location for drawing on screen.
    ///
    /// Terrain is sometimes replaced with a variant for visual effect, but
    /// this should not be reflected in the logical terrain.
    fn visual_terrain(&self, loc: Location) -> Terrain {
        use Terrain::*;

        let mut t = self.terrain(loc);
        // Floor terrain dot means "you can step here". So if the floor is outside the valid play
        // area, don't show the dot.
        //
        // XXX: Hardcoded set of floors, must be updated whenever a new floor type is added.
        if !self.is_valid_location(loc) && (t == Ground || t == Grass || t == Gate) {
            t = Empty;
        }

        // TODO: Might want a more generic method of specifying cosmetic terrain variants.
        if t == Grass && loc.noise() > 0.85 {
            // Grass is occasionally fancy.
            t = Grass2;
        }

        t
    }

    /// Return the name that can be used to spawn this entity.
    fn spawn_name(&self, e: Entity) -> Option<&str> {
        // TODO: Create a special component for this.
        self.ecs().desc.get(e).map_or(
            None,
            |desc| Some(&desc.name[..]),
        )
    }

    fn is_spawn_name(&self, spawn_name: &str) -> bool {
        form::FORMS.iter().any(|f| f.name() == Some(spawn_name))
    }

    fn extract_prefab<I: IntoIterator<Item = Location>>(&self, locs: I) -> Prefab {
        let mut map = Vec::new();
        let mut origin = None;

        for loc in locs {
            // Store first location as an arbitrary origin.
            let origin = match origin {
                None => {
                    origin = Some(loc);
                    loc
                }
                Some(origin) => origin,
            };

            let pos = origin.v2_at(loc).expect(
                "Trying to build prefab from multiple z-levels",
            );

            let terrain = self.terrain(loc);

            let entities = Vec::from_iter(self.entities_at(loc).into_iter().filter_map(|e| {
                self.spawn_name(e).map(|s| s.to_string())
            }));

            map.push((pos, (terrain, entities)));
        }

        Prefab::from_iter(map.into_iter())
    }

    fn free_bag_slot(&self, e: Entity) -> Option<Slot> {
        Slot::iter()
            .filter(|&&x| {
                !x.is_equipment_slot() && self.entity_equipped(e, x).is_none()
            })
            .next()
            .cloned()
    }

    /// Find a drop position for an item, trying to keep one item per cell.
    ///
    /// Dropping several items in the same location will cause them to spread out to the adjacent
    /// cells. If there is no room for the items to spread out, they will be stacked on the initial
    /// drop site.
    fn empty_item_drop_location(&self, origin: Location) -> Location {
        static MAX_SPREAD_DISTANCE: i32 = 8;
        let is_valid = |v: Vector2D<i32>| {
            self.can_drop_item_at(origin.jump(self, v)) && v.hex_dist() <= MAX_SPREAD_DISTANCE
        };
        let mut seen = HashSet::new();
        let mut incoming = VecDeque::new();
        incoming.push_back(vec2(0, 0));

        while let Some(offset) = incoming.pop_front() {
            if seen.contains(&offset) {
                continue;
            } else {
                seen.insert(offset);
            }

            let loc = origin.jump(self, offset);
            if self.item_at(loc).is_none() {
                return loc;
            }

            let current_dist = offset.hex_dist();
            for d in Dir6::iter() {
                let v = offset + d.to_v2();
                if v.hex_dist() > current_dist && !seen.contains(&v) && is_valid(v) {
                    incoming.push_back(v);
                }
            }
        }

        return origin;
    }
}
<|endoftext|>


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

//! Themis error types.
//!
//! This module wraps Themis error types and provides useful Rust API for them.

use std::{error, fmt, result};

use bindings::{
    THEMIS_BUFFER_TOO_SMALL, THEMIS_DATA_CORRUPT, THEMIS_FAIL, THEMIS_INVALID_PARAMETER,
    THEMIS_INVALID_SIGNATURE, THEMIS_NOT_SUPPORTED, THEMIS_NO_MEMORY, THEMIS_SCOMPARE_MATCH,
    THEMIS_SCOMPARE_NOT_READY, THEMIS_SCOMPARE_NO_MATCH, THEMIS_SCOMPARE_SEND_OUTPUT_TO_PEER,
    THEMIS_SSESSION_GET_PUB_FOR_ID_CALLBACK_ERROR, THEMIS_SSESSION_KA_NOT_FINISHED,
    THEMIS_SSESSION_SEND_OUTPUT_TO_PEER, THEMIS_SSESSION_TRANSPORT_ERROR, THEMIS_SUCCESS,
};

use crate::secure_session::TransportError;

/// Themis status code.
pub(crate) use bindings::themis_status_t;

/// Result type for most Themis operations.
pub type Result<T> = result::Result<T, Error>;

/// The error type for most Themis operations.
///
/// Errors are usually caused by invalid, malformed or malicious input as well as incorrect usage
/// of the library. However, they may also result from underlying OS errors. See [`ErrorKind`] for
/// details.
///
/// [`ErrorKind`]: enum.ErrorKind.html
#[derive(Debug, Eq, PartialEq)]
pub struct Error {
    kind: ErrorKind,
}

impl Error {
    /// Constructs a new error of given kind.
    pub(crate) fn with_kind(kind: ErrorKind) -> Error {
        Error { kind }
    }

    /// Converts generic Themis status codes.
    pub(crate) fn from_themis_status(status: themis_status_t) -> Error {
        let kind = match status as u32 {
            THEMIS_SUCCESS => ErrorKind::Success,
            THEMIS_FAIL => ErrorKind::Fail,
            THEMIS_INVALID_PARAMETER => ErrorKind::InvalidParameter,
            THEMIS_NO_MEMORY => ErrorKind::NoMemory,
            THEMIS_BUFFER_TOO_SMALL => ErrorKind::BufferTooSmall,
            THEMIS_DATA_CORRUPT => ErrorKind::DataCorrupt,
            THEMIS_INVALID_SIGNATURE => ErrorKind::InvalidSignature,
            THEMIS_NOT_SUPPORTED => ErrorKind::NotSupported,
            _ => ErrorKind::UnknownError(status),
        };
        Error { kind }
    }

    /// Converts status codes returned by Secure Session.
    pub(crate) fn from_session_status(status: themis_status_t) -> Error {
        let kind = match status as u32 {
            THEMIS_SSESSION_SEND_OUTPUT_TO_PEER => ErrorKind::SessionSendOutputToPeer,
            THEMIS_SSESSION_KA_NOT_FINISHED => ErrorKind::SessionKeyAgreementNotFinished,
            THEMIS_SSESSION_TRANSPORT_ERROR => {
                ErrorKind::SessionTransportError(TransportError::unspecified())
            }
            THEMIS_SSESSION_GET_PUB_FOR_ID_CALLBACK_ERROR => {
                ErrorKind::SessionGetPublicKeyForIdError
            }
            _ => return Error::from_themis_status(status),
        };
        Error { kind }
    }

    /// Wraps a transport error reported by Secure Session.
    pub(crate) fn from_transport_error(error: TransportError) -> Error {
        let kind = ErrorKind::SessionTransportError(error);
        Error { kind }
    }

    /// Converts status codes returned by Secure Comparator data exchange.
    pub(crate) fn from_compare_status(status: themis_status_t) -> Error {
        let kind = match status as u32 {
            THEMIS_SCOMPARE_SEND_OUTPUT_TO_PEER => ErrorKind::CompareSendOutputToPeer,
            _ => return Error::from_themis_status(status),
        };
        Error { kind }
    }

    /// Converts status codes returned by Secure Comparator status query.
    pub(crate) fn from_match_status(status: themis_status_t) -> Error {
        let kind = match status as u32 {
            THEMIS_SCOMPARE_NOT_READY => ErrorKind::CompareNotReady,
            THEMIS_SCOMPARE_MATCH => ErrorKind::CompareMatch,
            THEMIS_SCOMPARE_NO_MATCH => ErrorKind::CompareNoMatch,
            _ => return Error::from_themis_status(status),
        };
        Error { kind }
    }

    /// Returns the corresponding `ErrorKind` for this error.
    pub fn kind(&self) -> &ErrorKind {
        &self.kind
    }
}

impl error::Error for Error {}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.kind {
            ErrorKind::UnknownError(status) => write!(f, "unknown error: {}", status),
            ErrorKind::Success => write!(f, "success"),

            ErrorKind::Fail => write!(f, "failure"),
            ErrorKind::InvalidParameter => write!(f, "invalid parameter"),
            ErrorKind::NoMemory => write!(f, "out of memory"),
            ErrorKind::BufferTooSmall => write!(f, "buffer too small"),
            ErrorKind::DataCorrupt => write!(f, "corrupted data"),
            ErrorKind::InvalidSignature => write!(f, "invalid signature"),
            ErrorKind::NotSupported => write!(f, "operation not supported"),

            ErrorKind::SessionSendOutputToPeer => write!(f, "send key agreement data to peer"),
            ErrorKind::SessionKeyAgreementNotFinished => write!(f, "key agreement not finished"),
            ErrorKind::SessionTransportError(ref details) => {
                write!(f, "transport layer error: {}", details)
            }
            ErrorKind::SessionGetPublicKeyForIdError => {
                write!(f, "failed to get public key for ID")
            }

            ErrorKind::CompareSendOutputToPeer => write!(f, "send comparison data to peer"),
            ErrorKind::CompareMatch => write!(f, "data matches"),
            ErrorKind::CompareNoMatch => write!(f, "data does not match"),
            ErrorKind::CompareNotReady => write!(f, "comparator not ready"),
        }
    }
}

/// A list of Themis error categories.
///
/// This enumeration is used by [`Error`] type, returned by most Themis functions. Some error kinds
/// are specific to particular functions, and some are used internally by the library.
///
/// [`Error`]: struct.Error.html
#[derive(Debug)]
pub enum ErrorKind {
    /*
     * If you add a new error kind then please add it to the error_kinds_equal() function below
     * as well. Unfortunately, we cannot derive PartialEq implementation automatically.
     */
    /// Catch-all generic error.
    ///
    /// If you encounter this error kind then the Themis binding is likely to be out of sync with
    /// the core library. The contained error code has not been mapped onto `ErrorKind` value.
    #[doc(hidden)]
    UnknownError(i32),
    /// "Fatal error: success!"
    ///
    /// This value is used internally to distinguish successful function calls conveniently.
    /// End-users should never encounter it.
    #[doc(hidden)]
    Success,

    /// General failure.
    Fail,
    /// Some input parameter has incorrect value.
    InvalidParameter,
    /// Could not allocate memory.
    NoMemory,
    /// The provided buffer is too small to fit the result.
    BufferTooSmall,
    /// Input data is corrupted.
    DataCorrupt,
    /// Input data contains invalid signature.
    InvalidSignature,
    /// Operation not supported.
    NotSupported,

    /// Send output with internal data of Secure Session to the peer.
    ///
    /// This is not actually an error and the end-user should never see it.
    #[doc(hidden)]
    SessionSendOutputToPeer,
    /// Attempt to use Secure Session before completing key exchange.
    SessionKeyAgreementNotFinished,
    /// Transport layer returned error.
    SessionTransportError(TransportError),
    /// Could not retrieve a public key corresponding to peer ID.
    SessionGetPublicKeyForIdError,

    /// Send output with internal data of Secure Comparator to the peer.
    ///
    /// This is not actually an error and the end-user should never see it.
    #[doc(hidden)]
    CompareSendOutputToPeer,
    /// Indicates that compared data matches.
    ///
    /// This is not actually an error and the end-user should never see it.
    #[doc(hidden)]
    CompareMatch,
    /// Indicates that compared data does not match.
    ///
    /// This is not actually an error and the end-user should never see it.
    #[doc(hidden)]
    CompareNoMatch,
    /// Attempt to use Secure Comparator before completing nonce exchange.
    CompareNotReady,
}

// TransportError does not implement PartialEq therefore it's not possible to derive the
// implementation for ErrorKind automatically. TransportErrors cannot be compared because
// they either contain arbitrary human-readable strings or abstract boxed errors which
// may have different types. However, we really need to be able to compare ErrorKinds.
// Implement comparison by ignoring differences in TransportError details, comparing
// just *kinds* of errors, not their values. This is a full equivalence relationship.

impl Eq for ErrorKind {}

impl PartialEq for ErrorKind {
    fn eq(&self, other: &ErrorKind) -> bool {
        error_kinds_equal(self, other)
    }
}

impl PartialEq<&ErrorKind> for ErrorKind {
    fn eq(&self, other: &&ErrorKind) -> bool {
        error_kinds_equal(self, other)
    }
}

impl PartialEq<ErrorKind> for &ErrorKind {
    fn eq(&self, other: &ErrorKind) -> bool {
        error_kinds_equal(self, other)
    }
}

fn error_kinds_equal(lhs: &ErrorKind, rhs: &ErrorKind) -> bool {
    match (lhs, rhs) {
        (ErrorKind::UnknownError(lhs), ErrorKind::UnknownError(rhs)) => (lhs == rhs),
        (ErrorKind::Success, ErrorKind::Success) => true,

        (ErrorKind::Fail, ErrorKind::Fail) => true,
        (ErrorKind::InvalidParameter, ErrorKind::InvalidParameter) => true,
        (ErrorKind::NoMemory, ErrorKind::NoMemory) => true,
        (ErrorKind::BufferTooSmall, ErrorKind::BufferTooSmall) => true,
        (ErrorKind::DataCorrupt, ErrorKind::DataCorrupt) => true,
        (ErrorKind::InvalidSignature, ErrorKind::InvalidSignature) => true,
        (ErrorKind::NotSupported, ErrorKind::NotSupported) => true,

        (ErrorKind::SessionSendOutputToPeer, ErrorKind::SessionSendOutputToPeer) => true,
        (ErrorKind::SessionKeyAgreementNotFinished, ErrorKind::SessionKeyAgreementNotFinished) => {
            true
        }
        // Ignore transport error details.
        (ErrorKind::SessionTransportError(_), ErrorKind::SessionTransportError(_)) => true,
        (ErrorKind::SessionGetPublicKeyForIdError, ErrorKind::SessionGetPublicKeyForIdError) => {
            true
        }

        (ErrorKind::CompareSendOutputToPeer, ErrorKind::CompareSendOutputToPeer) => true,
        (ErrorKind::CompareMatch, ErrorKind::CompareMatch) => true,
        (ErrorKind::CompareNoMatch, ErrorKind::CompareNoMatch) => true,
        (ErrorKind::CompareNotReady, ErrorKind::CompareNotReady) => true,

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

//! Themis error types.
//!
//! This module wraps Themis error types and provides useful Rust API for them.

use std::{error, fmt, result};

use bindings::{
    THEMIS_BUFFER_TOO_SMALL, THEMIS_DATA_CORRUPT, THEMIS_FAIL, THEMIS_INVALID_PARAMETER,
    THEMIS_INVALID_SIGNATURE, THEMIS_NOT_SUPPORTED, THEMIS_NO_MEMORY, THEMIS_SCOMPARE_MATCH,
    THEMIS_SCOMPARE_NOT_READY, THEMIS_SCOMPARE_NO_MATCH, THEMIS_SCOMPARE_SEND_OUTPUT_TO_PEER,
    THEMIS_SSESSION_GET_PUB_FOR_ID_CALLBACK_ERROR, THEMIS_SSESSION_KA_NOT_FINISHED,
    THEMIS_SSESSION_SEND_OUTPUT_TO_PEER, THEMIS_SSESSION_TRANSPORT_ERROR, THEMIS_SUCCESS,
};

use crate::secure_session::TransportError;

/// Themis status code.
pub(crate) use bindings::themis_status_t;

/// Result type for most Themis operations.
pub type Result<T> = result::Result<T, Error>;

/// The error type for most Themis operations.
///
/// Errors are usually caused by invalid, malformed or malicious input as well as incorrect usage
/// of the library. However, they may also result from underlying OS errors. See [`ErrorKind`] for
/// details.
///
/// [`ErrorKind`]: enum.ErrorKind.html
#[derive(Debug, Eq, PartialEq)]
pub struct Error {
    kind: ErrorKind,
}

impl Error {
    /// Constructs a new error of given kind.
    pub(crate) fn with_kind(kind: ErrorKind) -> Error {
        Error { kind }
    }

    /// Converts generic Themis status codes.
    pub(crate) fn from_themis_status(status: themis_status_t) -> Error {
        let kind = match status as u32 {
            THEMIS_SUCCESS => ErrorKind::Success,
            THEMIS_FAIL => ErrorKind::Fail,
            THEMIS_INVALID_PARAMETER => ErrorKind::InvalidParameter,
            THEMIS_NO_MEMORY => ErrorKind::NoMemory,
            THEMIS_BUFFER_TOO_SMALL => ErrorKind::BufferTooSmall,
            THEMIS_DATA_CORRUPT => ErrorKind::DataCorrupt,
            THEMIS_INVALID_SIGNATURE => ErrorKind::InvalidSignature,
            THEMIS_NOT_SUPPORTED => ErrorKind::NotSupported,
            _ => ErrorKind::UnknownError(status),
        };
        Error { kind }
    }

    /// Converts status codes returned by Secure Session.
    pub(crate) fn from_session_status(status: themis_status_t) -> Error {
        let kind = match status as u32 {
            THEMIS_SSESSION_SEND_OUTPUT_TO_PEER => ErrorKind::SessionSendOutputToPeer,
            THEMIS_SSESSION_KA_NOT_FINISHED => ErrorKind::SessionKeyAgreementNotFinished,
            THEMIS_SSESSION_TRANSPORT_ERROR => {
                ErrorKind::SessionTransportError(TransportError::unspecified())
            }
            THEMIS_SSESSION_GET_PUB_FOR_ID_CALLBACK_ERROR => {
                ErrorKind::SessionGetPublicKeyForIdError
            }
            _ => return Error::from_themis_status(status),
        };
        Error { kind }
    }

    /// Wraps a transport error reported by Secure Session.
    pub(crate) fn from_transport_error(error: TransportError) -> Error {
        let kind = ErrorKind::SessionTransportError(error);
        Error { kind }
    }

    /// Converts status codes returned by Secure Comparator data exchange.
    pub(crate) fn from_compare_status(status: themis_status_t) -> Error {
        let kind = match status as u32 {
            THEMIS_SCOMPARE_SEND_OUTPUT_TO_PEER => ErrorKind::CompareSendOutputToPeer,
            _ => return Error::from_themis_status(status),
        };
        Error { kind }
    }

    /// Converts status codes returned by Secure Comparator status query.
    pub(crate) fn from_match_status(status: themis_status_t) -> Error {
        let kind = match status as u32 {
            THEMIS_SCOMPARE_NOT_READY => ErrorKind::CompareNotReady,
            THEMIS_SCOMPARE_MATCH => ErrorKind::CompareMatch,
            THEMIS_SCOMPARE_NO_MATCH => ErrorKind::CompareNoMatch,
            _ => return Error::from_themis_status(status),
        };
        Error { kind }
    }

    /// Returns the corresponding `ErrorKind` for this error.
    pub fn kind(&self) -> &ErrorKind {
        &self.kind
    }
}

impl error::Error for Error {}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.kind {
            ErrorKind::UnknownError(status) => write!(f, "unknown error: {}", status),
            ErrorKind::Success => write!(f, "success"),

            ErrorKind::Fail => write!(f, "failure"),
            ErrorKind::InvalidParameter => write!(f, "invalid parameter"),
            ErrorKind::NoMemory => write!(f, "out of memory"),
            ErrorKind::BufferTooSmall => write!(f, "buffer too small"),
            ErrorKind::DataCorrupt => write!(f, "corrupted data"),
            ErrorKind::InvalidSignature => write!(f, "invalid signature"),
            ErrorKind::NotSupported => write!(f, "operation not supported"),

            ErrorKind::SessionSendOutputToPeer => write!(f, "send key agreement data to peer"),
            ErrorKind::SessionKeyAgreementNotFinished => write!(f, "key agreement not finished"),
            ErrorKind::SessionTransportError(ref details) => {
                write!(f, "transport layer error: {}", details)
            }
            ErrorKind::SessionGetPublicKeyForIdError => {
                write!(f, "failed to get public key for ID")
            }

            ErrorKind::CompareSendOutputToPeer => write!(f, "send comparison data to peer"),
            ErrorKind::CompareMatch => write!(f, "data matches"),
            ErrorKind::CompareNoMatch => write!(f, "data does not match"),
            ErrorKind::CompareNotReady => write!(f, "comparator not ready"),
        }
    }
}

/// A list of Themis error categories.
///
/// This enumeration is used by [`Error`] type, returned by most Themis functions. Some error kinds
/// are specific to particular functions, and some are used internally by the library.
///
/// [`Error`]: struct.Error.html
#[derive(Debug)]
pub enum ErrorKind {
    /*
     * If you add a new error kind then please add it to the error_kinds_equal() function below
     * as well. Unfortunately, we cannot derive PartialEq implementation automatically.
     */
    /// Catch-all generic error.
    ///
    /// If you encounter this error kind then the Themis binding is likely to be out of sync with
    /// the core library. The contained error code has not been mapped onto `ErrorKind` value.
    #[doc(hidden)]
    UnknownError(i32),
    /// "Fatal error: success!"
    ///
    /// This value is used internally to distinguish successful function calls conveniently.
    /// End-users should never encounter it.
    #[doc(hidden)]
    Success,

    /// General failure.
    Fail,
    /// Some input parameter has incorrect value.
    InvalidParameter,
    /// Could not allocate memory.
    NoMemory,
    /// The provided buffer is too small to fit the result.
    BufferTooSmall,
    /// Input data is corrupted.
    DataCorrupt,
    /// Input data contains invalid signature.
    InvalidSignature,
    /// Operation not supported.
    NotSupported,

    /// Send output with internal data of Secure Session to the peer.
    ///
    /// This is not actually an error and the end-user should never see it.
    #[doc(hidden)]
    SessionSendOutputToPeer,
    /// Attempt to use Secure Session before completing key exchange.
    SessionKeyAgreementNotFinished,
    /// Transport layer returned error.
    SessionTransportError(TransportError),
    /// Could not retrieve a public key corresponding to peer ID.
    SessionGetPublicKeyForIdError,

    /// Send output with internal data of Secure Comparator to the peer.
    ///
    /// This is not actually an error and the end-user should never see it.
    #[doc(hidden)]
    CompareSendOutputToPeer,
    /// Indicates that compared data matches.
    ///
    /// This is not actually an error and the end-user should never see it.
    #[doc(hidden)]
    CompareMatch,
    /// Indicates that compared data does not match.
    ///
    /// This is not actually an error and the end-user should never see it.
    #[doc(hidden)]
    CompareNoMatch,
    /// Attempt to use Secure Comparator before completing nonce exchange.
    CompareNotReady,
}

// TransportError does not implement PartialEq therefore it's not possible to derive the
// implementation for ErrorKind automatically. TransportErrors cannot be compared because
// they either contain arbitrary human-readable strings or abstract boxed errors which
// may have different types. However, we really need to be able to compare ErrorKinds.
// Implement comparison by ignoring differences in TransportError details, comparing
// just *kinds* of errors, not their values. This is a full equivalence relationship.

impl Eq for ErrorKind {}

impl PartialEq for ErrorKind {
    fn eq(&self, other: &ErrorKind) -> bool {
        error_kinds_equal(self, other)
    }
}

impl PartialEq<&ErrorKind> for ErrorKind {
    fn eq(&self, other: &&ErrorKind) -> bool {
        error_kinds_equal(self, other)
    }
}

impl PartialEq<ErrorKind> for &ErrorKind {
    fn eq(&self, other: &ErrorKind) -> bool {
        error_kinds_equal(self, other)
    }
}

fn error_kinds_equal(lhs: &ErrorKind, rhs: &ErrorKind) -> bool {
    match (lhs, rhs) {
        (ErrorKind::UnknownError(lhs), ErrorKind::UnknownError(rhs)) => lhs == rhs,
        (ErrorKind::Success, ErrorKind::Success) => true,

        (ErrorKind::Fail, ErrorKind::Fail) => true,
        (ErrorKind::InvalidParameter, ErrorKind::InvalidParameter) => true,
        (ErrorKind::NoMemory, ErrorKind::NoMemory) => true,
        (ErrorKind::BufferTooSmall, ErrorKind::BufferTooSmall) => true,
        (ErrorKind::DataCorrupt, ErrorKind::DataCorrupt) => true,
        (ErrorKind::InvalidSignature, ErrorKind::InvalidSignature) => true,
        (ErrorKind::NotSupported, ErrorKind::NotSupported) => true,

        (ErrorKind::SessionSendOutputToPeer, ErrorKind::SessionSendOutputToPeer) => true,
        (ErrorKind::SessionKeyAgreementNotFinished, ErrorKind::SessionKeyAgreementNotFinished) => {
            true
        }
        // Ignore transport error details.
        (ErrorKind::SessionTransportError(_), ErrorKind::SessionTransportError(_)) => true,
        (ErrorKind::SessionGetPublicKeyForIdError, ErrorKind::SessionGetPublicKeyForIdError) => {
            true
        }

        (ErrorKind::CompareSendOutputToPeer, ErrorKind::CompareSendOutputToPeer) => true,
        (ErrorKind::CompareMatch, ErrorKind::CompareMatch) => true,
        (ErrorKind::CompareNoMatch, ErrorKind::CompareNoMatch) => true,
        (ErrorKind::CompareNotReady, ErrorKind::CompareNotReady) => true,

        _ => false,
    }
}
<|endoftext|>


<commit_before>#![recursion_limit = "128"]
#![feature(proc_macro)]

#[macro_use]
extern crate quote;
#[macro_use]
extern crate syn;
extern crate proc_macro;
extern crate proc_macro2;

mod args;
mod parser;

use proc_macro::TokenStream;
use syn::punctuated::Punctuated;

#[derive(Debug, Clone)]
struct KvPair(syn::Ident, syn::Expr);

#[derive(Debug, Clone)]
struct Object(Punctuated<KvPair, Token![,]>);

#[derive(Debug, Clone)]
struct List(Punctuated<syn::Expr, Token![,]>);

#[derive(Debug, Clone)]
struct Elems(Punctuated<syn::Expr, Token![,]>);

#[derive(Debug, Clone)]
struct Args {
    elems: Option<Elems>,
    opts: Option<Object>,
    closure: Option<syn::Expr>,
}

/// Splice an array of arguments into another term
///
/// A macro that’s used to splice a number of arguments into another term. This is
/// useful when you want to call a variadic term such as `branch` with a set of arguments produced at
/// runtime.
///
/// # Example
///
/// If `x` is greater than `5` return `big`, otherwise return `small`.
///
/// ```rust,ignore
/// r.branch(args!(r.expr(x).gt(5), "big", "small"));
/// ```
#[proc_macro]
pub fn args(input: TokenStream) -> TokenStream {
    let body = if input.is_empty() {
        quote!(Term::new())
    }

    else {
        let raw = input.to_string();
        syn::parse::<Args>(input)
            .unwrap()
            .process(raw)
    };

    let expanded = quote!({
        #[allow(unused_imports)]
        use reql::{Term, IntoArg, Arg};
        #body
    });

    expanded.into()
}
<commit_msg>add a note about the nightly compiler<commit_after>#![recursion_limit = "128"]
#![feature(proc_macro)]

//! This crate provides macros for making ReQL types more pleasant to work with.
//! Currently, it only exposes the `args` macro but it's possible that more will
//! be added in the future.
//!
//! In this crate we make use of a couple nightly features, specifically
//! `proc_macro` and `proc_macro_non_items` so you will need to use the nightly
//! compiler in order to use the macros here. Add the following to your crate:-
//!
//! ```rust,ignore
//! #![feature(proc_macro)]
//! #![feature(proc_macro_non_items)]
//! ```

#[macro_use]
extern crate quote;
#[macro_use]
extern crate syn;
extern crate proc_macro;
extern crate proc_macro2;

mod args;
mod parser;

use proc_macro::TokenStream;
use syn::punctuated::Punctuated;

#[derive(Debug, Clone)]
struct KvPair(syn::Ident, syn::Expr);

#[derive(Debug, Clone)]
struct Object(Punctuated<KvPair, Token![,]>);

#[derive(Debug, Clone)]
struct List(Punctuated<syn::Expr, Token![,]>);

#[derive(Debug, Clone)]
struct Elems(Punctuated<syn::Expr, Token![,]>);

#[derive(Debug, Clone)]
struct Args {
    elems: Option<Elems>,
    opts: Option<Object>,
    closure: Option<syn::Expr>,
}

/// Splice an array of arguments into another term
///
/// A macro that’s used to splice a number of arguments into another term. This is
/// useful when you want to call a variadic term such as `branch` with a set of arguments produced at
/// runtime.
///
/// # Example
///
/// If `x` is greater than `5` return `big`, otherwise return `small`.
///
/// ```rust,ignore
/// r.branch(args!(r.expr(x).gt(5), "big", "small"));
/// ```
#[proc_macro]
pub fn args(input: TokenStream) -> TokenStream {
    let body = if input.is_empty() {
        quote!(Term::new())
    }

    else {
        let raw = input.to_string();
        syn::parse::<Args>(input)
            .unwrap()
            .process(raw)
    };

    let expanded = quote!({
        #[allow(unused_imports)]
        use reql::{Term, IntoArg, Arg};
        #body
    });

    expanded.into()
}
<|endoftext|>


<commit_before>//! The integration suite for inspecting sessions.

extern crate libc;
extern crate rand;
extern crate regex;
extern crate yaml_rust;

mod helpers;

mod open {
    use rand::{random};
    use std::fs::File;
    use std::fs;
    use std::path::PathBuf;
    use std::io::prelude::*;
    use std::env::home_dir;
    use std::str;
    use helpers::*;
    use yaml_rust::YamlLoader;

    fn project_name(contents: &[u8]) -> String {
        let string_content = str::from_utf8(contents).unwrap();
        let yaml = YamlLoader::load_from_str(string_content).unwrap();

        match yaml[0]["name"].as_str() {
            Some(x) => x.to_string(),
            None    => format!("muxed_int_test_{}", random::<u16>())
        }
    }

    fn setup(contents: &[u8]) -> (String, PathBuf) {
        let project_name = project_name(&contents);
        let project_file = format!("/tmp/muxed_{}/{}.yml", random::<u16>(), project_name);
        let project_path = PathBuf::from(&project_file);

        let muxed_path = project_path.parent().unwrap();
        if !muxed_path.exists() { println!("{:?}", fs::create_dir(muxed_path)) };

        let mut buffer = File::create(&project_path).unwrap();
        let _ = buffer.write(contents);

        (project_name, project_path.clone())
    }

    fn cleanup(project_name: &String, config_path: &PathBuf) -> () {
        let _ = fs::remove_file(config_path);
        let _ = fs::remove_dir(config_path.parent().unwrap());
        kill_session(&project_name);
    }

    fn test_with_contents(contents: &[u8]) -> TmuxSession {
        let (project_name, config_path) = setup(contents);
        open_muxed(&project_name, config_path.parent().unwrap());

        let completed = PathBuf::from(format!("/tmp/{}.complete", project_name));
        let exec = format!("touch '{}'", completed.display());

        send_keys(&project_name, &exec);
        wait_on(&completed);

        let session = TmuxSession::from_string(&list_windows(&project_name.to_string()));
        cleanup(&project_name, &config_path);
        session
    }

    #[test]
    fn opens_3_windows_from_array() {
        let contents = b"---
windows: ['ls', 'vi', 'git']
";
        let session = test_with_contents(contents);
        assert_eq!(session.num_of_windows, 3)
    }

    #[test]
    fn opens_2_windows() {
        let contents = b"---
windows:
  - editor:
      layout: 'main-vertical'
      panes: ['ls', 'vi']
  - stuff: ''
";
        let session = test_with_contents(contents);
        assert_eq!(session.num_of_windows, 2)
    }

    #[test]
    fn opens_3_windows_with_integer_names() {
        let contents = b"---
windows: [1, 'ls', 3]
";
        let session = test_with_contents(contents);
        assert_eq!(session.num_of_windows, 3)
    }

    #[test]
    fn single_window_has_2_panes() {
        let contents = b"---
windows:
  - editor:
      layout: 'main-vertical'
      panes: ['ls', 'vi']
";
        let session = test_with_contents(contents);
        let num = session.windows.get("editor").unwrap().panes.as_usize().unwrap();
        assert_eq!(num, 2)
    }

    #[test]
    fn multiple_windows_with_panes() {
        let contents = b"---
windows:
  - editor:
      layout: 'main-vertical'
      panes: ['ls', 'vi']
  - tests:
      layout: 'main-vertical'
      panes: ['ls', 'vi', 'ls']
";
        let session = test_with_contents(contents);
        let num = session.windows.get("editor").unwrap().panes.as_usize().unwrap();
        let num1 = session.windows.get("tests").unwrap().panes.as_usize().unwrap();
        assert_eq!(num, 2);
        assert_eq!(num1, 3)
    }

    #[test]
    fn window_with_empty_command_is_valid() {
        let contents = b"---
windows:
  - editor:
";
        let session = test_with_contents(contents);
        assert_eq!(session.num_of_windows, 1)
    }

    #[test]
    fn panes_with_empty_commands_are_valid() {
        let contents = b"---
windows:
  - editor:
      layout: 'main-vertical'
      panes:
        -
        -
";
        let session = test_with_contents(contents);
        let num = session.windows.get("editor").unwrap().panes.as_usize().unwrap();
        assert_eq!(num, 2)
    }

    #[test]
    fn expect_to_open_in_directory_containing_spaces() {
        let dir = PathBuf::from("/tmp/Directory With Spaces/");
        if !dir.exists() { println!("{:?}", fs::create_dir(&dir)) };
        let contents = b"---
root: /tmp/Directory With Spaces/
windows:
  - editor: ''
";
        let session = test_with_contents(contents);
        let pane_current_path = session.windows.get("editor").unwrap().pane_current_path.as_str().unwrap();
        let _ = fs::remove_dir(dir);
        // Use contains because OSX on travis ci symlinks /tmp/ to /private/tmp/
        // resulting in `pane_current_path` being `/private/tmp/Direct…`
        assert!(pane_current_path.contains("/tmp/Directory With Spaces"));
    }

    #[test]
    fn expect_home_var_to_open_in_home_dir() {
        let contents = b"---
root: '$HOME'
windows:
  - editor: ''
";
        let session = test_with_contents(contents);
        let pane_current_path = session.windows.get("editor").unwrap().pane_current_path.as_str().unwrap();
        assert_eq!(pane_current_path, home_dir().unwrap().to_str().unwrap());
    }

    #[test]
    fn expect_tilde_slash_to_open_in_home_dir() {
        let contents = b"---
root: ~/
windows:
  - editor: ''
";
        let session = test_with_contents(contents);
        let pane_current_path = session.windows.get("editor").unwrap().pane_current_path.as_str().unwrap();
        assert_eq!(pane_current_path, home_dir().unwrap().to_str().unwrap());
    }

    #[test]
    fn expect_focus_on_the_first_window() {
        let contents = b"---
windows: ['ssh', 'git']
";
        let session = test_with_contents(contents);
        let window_active = session.window_active.as_str().unwrap();
        assert_eq!(window_active, "ssh")
    }

    #[test]
    fn expect_pre_to_create_file() {
        let file = PathBuf::from(format!("/tmp/{}", random::<u16>()));
        let contents = format!("---
pre: touch {}
windows: ['ssh', 'git']
", file.display());
        let _ = test_with_contents(contents.as_bytes());
        assert!(file.exists());
        let _ = fs::remove_file(file);
    }

    #[test]
    fn expect_pre_to_create_two_files() {
        let file1 = PathBuf::from(format!("/tmp/{}", random::<u16>()));
        let file2 = PathBuf::from(format!("/tmp/{}", random::<u16>()));
        let contents = format!("---
pre:
  - touch {}
  - touch {}
windows: ['ssh', 'git']
", file1.display(), file2.display());
        let _ = test_with_contents(contents.as_bytes());
        assert!(file1.exists());
        assert!(file2.exists());
        let _ = fs::remove_file(file1);
        let _ = fs::remove_file(file2);
    }

    #[test]
    fn expect_pre_window_to_be_called_for_each_window() {
        let file = PathBuf::from(format!("/tmp/{}", random::<u16>()));
        let contents = format!("---
pre_window: echo 'pre_window' >> {}
windows: ['ssh', 'git']
", file.display());
        let _ = test_with_contents(contents.as_bytes());
        let mut f = File::open(&file).unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s);
        assert_eq!(s.lines().count(), 2);
        let _ = fs::remove_file(&file);
    }

    #[test]
    fn expect_pre_window_to_be_called_twice_for_each_window() {
        let file = PathBuf::from(format!("/tmp/{}", random::<u16>()));
        let contents = format!("---
pre_window:
 - echo 'pre_window' >> {}
 - echo 'pre_window' >> {}
windows: ['ssh', 'git']
", file.display(), file.display());
        let _ = test_with_contents(contents.as_bytes());
        let mut f = File::open(&file).unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s);
        assert_eq!(s.lines().count(), 4);
        let _ = fs::remove_file(&file);
    }

    #[test]
    fn expect_session_name_brians_session() {
        let contents = b"---
name: 'Brians Session'
windows: ['ssh', 'git']
";
        let session = test_with_contents(contents);
        let name = session.name.as_str().unwrap();
        assert_eq!(name, "Brians Session")
    }

// This test should exist but we currently don't do anything to list panes.
//    #[test]
//    fn expect_focus_on_the_top_pane() {
//        let contents = b"---
//windows:
//  - ssh:
//    layout: main-horizontal
//    panes:
//      - ''
//      - ''
//  - git: ''
//";
//        let session = test_with_contents(contents);
//        assert_eq!(session.pane_active, "ssh.0")
//    }
}
<commit_msg>refactor(tests/open): Better hashmap access<commit_after>//! The integration suite for inspecting sessions.

extern crate libc;
extern crate rand;
extern crate regex;
extern crate yaml_rust;

mod helpers;

mod open {
    use rand::{random};
    use std::fs::File;
    use std::fs;
    use std::path::PathBuf;
    use std::io::prelude::*;
    use std::env::home_dir;
    use std::str;
    use helpers::*;
    use yaml_rust::YamlLoader;

    fn project_name(contents: &[u8]) -> String {
        let string_content = str::from_utf8(contents).unwrap();
        let yaml = YamlLoader::load_from_str(string_content).unwrap();

        match yaml[0]["name"].as_str() {
            Some(x) => x.to_string(),
            None    => format!("muxed_int_test_{}", random::<u16>())
        }
    }

    fn setup(contents: &[u8]) -> (String, PathBuf) {
        let project_name = project_name(&contents);
        let project_file = format!("/tmp/muxed_{}/{}.yml", random::<u16>(), project_name);
        let project_path = PathBuf::from(&project_file);

        let muxed_path = project_path.parent().unwrap();
        if !muxed_path.exists() { println!("{:?}", fs::create_dir(muxed_path)) };

        let mut buffer = File::create(&project_path).unwrap();
        let _ = buffer.write(contents);

        (project_name, project_path.clone())
    }

    fn cleanup(project_name: &String, config_path: &PathBuf) -> () {
        let _ = fs::remove_file(config_path);
        let _ = fs::remove_dir(config_path.parent().unwrap());
        kill_session(&project_name);
    }

    fn test_with_contents(contents: &[u8]) -> TmuxSession {
        let (project_name, config_path) = setup(contents);
        open_muxed(&project_name, config_path.parent().unwrap());

        let completed = PathBuf::from(format!("/tmp/{}.complete", project_name));
        let exec = format!("touch '{}'", completed.display());

        send_keys(&project_name, &exec);
        wait_on(&completed);

        let session = TmuxSession::from_string(&list_windows(&project_name.to_string()));
        cleanup(&project_name, &config_path);
        session
    }

    #[test]
    fn opens_3_windows_from_array() {
        let contents = b"---
windows: ['ls', 'vi', 'git']
";
        let session = test_with_contents(contents);
        assert_eq!(session.num_of_windows, 3)
    }

    #[test]
    fn opens_2_windows() {
        let contents = b"---
windows:
  - editor:
      layout: 'main-vertical'
      panes: ['ls', 'vi']
  - stuff: ''
";
        let session = test_with_contents(contents);
        assert_eq!(session.num_of_windows, 2)
    }

    #[test]
    fn opens_3_windows_with_integer_names() {
        let contents = b"---
windows: [1, 'ls', 3]
";
        let session = test_with_contents(contents);
        assert_eq!(session.num_of_windows, 3)
    }

    #[test]
    fn single_window_has_2_panes() {
        let contents = b"---
windows:
  - editor:
      layout: 'main-vertical'
      panes: ['ls', 'vi']
";
        let session = test_with_contents(contents);
        let num = session.windows["editor"].panes.as_usize().unwrap();
        assert_eq!(num, 2)
    }

    #[test]
    fn multiple_windows_with_panes() {
        let contents = b"---
windows:
  - editor:
      layout: 'main-vertical'
      panes: ['ls', 'vi']
  - tests:
      layout: 'main-vertical'
      panes: ['ls', 'vi', 'ls']
";
        let session = test_with_contents(contents);
        let num = session.windows["editor"].panes.as_usize().unwrap();
        let num1 = session.windows["tests"].panes.as_usize().unwrap();
        assert_eq!(num, 2);
        assert_eq!(num1, 3)
    }

    #[test]
    fn window_with_empty_command_is_valid() {
        let contents = b"---
windows:
  - editor:
";
        let session = test_with_contents(contents);
        assert_eq!(session.num_of_windows, 1)
    }

    #[test]
    fn panes_with_empty_commands_are_valid() {
        let contents = b"---
windows:
  - editor:
      layout: 'main-vertical'
      panes:
        -
        -
";
        let session = test_with_contents(contents);
        let num = session.windows["editor"].panes.as_usize().unwrap();
        assert_eq!(num, 2)
    }

    #[test]
    fn expect_to_open_in_directory_containing_spaces() {
        let dir = PathBuf::from("/tmp/Directory With Spaces/");
        if !dir.exists() { println!("{:?}", fs::create_dir(&dir)) };
        let contents = b"---
root: /tmp/Directory With Spaces/
windows:
  - editor: ''
";
        let session = test_with_contents(contents);
        let pane_current_path = session.windows["editor"].pane_current_path.as_str().unwrap();
        let _ = fs::remove_dir(dir);
        // Use contains because OSX on travis ci symlinks /tmp/ to /private/tmp/
        // resulting in `pane_current_path` being `/private/tmp/Direct…`
        assert!(pane_current_path.contains("/tmp/Directory With Spaces"));
    }

    #[test]
    fn expect_home_var_to_open_in_home_dir() {
        let contents = b"---
root: '$HOME'
windows:
  - editor: ''
";
        let session = test_with_contents(contents);
        let pane_current_path = session.windows["editor"].pane_current_path.as_str().unwrap();
        assert_eq!(pane_current_path, home_dir().unwrap().to_str().unwrap());
    }

    #[test]
    fn expect_tilde_slash_to_open_in_home_dir() {
        let contents = b"---
root: ~/
windows:
  - editor: ''
";
        let session = test_with_contents(contents);
        let pane_current_path = session.windows["editor"].pane_current_path.as_str().unwrap();
        assert_eq!(pane_current_path, home_dir().unwrap().to_str().unwrap());
    }

    #[test]
    fn expect_focus_on_the_first_window() {
        let contents = b"---
windows: ['ssh', 'git']
";
        let session = test_with_contents(contents);
        let window_active = session.window_active.as_str().unwrap();
        assert_eq!(window_active, "ssh")
    }

    #[test]
    fn expect_pre_to_create_file() {
        let file = PathBuf::from(format!("/tmp/{}", random::<u16>()));
        let contents = format!("---
pre: touch {}
windows: ['ssh', 'git']
", file.display());
        let _ = test_with_contents(contents.as_bytes());
        assert!(file.exists());
        let _ = fs::remove_file(file);
    }

    #[test]
    fn expect_pre_to_create_two_files() {
        let file1 = PathBuf::from(format!("/tmp/{}", random::<u16>()));
        let file2 = PathBuf::from(format!("/tmp/{}", random::<u16>()));
        let contents = format!("---
pre:
  - touch {}
  - touch {}
windows: ['ssh', 'git']
", file1.display(), file2.display());
        let _ = test_with_contents(contents.as_bytes());
        assert!(file1.exists());
        assert!(file2.exists());
        let _ = fs::remove_file(file1);
        let _ = fs::remove_file(file2);
    }

    #[test]
    fn expect_pre_window_to_be_called_for_each_window() {
        let file = PathBuf::from(format!("/tmp/{}", random::<u16>()));
        let contents = format!("---
pre_window: echo 'pre_window' >> {}
windows: ['ssh', 'git']
", file.display());
        let _ = test_with_contents(contents.as_bytes());
        let mut f = File::open(&file).unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s);
        assert_eq!(s.lines().count(), 2);
        let _ = fs::remove_file(&file);
    }

    #[test]
    fn expect_pre_window_to_be_called_twice_for_each_window() {
        let file = PathBuf::from(format!("/tmp/{}", random::<u16>()));
        let contents = format!("---
pre_window:
 - echo 'pre_window' >> {}
 - echo 'pre_window' >> {}
windows: ['ssh', 'git']
", file.display(), file.display());
        let _ = test_with_contents(contents.as_bytes());
        let mut f = File::open(&file).unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s);
        assert_eq!(s.lines().count(), 4);
        let _ = fs::remove_file(&file);
    }

    #[test]
    fn expect_session_name_brians_session() {
        let contents = b"---
name: 'Brians Session'
windows: ['ssh', 'git']
";
        let session = test_with_contents(contents);
        let name = session.name.as_str().unwrap();
        assert_eq!(name, "Brians Session")
    }

// This test should exist but we currently don't do anything to list panes.
//    #[test]
//    fn expect_focus_on_the_top_pane() {
//        let contents = b"---
//windows:
//  - ssh:
//    layout: main-horizontal
//    panes:
//      - ''
//      - ''
//  - git: ''
//";
//        let session = test_with_contents(contents);
//        assert_eq!(session.pane_active, "ssh.0")
//    }
}
<|endoftext|>


<commit_before>extern crate udt;
#[macro_use]
extern crate log;

use udt::*;

#[cfg(target_os="linux")]
fn do_platform_specific_init(sock: &mut UdtSocket) {}

#[cfg(target_os="macos")]
fn do_platform_specific_init(sock: &mut UdtSocket) {
    sock.setsockopt(UdtOpts::UDP_RCVBUF, 8192).unwrap();
    sock.setsockopt(UdtOpts::UDP_SNDBUF, 8192).unwrap();
}

#[test]
fn test_getsockopt() {
    init();
    let mut sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Datagram).unwrap();
    do_platform_specific_init(&mut sock);

    // test some defaults
    assert_eq!(sock.getsockopt(UdtOpts::UDT_MSS).unwrap(), 1500 as i32);
    assert_eq!(sock.getsockopt(UdtOpts::UDT_SNDSYN).unwrap(), true);
    assert_eq!(sock.getsockopt(UdtOpts::UDT_RCVSYN).unwrap(), true);
    assert_eq!(sock.getsockopt(UdtOpts::UDT_FC).unwrap(), 25600 as i32);
    assert_eq!(sock.getsockopt(UdtOpts::UDT_RENDEZVOUS).unwrap(), false);
    assert_eq!(sock.getsockopt(UdtOpts::UDT_SNDTIMEO).unwrap(), -1);
    assert_eq!(sock.getsockopt(UdtOpts::UDT_RCVTIMEO).unwrap(), -1);

}

#[test]
fn test_setsockopt() {
    init();
    let mut sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Datagram).unwrap();
    do_platform_specific_init(&mut sock);

    assert_eq!(sock.getsockopt(UdtOpts::UDT_MSS).unwrap(), 1500);
    sock.setsockopt(UdtOpts::UDT_MSS, 1400).unwrap();
    assert_eq!(sock.getsockopt(UdtOpts::UDT_MSS).unwrap(), 1400);
}

#[test]
fn test_sendmsg() {
    use std::thread::spawn;
    use std::net::{SocketAddr, SocketAddrV4};
    use std::net::Ipv4Addr;
    use std::str::FromStr;
    use std::sync::mpsc::channel;

    init();

    let localhost = Ipv4Addr::from_str("127.0.0.1").unwrap();

    // the server will bind to a random port and pass it back for the client to connect to
    let (tx, rx) = channel();

    // spawn the server
    let server = spawn(move || {
        let mut sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Datagram).unwrap();
        do_platform_specific_init(&mut sock);
        sock.bind(SocketAddr::V4(SocketAddrV4::new(localhost, 0))).unwrap();
        let my_addr = sock.getsockname().unwrap();
        debug!("Server bound to {:?}", my_addr);

        sock.listen(5).unwrap();

        tx.send(my_addr.port());

        let (mut new, peer) = sock.accept().unwrap();
        debug!("Server recieved connection from {:?}", peer);

        let peer2 = new.getpeername().unwrap();
        assert_eq!(peer2, peer);

        let msg = new.recvmsg(100).unwrap();
        assert_eq!(msg.len(), 5);
        assert_eq!(msg, "hello".as_bytes());
        new.sendmsg("world".as_bytes()).unwrap();

        new.close();
        sock.close();

    });

    let client = spawn(move || {
        let port = rx.recv().unwrap();
        debug!("Client connecting to port {:?}", port);
        let mut sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Datagram).unwrap();
        do_platform_specific_init(&mut sock);
        sock.connect(SocketAddr::V4(SocketAddrV4::new(localhost, port))).unwrap();

        sock.sendmsg("hello".as_bytes()).unwrap();
        let msg = sock.recvmsg(1024).unwrap();
        assert_eq!(msg.len(), 5);
        assert_eq!(msg, "world".as_bytes());

        sock.close();

    });

    server.join().unwrap();
    client.join().unwrap();

}

#[test]
fn test_send() {
    use std::thread::spawn;
    use std::net::{SocketAddr, SocketAddrV4};
    use std::net::Ipv4Addr;
    use std::str::FromStr;
    use std::sync::mpsc::channel;

    init();

    let localhost = Ipv4Addr::from_str("127.0.0.1").unwrap();

    // the server will bind to a random port and pass it back for the client to connect to
    let (tx, rx) = channel();

    // spawn the server
    let server = spawn(move || {
        let mut sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Stream).unwrap();
        do_platform_specific_init(&mut sock);
        sock.bind(SocketAddr::V4(SocketAddrV4::new(localhost, 0))).unwrap();
        let my_addr = sock.getsockname().unwrap();
        debug!("Server bound to {:?}", my_addr);

        sock.listen(5).unwrap();

        tx.send(my_addr.port());

        let (mut new, new_peer) = sock.accept().unwrap();
        debug!("Server recieved connection from {:?}", new_peer);

        let mut buf: [u8; 10] = [0; 10];
        assert_eq!(new.recv(&mut buf, 5).unwrap(), 5);
        assert_eq!(&buf[0..5], "hello".as_bytes());
        assert_eq!(&buf[5..], [0; 5]);
        assert_eq!(new.recv(&mut buf[5..], 5).unwrap(), 5);
        assert_eq!(&buf[5..], "world".as_bytes());
        assert_eq!(&buf, "helloworld".as_bytes());

        new.close();
        sock.close();

    });

    let client = spawn(move || {
        let port = rx.recv().unwrap();
        debug!("Client connecting to port {:?}", port);
        let mut sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Stream).unwrap();
        do_platform_specific_init(&mut sock);
        sock.connect(SocketAddr::V4(SocketAddrV4::new(localhost, port))).unwrap();

        assert_eq!(sock.send("hello".as_bytes()).unwrap(), 5);
        assert_eq!(sock.send("world".as_bytes()).unwrap(), 5);

        sock.close();

    });

    server.join().unwrap();
    client.join().unwrap();

}

#[test]
fn test_epoll() {
    use std::thread::spawn;
    use std::net::{SocketAddr, SocketAddrV4};
    use std::net::Ipv4Addr;
    use std::str::FromStr;
    use std::sync::mpsc::channel;
    use std::thread::sleep_ms;

    init();

    let localhost = Ipv4Addr::from_str("127.0.0.1").unwrap();

    // the server will bind to a random port and pass it back for the client to connect to
    let (tx, rx) = channel();

    // spawn the server
    let server = spawn(move || {
        let mut sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Datagram).unwrap();
        do_platform_specific_init(&mut sock);
        sock.bind(SocketAddr::V4(SocketAddrV4::new(localhost, 0))).unwrap();
        let my_addr = sock.getsockname().unwrap();
        debug!("Server bound to {:?}", my_addr);

        sock.listen(5).unwrap();

        tx.send(my_addr.port());

        let mut epoll = Epoll::create().unwrap();

        epoll.add_usock(&sock).unwrap();

        let mut counter = 0;
        loop {
            let (pending_rd, pending_wr) = epoll.wait(1000, true).unwrap();
            debug!("Pending sockets: {:?} {:?}", pending_rd, pending_wr);

            let rd_len = pending_rd.len();
            for mut s in pending_rd {
                if s == sock {
                    debug!("trying to accept new sock");
                    let (mut new, peer) = sock.accept().unwrap();
                    debug!("Server recieved connection from {:?}", peer);
                    epoll.add_usock(&new).unwrap();
                } else {
                    let msg = s.recvmsg(100).unwrap();
                    let msg_string = String::from_utf8(msg).unwrap();
                    debug!("Received message: {:?}", msg_string);
                }

            }

            for mut s in pending_wr {
                let state = s.getstate();
                if rd_len == 0 && (state == UdtStatus::BROKEN || state == UdtStatus::CLOSED || state == UdtStatus::NONEXIST) {
                    epoll.remove_usock(&s);
                    return;
                }
                debug!("Sock {:?} is in state {:?}", s, state);
            }
            sleep_ms(100);
            counter += 1;
            assert!(counter < 500);
        }

        sock.close();

    });

    let client = spawn(move || {
        let port = rx.recv().unwrap();
        debug!("Client connecting to port {:?}", port);
        let mut sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Datagram).unwrap();
        do_platform_specific_init(&mut sock);
        sock.connect(SocketAddr::V4(SocketAddrV4::new(localhost, port))).unwrap();

        sock.sendmsg("hello".as_bytes()).unwrap();

        sleep_ms(3000);
        sock.sendmsg("world".as_bytes()).unwrap();
        sock.sendmsg("done.".as_bytes()).unwrap();

        sock.close();

    });

    server.join().unwrap();
    client.join().unwrap();

}

<commit_msg>Unwrap a bunch of Results in test.rs<commit_after>extern crate udt;
#[macro_use]
extern crate log;

use udt::*;

#[cfg(target_os="linux")]
fn do_platform_specific_init(sock: &mut UdtSocket) {}

#[cfg(target_os="macos")]
fn do_platform_specific_init(sock: &mut UdtSocket) {
    sock.setsockopt(UdtOpts::UDP_RCVBUF, 8192).unwrap();
    sock.setsockopt(UdtOpts::UDP_SNDBUF, 8192).unwrap();
}

#[test]
fn test_getsockopt() {
    init();
    let mut sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Datagram).unwrap();
    do_platform_specific_init(&mut sock);

    // test some defaults
    assert_eq!(sock.getsockopt(UdtOpts::UDT_MSS).unwrap(), 1500 as i32);
    assert_eq!(sock.getsockopt(UdtOpts::UDT_SNDSYN).unwrap(), true);
    assert_eq!(sock.getsockopt(UdtOpts::UDT_RCVSYN).unwrap(), true);
    assert_eq!(sock.getsockopt(UdtOpts::UDT_FC).unwrap(), 25600 as i32);
    assert_eq!(sock.getsockopt(UdtOpts::UDT_RENDEZVOUS).unwrap(), false);
    assert_eq!(sock.getsockopt(UdtOpts::UDT_SNDTIMEO).unwrap(), -1);
    assert_eq!(sock.getsockopt(UdtOpts::UDT_RCVTIMEO).unwrap(), -1);

}

#[test]
fn test_setsockopt() {
    init();
    let mut sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Datagram).unwrap();
    do_platform_specific_init(&mut sock);

    assert_eq!(sock.getsockopt(UdtOpts::UDT_MSS).unwrap(), 1500);
    sock.setsockopt(UdtOpts::UDT_MSS, 1400).unwrap();
    assert_eq!(sock.getsockopt(UdtOpts::UDT_MSS).unwrap(), 1400);
}

#[test]
fn test_sendmsg() {
    use std::thread::spawn;
    use std::net::{SocketAddr, SocketAddrV4};
    use std::net::Ipv4Addr;
    use std::str::FromStr;
    use std::sync::mpsc::channel;

    init();

    let localhost = Ipv4Addr::from_str("127.0.0.1").unwrap();

    // the server will bind to a random port and pass it back for the client to connect to
    let (tx, rx) = channel();

    // spawn the server
    let server = spawn(move || {
        let mut sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Datagram).unwrap();
        do_platform_specific_init(&mut sock);
        sock.bind(SocketAddr::V4(SocketAddrV4::new(localhost, 0))).unwrap();
        let my_addr = sock.getsockname().unwrap();
        debug!("Server bound to {:?}", my_addr);

        sock.listen(5).unwrap();

        tx.send(my_addr.port()).unwrap();

        let (mut new, peer) = sock.accept().unwrap();
        debug!("Server recieved connection from {:?}", peer);

        let peer2 = new.getpeername().unwrap();
        assert_eq!(peer2, peer);

        let msg = new.recvmsg(100).unwrap();
        assert_eq!(msg.len(), 5);
        assert_eq!(msg, "hello".as_bytes());
        new.sendmsg("world".as_bytes()).unwrap();

        new.close().unwrap();
        sock.close().unwrap();

    });

    let client = spawn(move || {
        let port = rx.recv().unwrap();
        debug!("Client connecting to port {:?}", port);
        let mut sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Datagram).unwrap();
        do_platform_specific_init(&mut sock);
        sock.connect(SocketAddr::V4(SocketAddrV4::new(localhost, port))).unwrap();

        sock.sendmsg("hello".as_bytes()).unwrap();
        let msg = sock.recvmsg(1024).unwrap();
        assert_eq!(msg.len(), 5);
        assert_eq!(msg, "world".as_bytes());

        sock.close().unwrap();

    });

    server.join().unwrap();
    client.join().unwrap();

}

#[test]
fn test_send() {
    use std::thread::spawn;
    use std::net::{SocketAddr, SocketAddrV4};
    use std::net::Ipv4Addr;
    use std::str::FromStr;
    use std::sync::mpsc::channel;

    init();

    let localhost = Ipv4Addr::from_str("127.0.0.1").unwrap();

    // the server will bind to a random port and pass it back for the client to connect to
    let (tx, rx) = channel();

    // spawn the server
    let server = spawn(move || {
        let mut sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Stream).unwrap();
        do_platform_specific_init(&mut sock);
        sock.bind(SocketAddr::V4(SocketAddrV4::new(localhost, 0))).unwrap();
        let my_addr = sock.getsockname().unwrap();
        debug!("Server bound to {:?}", my_addr);

        sock.listen(5).unwrap();

        tx.send(my_addr.port()).unwrap();

        let (mut new, new_peer) = sock.accept().unwrap();
        debug!("Server recieved connection from {:?}", new_peer);

        let mut buf: [u8; 10] = [0; 10];
        assert_eq!(new.recv(&mut buf, 5).unwrap(), 5);
        assert_eq!(&buf[0..5], "hello".as_bytes());
        assert_eq!(&buf[5..], [0; 5]);
        assert_eq!(new.recv(&mut buf[5..], 5).unwrap(), 5);
        assert_eq!(&buf[5..], "world".as_bytes());
        assert_eq!(&buf, "helloworld".as_bytes());

        new.close().unwrap();
        sock.close().unwrap();

    });

    let client = spawn(move || {
        let port = rx.recv().unwrap();
        debug!("Client connecting to port {:?}", port);
        let mut sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Stream).unwrap();
        do_platform_specific_init(&mut sock);
        sock.connect(SocketAddr::V4(SocketAddrV4::new(localhost, port))).unwrap();

        assert_eq!(sock.send("hello".as_bytes()).unwrap(), 5);
        assert_eq!(sock.send("world".as_bytes()).unwrap(), 5);

        sock.close().unwrap();

    });

    server.join().unwrap();
    client.join().unwrap();

}

#[test]
fn test_epoll() {
    use std::thread::spawn;
    use std::net::{SocketAddr, SocketAddrV4};
    use std::net::Ipv4Addr;
    use std::str::FromStr;
    use std::sync::mpsc::channel;
    use std::thread::sleep_ms;

    init();

    let localhost = Ipv4Addr::from_str("127.0.0.1").unwrap();

    // the server will bind to a random port and pass it back for the client to connect to
    let (tx, rx) = channel();

    // spawn the server
    let server = spawn(move || {
        let mut sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Datagram).unwrap();
        do_platform_specific_init(&mut sock);
        sock.bind(SocketAddr::V4(SocketAddrV4::new(localhost, 0))).unwrap();
        let my_addr = sock.getsockname().unwrap();
        debug!("Server bound to {:?}", my_addr);

        sock.listen(5).unwrap();

        tx.send(my_addr.port()).unwrap();

        let mut epoll = Epoll::create().unwrap();

        epoll.add_usock(&sock).unwrap();

        let mut counter = 0;
        loop {
            let (pending_rd, pending_wr) = epoll.wait(1000, true).unwrap();
            debug!("Pending sockets: {:?} {:?}", pending_rd, pending_wr);

            let rd_len = pending_rd.len();
            for mut s in pending_rd {
                if s == sock {
                    debug!("trying to accept new sock");
                    let (new, peer) = sock.accept().unwrap();
                    debug!("Server recieved connection from {:?}", peer);
                    epoll.add_usock(&new).unwrap();
                } else {
                    let msg = s.recvmsg(100).unwrap();
                    let msg_string = String::from_utf8(msg).unwrap();
                    debug!("Received message: {:?}", msg_string);
                }

            }

            for mut s in pending_wr {
                let state = s.getstate();
                if rd_len == 0 && (state == UdtStatus::BROKEN || state == UdtStatus::CLOSED || state == UdtStatus::NONEXIST) {
                    epoll.remove_usock(&s).unwrap();
                    return;
                }
                debug!("Sock {:?} is in state {:?}", s, state);
            }
            sleep_ms(100);
            counter += 1;
            assert!(counter < 500);
        }

    });

    let client = spawn(move || {
        let port = rx.recv().unwrap();
        debug!("Client connecting to port {:?}", port);
        let mut sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Datagram).unwrap();
        do_platform_specific_init(&mut sock);
        sock.connect(SocketAddr::V4(SocketAddrV4::new(localhost, port))).unwrap();

        sock.sendmsg("hello".as_bytes()).unwrap();

        sleep_ms(3000);
        sock.sendmsg("world".as_bytes()).unwrap();
        sock.sendmsg("done.".as_bytes()).unwrap();

        sock.close().unwrap();

    });

    server.join().unwrap();
    client.join().unwrap();

}

<|endoftext|>


<commit_before>
extern crate mio;
extern crate hyperhyper;
extern crate eventual;

use mio::*;
use hyperhyper::action::Echo;
use std::thread;
use eventual::Async;
use std::str;

#[test]
fn get_a_simple_webpage_2() {
    let mut event_loop = EventLoop::new().unwrap();
    let (tx, rx) = eventual::Future::<Box<Vec<u8>>, &'static str>::pair();

    //  poke_web_page_async(event_loop,
    // 	tx,
    //  	"google.com".to_string(),
    //   	80,
    //    	HttpAction::Get(Rc::new(String::from_str("/"))));
    event_loop.channel().send(("http://www.google.com/".to_string(), tx)).unwrap();

    thread::spawn(move || {
        let echo = &mut Echo::new();
        event_loop.run(echo).unwrap();
    });

    let vec = &*rx.await().unwrap();
    assert!( str::from_utf8(vec).unwrap().contains("google"));
}<commit_msg>Remove excess import<commit_after>
extern crate mio;
extern crate hyperhyper;
extern crate eventual;

use mio::EventLoop;
use hyperhyper::action::Echo;
use std::thread;
use eventual::Async;
use std::str;

#[test]
fn get_a_simple_webpage_2() {
    let mut event_loop = EventLoop::new().unwrap();
    let (tx, rx) = eventual::Future::<Box<Vec<u8>>, &'static str>::pair();

    //  poke_web_page_async(event_loop,
    // 	tx,
    //  	"google.com".to_string(),
    //   	80,
    //    	HttpAction::Get(Rc::new(String::from_str("/"))));
    event_loop.channel().send(("http://www.google.com/".to_string(), tx)).unwrap();

    thread::spawn(move || {
        let echo = &mut Echo::new();
        event_loop.run(echo).unwrap();
    });

    let vec = &*rx.await().unwrap();
    assert!( str::from_utf8(vec).unwrap().contains("google"));
}<|endoftext|>