<commit_before>use std::sync::Arc;
use std::collections::HashSet;
use std::iter::FromIterator;
use calx_grid::{Dir6, HexFov, Prefab};
use calx_ecs::Entity;
use calx_resource::{Resource, ResourceStore};
use world::World;
use components::{Alignment, BrainState};
use stats::Intrinsic;
use location::Location;
use brush::Brush;
use stats;
use FovStatus;
use fov::SightFov;
use terraform::TerrainQuery;
use world::Ecs;
use terrain;

/// Immutable querying of game world state.
pub trait Query: TerrainQuery {
    /// 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 }

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

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

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

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

    /// 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_brush(&self, e: Entity) -> Option<Resource<Brush>> {
        self.ecs().desc.get(e).map(|x| x.brush.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 + dir.to_v2()))
    }

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

    /// 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.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 position.
    fn mob_at(&self, loc: Location) -> Option<Entity> {
        self.entities_at(loc).into_iter().find(|&e| self.is_mob(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 => return true,
            1 => return self.has_intrinsic(e, Intrinsic::Fast),
            2 => return true,
            3 => return self.has_intrinsic(e, Intrinsic::Quick),
            4 => return !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;
        }
        return 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();
        for i in 1..(range + 1) {
            let loc = origin + dir.to_v2() * (i as i32);
            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 {
        match (self.alignment(e), self.alignment(other)) {
            (Some(Alignment::Chaotic), Some(_)) => true,
            (Some(_), Some(Alignment::Chaotic)) => true,
            (Some(Alignment::Evil), Some(Alignment::Good)) => true,
            (Some(Alignment::Good), Some(Alignment::Evil)) => true,
            _ => false,
        }
    }

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

    /// Return the field of view chart for visible tiles.
    fn sight_fov(w: &World, origin: Location, range: u32) -> HashSet<Location> {
        HashSet::from_iter(HexFov::new(SightFov::new(w, range, origin))
                               .map(|(pos, a)| a.origin + pos))
    }

    /// Return Id value of terrain at location for drawing on screen.
    fn visual_terrain_id(&self, loc: Location) -> u8 {
        let mut idx = self.terrain_id(loc);

        if idx == terrain::Id::Door as u8 {
            // Standing in the doorway opens the door.
            if self.has_mobs(loc) {
                idx = terrain::Id::OpenDoor as u8;
            }
        }

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

        idx
    }

    /// 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) -> Arc<terrain::Tile> {
        terrain::Tile::get_resource(&self.visual_terrain_id(loc)).unwrap()
    }

    /// Return the name that can be used to spawn this entity.
    fn spawn_name(&self, e: Entity) -> Option<String> {
        // TODO: Create a special component for this.
        None
    }

    fn is_spawn_name(&self, spawn_name: &str) -> bool {
        // TODO: Return true if `spawn_name` will build an entity in whatever factory system we'll
        // use.
        false
    }

    fn extract_prefab<I: IntoIterator<Item=Location>>(&self, locs: I) -> Prefab<(terrain::Id, Vec<String>)> {
        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 = terrain::Id::from_u8(self.terrain_id(loc)).expect("Corrupt terrain");

            let entities = Vec::from_iter(
                self.entities_at(loc).into_iter().filter_map(|e| self.spawn_name(e)));

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

        Prefab::from_iter(map.into_iter())
    }
}
<commit_msg>Spawnable entities written to prefabs<commit_after>use std::sync::Arc;
use std::collections::HashSet;
use std::iter::FromIterator;
use calx_grid::{Dir6, HexFov, Prefab};
use calx_ecs::Entity;
use calx_resource::{Resource, ResourceStore};
use world::World;
use components::{Alignment, BrainState};
use stats::Intrinsic;
use location::Location;
use brush::Brush;
use stats;
use FovStatus;
use fov::SightFov;
use terraform::TerrainQuery;
use world::Ecs;
use terrain;
use form;

/// Immutable querying of game world state.
pub trait Query: TerrainQuery {
    /// 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 }

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

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

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

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

    /// 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_brush(&self, e: Entity) -> Option<Resource<Brush>> {
        self.ecs().desc.get(e).map(|x| x.brush.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 + dir.to_v2()))
    }

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

    /// 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.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 position.
    fn mob_at(&self, loc: Location) -> Option<Entity> {
        self.entities_at(loc).into_iter().find(|&e| self.is_mob(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 => return true,
            1 => return self.has_intrinsic(e, Intrinsic::Fast),
            2 => return true,
            3 => return self.has_intrinsic(e, Intrinsic::Quick),
            4 => return !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;
        }
        return 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();
        for i in 1..(range + 1) {
            let loc = origin + dir.to_v2() * (i as i32);
            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 {
        match (self.alignment(e), self.alignment(other)) {
            (Some(Alignment::Chaotic), Some(_)) => true,
            (Some(_), Some(Alignment::Chaotic)) => true,
            (Some(Alignment::Evil), Some(Alignment::Good)) => true,
            (Some(Alignment::Good), Some(Alignment::Evil)) => true,
            _ => false,
        }
    }

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

    /// Return the field of view chart for visible tiles.
    fn sight_fov(w: &World, origin: Location, range: u32) -> HashSet<Location> {
        HashSet::from_iter(HexFov::new(SightFov::new(w, range, origin))
                               .map(|(pos, a)| a.origin + pos))
    }

    /// Return Id value of terrain at location for drawing on screen.
    fn visual_terrain_id(&self, loc: Location) -> u8 {
        let mut idx = self.terrain_id(loc);

        if idx == terrain::Id::Door as u8 {
            // Standing in the doorway opens the door.
            if self.has_mobs(loc) {
                idx = terrain::Id::OpenDoor as u8;
            }
        }

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

        idx
    }

    /// 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) -> Arc<terrain::Tile> {
        terrain::Tile::get_resource(&self.visual_terrain_id(loc)).unwrap()
    }

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

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

    fn extract_prefab<I: IntoIterator<Item=Location>>(&self, locs: I) -> Prefab<(terrain::Id, Vec<String>)> {
        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 = terrain::Id::from_u8(self.terrain_id(loc)).expect("Corrupt terrain");

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


<commit_before>extern crate crossbeam;
#[macro_use] extern crate version;
extern crate walkdir;

use std::env;
use std::process::exit;
use std::process::Command;
use std::process::Stdio;
use std::io::ErrorKind;

use walkdir::WalkDir;
use crossbeam::*;

fn help(cmds: Vec<String>) {
    println!(r#"

     _
    (_)_ __ ___   __ _  __ _
    | | '_ \` _ \/ _\`|/ _\`|
    | | | | | | | (_| | (_| |
    |_|_| |_| |_|\__,_|\__, |
                       |___/
    -------------------------

    Usage: imag [--version | --versions | -h | --help] <command> <args...>

    imag - the personal information management suite for the commandline

    imag is a PIM suite for the commandline. It consists of several commands,
    called "modules". Each module implements one PIM aspect and all of these
    modules can be used independently.

    Available commands:
    "#);

    for cmd in cmds.iter() {
        println!("\t{}", cmd);
    }

    println!(r#"

    Call a command with 'imag <command> <args>'
    Each command can be called with "--help" to get the respective helptext.

    Please visit https://github.com/matthiasbeyer/imag to view the source code,
    follow the development of imag or maybe even contribute to imag.

    imag is free software. It is released under the terms of LGPLv2.1

    (c) 2016 Matthias Beyer and contributors"#);
}

fn get_commands() -> Vec<String> {
    let path = env::var("PATH");
    if path.is_err() {
        println!("PATH error: {:?}", path);
        exit(1);
    }
    let pathelements = path.unwrap();
    let pathelements = pathelements.split(":");

    let joinhandles : Vec<ScopedJoinHandle<Vec<String>>> = pathelements
        .map(|elem| {
            crossbeam::scope(|scope| {
                scope.spawn(|| {
                    WalkDir::new(elem)
                        .max_depth(1)
                        .into_iter()
                        .filter(|path| {
                            match path {
                                &Ok(ref p) => p.file_name()
                                    .to_str()
                                    .map_or(false, |filename| filename.starts_with("imag-")),
                                &Err(_)   => false,
                            }
                        })
                        .filter_map(|x| x.ok())
                        .filter_map(|path| {
                           path.file_name()
                               .to_str()
                               .map(String::from)
                        })
                        .collect()
                })
            })
        })
        .collect();

    let mut execs = vec![];
    for joinhandle in joinhandles.into_iter() {
        let mut v = joinhandle.join();
        execs.append(&mut v);
    }

    execs
}

fn find_command() -> Option<String> {
    env::args().skip(1).filter(|x| !x.starts_with("-")).next()
}

fn find_flag() -> Option<String> {
    env::args().skip(1).filter(|x| x.starts_with("-")).next()
}

fn find_args(command: &str) -> Vec<String> {
    env::args()
        .skip(1)
        .position(|e| e == command)
        .map(|pos| env::args().skip(pos + 2).collect::<Vec<String>>())
        .unwrap_or(vec![])
}

fn main() {
    let commands  = get_commands();
    let mut args  = env::args();
    let _         = args.next();
    let first_arg = match find_command() {
        Some(s) => s,
        None    => match find_flag() {
            Some(s) => s,
            None => {
                help(commands);
                exit(0);
            },
        },
    };
    let is_debug = env::args().skip(1).filter(|x| x == "--debug").next().is_some();

    match &first_arg[..] {
        "--help" | "-h" => {
            help(commands);
            exit(0);
        },

        "--version"  => println!("imag {}", &version!()[..]),

        "--versions" => {
            let mut result = vec![];
            for command in commands.iter() {
                result.push(crossbeam::scope(|scope| {
                    scope.spawn(|| {
                        let v = Command::new(command).arg("--version").output();
                        match v {
                            Ok(v) => match String::from_utf8(v.stdout) {
                                Ok(s) => format!("{} -> {}", command, s),
                                Err(e) => format!("Failed calling {} -> {:?}", command, e),
                            },
                            Err(e) => format!("Failed calling {} -> {:?}", command, e),
                        }
                    })
                }))
            }

            for versionstring in result.into_iter().map(|handle| handle.join()) {
                println!("{}", versionstring);
            }
        },

        s => {
            let mut subcommand_args = find_args(s);
            if is_debug && subcommand_args.iter().find(|x| *x == "--debug").is_none() {
                subcommand_args.push(String::from("--debug"));
            }
            match Command::new(format!("imag-{}", s))
                .stdin(Stdio::inherit())
                .stdout(Stdio::inherit())
                .stderr(Stdio::inherit())
                .args(&subcommand_args[..])
                .spawn()
                .and_then(|mut handle| handle.wait())
            {
                Ok(exit_status) => {
                    if !exit_status.success() {
                        println!("{} exited with non-zero exit code", s);
                        exit(exit_status.code().unwrap_or(42));
                    }
                },

                Err(e) => {
                    match e.kind() {
                        ErrorKind::NotFound => {
                            println!("No such command: 'imag-{}'", s);
                            exit(2);
                        },
                        ErrorKind::PermissionDenied => {
                            println!("No permission to execute: 'imag-{}'", s);
                            exit(1);
                        },
                        _ => {
                            println!("Error spawning: {:?}", e);
                            exit(1337);
                        }
                    }
                }
            }

        },
    }
}
<commit_msg>Pulled out lambda and made "--debug" constant<commit_after>extern crate crossbeam;
#[macro_use] extern crate version;
extern crate walkdir;

use std::env;
use std::process::exit;
use std::process::Command;
use std::process::Stdio;
use std::io::ErrorKind;

use walkdir::WalkDir;
use crossbeam::*;

const DBG_FLAG: &'static str = "--debug";

fn help(cmds: Vec<String>) {
    println!(r#"

     _
    (_)_ __ ___   __ _  __ _
    | | '_ \` _ \/ _\`|/ _\`|
    | | | | | | | (_| | (_| |
    |_|_| |_| |_|\__,_|\__, |
                       |___/
    -------------------------

    Usage: imag [--version | --versions | -h | --help] <command> <args...>

    imag - the personal information management suite for the commandline

    imag is a PIM suite for the commandline. It consists of several commands,
    called "modules". Each module implements one PIM aspect and all of these
    modules can be used independently.

    Available commands:
    "#);

    for cmd in cmds.iter() {
        println!("\t{}", cmd);
    }

    println!(r#"

    Call a command with 'imag <command> <args>'
    Each command can be called with "--help" to get the respective helptext.

    Please visit https://github.com/matthiasbeyer/imag to view the source code,
    follow the development of imag or maybe even contribute to imag.

    imag is free software. It is released under the terms of LGPLv2.1

    (c) 2016 Matthias Beyer and contributors"#);
}

fn get_commands() -> Vec<String> {
    let path = env::var("PATH");
    if path.is_err() {
        println!("PATH error: {:?}", path);
        exit(1);
    }
    let pathelements = path.unwrap();
    let pathelements = pathelements.split(":");

    let joinhandles : Vec<ScopedJoinHandle<Vec<String>>> = pathelements
        .map(|elem| {
            crossbeam::scope(|scope| {
                scope.spawn(|| {
                    WalkDir::new(elem)
                        .max_depth(1)
                        .into_iter()
                        .filter(|path| {
                            match path {
                                &Ok(ref p) => p.file_name()
                                    .to_str()
                                    .map_or(false, |filename| filename.starts_with("imag-")),
                                &Err(_)   => false,
                            }
                        })
                        .filter_map(|x| x.ok())
                        .filter_map(|path| {
                           path.file_name()
                               .to_str()
                               .map(String::from)
                        })
                        .collect()
                })
            })
        })
        .collect();

    let mut execs = vec![];
    for joinhandle in joinhandles.into_iter() {
        let mut v = joinhandle.join();
        execs.append(&mut v);
    }

    execs
}

fn find_command() -> Option<String> {
    env::args().skip(1).filter(|x| !x.starts_with("-")).next()
}

fn find_flag() -> Option<String> {
    env::args().skip(1).filter(|x| x.starts_with("-")).next()
}

fn is_debug_flag<T: AsRef<str>>(ref s: &T) -> bool {
    s.as_ref() == DBG_FLAG
}

fn find_args(command: &str) -> Vec<String> {
    env::args()
        .skip(1)
        .position(|e| e == command)
        .map(|pos| env::args().skip(pos + 2).collect::<Vec<String>>())
        .unwrap_or(vec![])
}

fn main() {
    let commands  = get_commands();
    let mut args  = env::args();
    let _         = args.next();
    let first_arg = match find_command() {
        Some(s) => s,
        None    => match find_flag() {
            Some(s) => s,
            None => {
                help(commands);
                exit(0);
            },
        },
    };
    let is_debug = env::args().skip(1).find(is_debug_flag).is_some();

    match &first_arg[..] {
        "--help" | "-h" => {
            help(commands);
            exit(0);
        },

        "--version"  => println!("imag {}", &version!()[..]),

        "--versions" => {
            let mut result = vec![];
            for command in commands.iter() {
                result.push(crossbeam::scope(|scope| {
                    scope.spawn(|| {
                        let v = Command::new(command).arg("--version").output();
                        match v {
                            Ok(v) => match String::from_utf8(v.stdout) {
                                Ok(s) => format!("{} -> {}", command, s),
                                Err(e) => format!("Failed calling {} -> {:?}", command, e),
                            },
                            Err(e) => format!("Failed calling {} -> {:?}", command, e),
                        }
                    })
                }))
            }

            for versionstring in result.into_iter().map(|handle| handle.join()) {
                println!("{}", versionstring);
            }
        },

        s => {
            let mut subcommand_args = find_args(s);
            if is_debug && subcommand_args.iter().find(is_debug_flag).is_none() {
                subcommand_args.push(String::from(DBG_FLAG));
            }
            match Command::new(format!("imag-{}", s))
                .stdin(Stdio::inherit())
                .stdout(Stdio::inherit())
                .stderr(Stdio::inherit())
                .args(&subcommand_args[..])
                .spawn()
                .and_then(|mut handle| handle.wait())
            {
                Ok(exit_status) => {
                    if !exit_status.success() {
                        println!("{} exited with non-zero exit code", s);
                        exit(exit_status.code().unwrap_or(42));
                    }
                },

                Err(e) => {
                    match e.kind() {
                        ErrorKind::NotFound => {
                            println!("No such command: 'imag-{}'", s);
                            exit(2);
                        },
                        ErrorKind::PermissionDenied => {
                            println!("No permission to execute: 'imag-{}'", s);
                            exit(1);
                        },
                        _ => {
                            println!("Error spawning: {:?}", e);
                            exit(1337);
                        }
                    }
                }
            }

        },
    }
}
<|endoftext|>


<commit_before>use std::io::{self, Read, Write};
use uuid::Uuid;
use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian};
use tokio_core::io::{Codec, EasyBuf};

use errors::ErrorKind;
use package::{self, Package, TcpFlags, MessageContainer};
use {UsernamePassword};
use raw::RawMessage;

pub struct PackageCodec;

impl PackageCodec {
    fn decode_inner(&mut self, buf: &mut EasyBuf) -> io::Result<Option<Package>> {
        if buf.len() < 4 + 1 + 1 + 16 {
            return Ok(None);
        }

        let len = {
            let mut cursor = io::Cursor::new(buf.as_slice());
            cursor.read_u32::<LittleEndian>()?
        } as usize;

        if len < 18 {
            panic!("length is too little: {}", len);
        }

        if buf.len() < len + 4 {
            return Ok(None);
        }

        let mut frame = buf.clone();
        frame.drain_to(4);
        frame.split_off(len);

        let decoded_frame = self.decode_body(&mut frame);

        match decoded_frame {
            Ok((c, a, m)) => {
                buf.drain_to(4 + len);
                Ok(Some(Package {
                    correlation_id: c,
                    authentication: a,
                    message: m.into(),
                }))
            }
            Err(e) => Err(e),
        }
    }

    fn decode_body(&mut self,
                   buf: &mut EasyBuf)
                   -> io::Result<(Uuid, Option<UsernamePassword>, RawMessage<'static>)> {
        let (d, c, a) = self.decode_header(buf)?;
        let message = RawMessage::decode(d, buf.as_slice())?.into_owned();
        Ok((c, a, message))
    }

    fn decode_header(&mut self,
                     buf: &mut EasyBuf)
                     -> io::Result<(u8, Uuid, Option<UsernamePassword>)> {
        let (d, c, a, pos) = {
            let mut cursor = io::Cursor::new(buf.as_slice());
            let discriminator = cursor.read_u8()?;
            let flags = cursor.read_u8()?;
            let flags = match TcpFlags::from_bits(flags) {
                Some(flags) => flags,
                None => bail!(ErrorKind::InvalidFlags(flags)),
            };

            let correlation_id = {
                let mut uuid_bytes = [0u8; 16];
                cursor.read_exact(&mut uuid_bytes)?;
                // this should only err if len is not 16
                Uuid::from_bytes(&uuid_bytes).unwrap()
            };

            let authentication = if flags.contains(package::FLAG_AUTHENTICATED) {
                Some(UsernamePassword::decode(&mut cursor)?)
            } else {
                None
            };

            (discriminator, correlation_id, authentication, cursor.position() as usize)
        };

        buf.drain_to(pos);
        Ok((d, c, a))
    }
}

impl Codec for PackageCodec {
    type In = Package;
    type Out = Package;

    fn decode(&mut self, buf: &mut EasyBuf) -> io::Result<Option<Self::In>> {
        self.decode_inner(buf).map_err(|e| e.into())
    }

    fn encode(&mut self, msg: Package, buf: &mut Vec<u8>) -> io::Result<()> {
        // not sure how to make this without tmp vec
        let mut cursor = io::Cursor::new(Vec::new());

        let mut flags = package::FLAG_NONE;
        if msg.authentication.is_some() {
            flags.insert(package::FLAG_AUTHENTICATED);
        }

        let raw = match msg.message {
            MessageContainer::Raw(raw) => raw,
            MessageContainer::Adapted(ref adapted) => adapted.as_raw()
        };

        cursor.write_u32::<LittleEndian>(0)?; // placeholder for prefix
        cursor.write_u8(raw.discriminator())?;
        cursor.write_u8(flags.bits())?;
        cursor.write_all(msg.correlation_id.as_bytes())?;
        if flags.contains(package::FLAG_AUTHENTICATED) {
            msg.authentication
                .expect("According to flag authentication token is present")
                .encode(&mut cursor)?;
        }

        raw.encode(&mut cursor)?;

        let at_end = cursor.position();
        let len = at_end as u32 - 4;

        cursor.set_position(0);
        cursor.write_u32::<LittleEndian>(len)?;

        let tmp = cursor.into_inner();
        buf.extend(tmp);
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use std::fmt::Debug;
    use rustc_serialize::hex::FromHex;
    use tokio_core::io::Codec;
    use uuid::Uuid;
    use super::{PackageCodec};
    use package::Package;
    use errors;
    use {Message, WriteEventsCompleted, StreamVersion};

    #[test]
    fn decode_ping() {
        test_decoding_hex("1200000003007b50a1b034b9224e8f9d708c394fab2d",
                          PackageCodec,
                          Package {
                              authentication: None,
                              correlation_id:
                                  Uuid::parse_str("7b50a1b0-34b9-224e-8f9d-708c394fab2d").unwrap(),
                              message: Message::Ping,
                          });
    }

    #[test]
    fn decode_ping_with_junk() {
        test_decoding_hex("1300000003007b50a1b034b9224e8f9d708c394fab2d00",
                          PackageCodec,
                          Package {
                              authentication: None,
                              correlation_id:
                                  Uuid::parse_str("7b50a1b0-34b9-224e-8f9d-708c394fab2d").unwrap(),
                              message: Message::Ping,
                          });
    }

    #[test]
    fn encode_ping() {
        test_encoding_hex("1200000003007b50a1b034b9224e8f9d708c394fab2d",
                          PackageCodec,
                          Package {
                              authentication: None,
                              correlation_id:
                                  Uuid::parse_str("7b50a1b0-34b9-224e-8f9d-708c394fab2d").unwrap(),
                              message: Message::Ping,
                          });
    }

    #[test]
    fn decode_unknown_discriminator() {
        use std::io;

        let err = PackageCodec.decode(&mut ("12000000ff007b50a1b034b9224e8f9d708c394fab2d"
                .to_string()
                .from_hex()
                .unwrap()
                .into()))
            .unwrap_err();

        assert_eq!(err.kind(), io::ErrorKind::Other);
        let err = err.into_inner();
        match err {
            Some(inner) => {
                match *inner.downcast::<errors::Error>().unwrap() {
                    errors::Error(errors::ErrorKind::UnsupportedDiscriminator(0xff), _) => { /* good */ }
                    x => panic!("unexpected errorkind: {:?}", x),
                }
            }
            x => panic!("unexpected inner error: {:?}", x),
        }
    }

    #[test]
    fn decode_write_events_completed() {
        let input = "2200000083009b59d8734e9fd84eb8a421f2666a3aa40800181e20272884d6bc563084d6bc56";
        test_decoding_hex(input,
                          PackageCodec,
                          Package {
                              authentication: None,
                              correlation_id:
                                  Uuid::parse_str("9b59d873-4e9f-d84e-b8a4-21f2666a3aa4").unwrap(),
                              message: Message::WriteEventsCompleted(Ok(WriteEventsCompleted {
                                  event_numbers: StreamVersion::from(30)..StreamVersion::from(40),
                                  prepare_position: Some(181349124.into()),
                                  commit_position: Some(181349124.into())
                              }))
                          });
    }

    #[test]
    fn encode_write_events_completed() {
        test_encoding_hex("2200000083009b59d8734e9fd84eb8a421f2666a3aa40800181e20272884d6bc563084d6bc56",
                          PackageCodec,
                          Package {
                              authentication: None,
                              correlation_id:
                                  Uuid::parse_str("9b59d873-4e9f-d84e-b8a4-21f2666a3aa4").unwrap(),
                              message: Message::WriteEventsCompleted(Ok(WriteEventsCompleted {
                                  event_numbers: StreamVersion::from(30)..StreamVersion::from(40),
                                  prepare_position: Some(181349124.into()),
                                  commit_position: Some(181349124.into())
                              }))
                          });

    }

    fn test_decoding_hex<C: Codec>(input: &str, codec: C, expected: C::In)
        where C::In: Debug + PartialEq
    {
        test_decoding(input.to_string().from_hex().unwrap(), codec, expected);
    }

    fn test_decoding<C: Codec>(input: Vec<u8>, mut codec: C, expected: C::In)
        where C::In: Debug + PartialEq
    {
        // decode whole buffer
        {
            let mut buf = input.clone().into();
            let item = codec.decode(&mut buf).unwrap().unwrap();

            assert_eq!(item, expected);
            assert_eq!(buf.len(), 0, "decoding correctly sized buffer left bytes");
        }

        // decoding partial buffer consumes no bytes
        for len in 1..(input.len() - 1) {
            let mut part = input.clone();
            part.truncate(len);

            let mut buf = part.into();
            assert!(codec.decode(&mut buf).unwrap().is_none());
            assert_eq!(buf.len(), len, "decoding partial buffer consumed bytes");
        }

        // decoding a too long buffer consumes no extra bytes
        {
            let mut input = input.clone();
            let len = input.len();
            input.extend(vec![0u8; len]);
            let mut buf = input.into();
            let item = codec.decode(&mut buf).unwrap().unwrap();
            assert_eq!(item, expected);
            assert_eq!(buf.len(), len, "decoding oversized buffer overused bytes");
        }
    }

    fn test_encoding_hex<C: Codec>(input: &str, codec: C, expected: C::Out)
        where C::In: Debug + PartialEq
    {
        test_encoding(input.to_string().from_hex().unwrap(), codec, expected);
    }

    fn test_encoding<C: Codec>(input: Vec<u8>, mut codec: C, expected: C::Out)
        where C::In: Debug + PartialEq
    {
        let mut buf = Vec::new();
        codec.encode(expected, &mut buf).unwrap();
        assert_eq!(buf.as_slice(),
                   input.as_slice(),
                   "encoding did not yield same");
    }
}
<commit_msg>fix all but the example in lib<commit_after>use std::io::{self, Read, Write};
use uuid::Uuid;
use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian};
use tokio_core::io::{Codec, EasyBuf};

use errors::ErrorKind;
use package::{self, Package, TcpFlags, MessageContainer};
use {UsernamePassword};
use raw::RawMessage;

pub struct PackageCodec;

impl PackageCodec {
    fn decode_inner(&mut self, buf: &mut EasyBuf) -> io::Result<Option<Package>> {
        if buf.len() < 4 + 1 + 1 + 16 {
            return Ok(None);
        }

        let len = {
            let mut cursor = io::Cursor::new(buf.as_slice());
            cursor.read_u32::<LittleEndian>()?
        } as usize;

        if len < 18 {
            panic!("length is too little: {}", len);
        }

        if buf.len() < len + 4 {
            return Ok(None);
        }

        let mut frame = buf.clone();
        frame.drain_to(4);
        frame.split_off(len);

        let decoded_frame = self.decode_body(&mut frame);

        match decoded_frame {
            Ok((c, a, m)) => {
                buf.drain_to(4 + len);
                Ok(Some(Package {
                    correlation_id: c,
                    authentication: a,
                    message: m.into(),
                }))
            }
            Err(e) => Err(e),
        }
    }

    fn decode_body(&mut self,
                   buf: &mut EasyBuf)
                   -> io::Result<(Uuid, Option<UsernamePassword>, RawMessage<'static>)> {
        let (d, c, a) = self.decode_header(buf)?;
        let message = RawMessage::decode(d, buf.as_slice())?.into_owned();
        Ok((c, a, message))
    }

    fn decode_header(&mut self,
                     buf: &mut EasyBuf)
                     -> io::Result<(u8, Uuid, Option<UsernamePassword>)> {
        let (d, c, a, pos) = {
            let mut cursor = io::Cursor::new(buf.as_slice());
            let discriminator = cursor.read_u8()?;
            let flags = cursor.read_u8()?;
            let flags = match TcpFlags::from_bits(flags) {
                Some(flags) => flags,
                None => bail!(ErrorKind::InvalidFlags(flags)),
            };

            let correlation_id = {
                let mut uuid_bytes = [0u8; 16];
                cursor.read_exact(&mut uuid_bytes)?;
                // this should only err if len is not 16
                Uuid::from_bytes(&uuid_bytes).unwrap()
            };

            let authentication = if flags.contains(package::FLAG_AUTHENTICATED) {
                Some(UsernamePassword::decode(&mut cursor)?)
            } else {
                None
            };

            (discriminator, correlation_id, authentication, cursor.position() as usize)
        };

        buf.drain_to(pos);
        Ok((d, c, a))
    }
}

impl Codec for PackageCodec {
    type In = Package;
    type Out = Package;

    fn decode(&mut self, buf: &mut EasyBuf) -> io::Result<Option<Self::In>> {
        self.decode_inner(buf).map_err(|e| e.into())
    }

    fn encode(&mut self, msg: Package, buf: &mut Vec<u8>) -> io::Result<()> {
        // not sure how to make this without tmp vec
        let mut cursor = io::Cursor::new(Vec::new());

        let mut flags = package::FLAG_NONE;
        if msg.authentication.is_some() {
            flags.insert(package::FLAG_AUTHENTICATED);
        }

        let raw = match msg.message {
            MessageContainer::Raw(raw) => raw,
            MessageContainer::Adapted(ref adapted) => adapted.as_raw()
        };

        cursor.write_u32::<LittleEndian>(0)?; // placeholder for prefix
        cursor.write_u8(raw.discriminator())?;
        cursor.write_u8(flags.bits())?;
        cursor.write_all(msg.correlation_id.as_bytes())?;
        if flags.contains(package::FLAG_AUTHENTICATED) {
            msg.authentication
                .expect("According to flag authentication token is present")
                .encode(&mut cursor)?;
        }

        raw.encode(&mut cursor)?;

        let at_end = cursor.position();
        let len = at_end as u32 - 4;

        cursor.set_position(0);
        cursor.write_u32::<LittleEndian>(len)?;

        let tmp = cursor.into_inner();
        buf.extend(tmp);
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use std::fmt::Debug;
    use rustc_serialize::hex::FromHex;
    use tokio_core::io::Codec;
    use uuid::Uuid;
    use super::{PackageCodec};
    use package::Package;
    use raw::RawMessage;
    use client_messages::{WriteEventsCompleted, OperationResult};

    #[test]
    fn decode_ping() {
        test_decoding_hex("1200000003007b50a1b034b9224e8f9d708c394fab2d",
                          PackageCodec,
                          Package {
                              authentication: None,
                              correlation_id:
                                  Uuid::parse_str("7b50a1b0-34b9-224e-8f9d-708c394fab2d").unwrap(),
                              message: RawMessage::Ping.into(),
                          });
    }

    #[test]
    fn decode_ping_with_junk() {
        test_decoding_hex("1300000003007b50a1b034b9224e8f9d708c394fab2d00",
                          PackageCodec,
                          Package {
                              authentication: None,
                              correlation_id:
                                  Uuid::parse_str("7b50a1b0-34b9-224e-8f9d-708c394fab2d").unwrap(),
                              message: RawMessage::Ping.into(),
                          });
    }

    #[test]
    fn encode_ping() {
        test_encoding_hex("1200000003007b50a1b034b9224e8f9d708c394fab2d",
                          PackageCodec,
                          Package {
                              authentication: None,
                              correlation_id:
                                  Uuid::parse_str("7b50a1b0-34b9-224e-8f9d-708c394fab2d").unwrap(),
                              message: RawMessage::Ping.into(),
                          });
    }

    #[test]
    fn decode_unknown_discriminator() {
        use std::borrow::Cow;

        let err = PackageCodec.decode(&mut ("12000000ff007b50a1b034b9224e8f9d708c394fab2d"
                .to_string()
                .from_hex()
                .unwrap()
                .into()))
            .unwrap() // Result
            .unwrap();// Option

        assert_eq!(err, Package {
            authentication: None,
            correlation_id: Uuid::parse_str("7b50a1b0-34b9-224e-8f9d-708c394fab2d").unwrap(),
            message: RawMessage::Unsupported(255, Cow::Owned(vec![])).into()
        });
    }

    #[test]
    fn decode_write_events_completed() {
        let input = "2200000083009b59d8734e9fd84eb8a421f2666a3aa40800181e20272884d6bc563084d6bc56";
        test_decoding_hex(input,
                          PackageCodec,
                          Package {
                              authentication: None,
                              correlation_id:
                                  Uuid::parse_str("9b59d873-4e9f-d84e-b8a4-21f2666a3aa4").unwrap(),
                              message: RawMessage::WriteEventsCompleted(WriteEventsCompleted {
                                  result: Some(OperationResult::Success),
                                  message: None,
                                  first_event_number: 30,
                                  last_event_number: 39,
                                  prepare_position: Some(181349124),
                                  commit_position: Some(181349124)
                              }).into()
                          });
    }

    #[test]
    fn encode_write_events_completed() {
        test_encoding_hex("2200000083009b59d8734e9fd84eb8a421f2666a3aa40800181e20272884d6bc563084d6bc56",
                          PackageCodec,
                          Package {
                              authentication: None,
                              correlation_id:
                                  Uuid::parse_str("9b59d873-4e9f-d84e-b8a4-21f2666a3aa4").unwrap(),
                              message: RawMessage::WriteEventsCompleted(WriteEventsCompleted {
                                  result: Some(OperationResult::Success),
                                  message: None,
                                  first_event_number: 30,
                                  last_event_number: 39,
                                  prepare_position: Some(181349124),
                                  commit_position: Some(181349124)
                              }).into()
                          });

    }

    fn test_decoding_hex<C: Codec>(input: &str, codec: C, expected: C::In)
        where C::In: Debug + PartialEq
    {
        test_decoding(input.to_string().from_hex().unwrap(), codec, expected);
    }

    fn test_decoding<C: Codec>(input: Vec<u8>, mut codec: C, expected: C::In)
        where C::In: Debug + PartialEq
    {
        // decode whole buffer
        {
            let mut buf = input.clone().into();
            let item = codec.decode(&mut buf).unwrap().unwrap();

            assert_eq!(item, expected);
            assert_eq!(buf.len(), 0, "decoding correctly sized buffer left bytes");
        }

        // decoding partial buffer consumes no bytes
        for len in 1..(input.len() - 1) {
            let mut part = input.clone();
            part.truncate(len);

            let mut buf = part.into();
            assert!(codec.decode(&mut buf).unwrap().is_none());
            assert_eq!(buf.len(), len, "decoding partial buffer consumed bytes");
        }

        // decoding a too long buffer consumes no extra bytes
        {
            let mut input = input.clone();
            let len = input.len();
            input.extend(vec![0u8; len]);
            let mut buf = input.into();
            let item = codec.decode(&mut buf).unwrap().unwrap();
            assert_eq!(item, expected);
            assert_eq!(buf.len(), len, "decoding oversized buffer overused bytes");
        }
    }

    fn test_encoding_hex<C: Codec>(input: &str, codec: C, expected: C::Out)
        where C::In: Debug + PartialEq
    {
        test_encoding(input.to_string().from_hex().unwrap(), codec, expected);
    }

    fn test_encoding<C: Codec>(input: Vec<u8>, mut codec: C, expected: C::Out)
        where C::In: Debug + PartialEq
    {
        let mut buf = Vec::new();
        codec.encode(expected, &mut buf).unwrap();
        assert_eq!(buf.as_slice(),
                   input.as_slice(),
                   "encoding did not yield same");
    }
}
<|endoftext|>


<commit_before>//! A module to deserialize a RoomState struct from incorrectly specified v1
//! send_join endpoint.
//!
//! For more information, see this [GitHub issue](https://github.com/matrix-org/matrix-doc/issues/2541).

use std::fmt;

use serde::{
    de::{Deserializer, Error, IgnoredAny, SeqAccess, Visitor},
    ser::{SerializeSeq, Serializer},
};

use crate::membership::create_join_event::RoomState;

pub fn serialize<S>(room_state: &RoomState, serializer: S) -> Result<S::Ok, S::Error>
where
    S: Serializer,
{
    let mut seq = serializer.serialize_seq(Some(2))?;
    seq.serialize_element(&200)?;
    seq.serialize_element(room_state)?;
    seq.end()
}

pub fn deserialize<'de, D>(deserializer: D) -> Result<RoomState, D::Error>
where
    D: Deserializer<'de>,
{
    deserializer.deserialize_seq(RoomStateVisitor)
}

struct RoomStateVisitor;

impl<'de> Visitor<'de> for RoomStateVisitor {
    type Value = RoomState;
    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("Room State response wrapped in an array.")
    }

    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
    where
        A: SeqAccess<'de>,
    {
        let expected = "a two-element list in the response";
        if seq.next_element::<IgnoredAny>()?.is_none() {
            return Err(A::Error::invalid_length(0, &expected));
        }

        let room_state = seq
            .next_element()?
            .ok_or_else(|| A::Error::invalid_length(1, &expected))?;

        while let Some(IgnoredAny) = seq.next_element()? {
            // ignore extra elements
        }

        Ok(room_state)
    }
}

#[cfg(test)]
mod tests {
    use matches::assert_matches;
    use serde_json::{json, to_value as to_json_value};

    use super::{deserialize, serialize, RoomState};

    #[test]
    fn test_deserialize_response() {
        let response = json!([
            200,
            {
                "origin": "example.com",
                "auth_chain": [],
                "state": []
            }
        ]);

        let parsed = deserialize(response).unwrap();

        assert_matches!(
            parsed,
            RoomState { origin, auth_chain, state }
            if origin == "example.com"
                && auth_chain.is_empty()
                && state.is_empty()
        );
    }

    #[test]
    fn test_serialize_response() {
        let room_state = RoomState {
            origin: "matrix.org".to_string(),
            auth_chain: Vec::new(),
            state: Vec::new(),
        };

        let serialized = serialize(&room_state, serde_json::value::Serializer).unwrap();
        let expected = to_json_value(&json!(
            [
                200,
                {
                    "origin": "matrix.org",
                    "auth_chain": [],
                    "state": []
                }
            ]
        ))
        .unwrap();

        assert_eq!(serialized, expected);
    }

    #[test]
    fn test_too_short_array() {
        let json = json!([200]);
        let failed_room_state = deserialize(json);
        assert_eq!(
            failed_room_state.unwrap_err().to_string(),
            "invalid length 1, expected a two-element list in the response"
        );
    }

    #[test]
    fn test_not_an_array() {
        let json = json!({
            "origin": "matrix.org",
            "auth_chain": [],
            "state": []
        });
        let failed_room_state = deserialize(json);

        assert_eq!(
            failed_room_state.unwrap_err().to_string(),
            "invalid type: map, expected Room State response wrapped in an array.",
        )
    }

    #[test]
    fn test_too_long_array() {
        let json = json!([200, {"origin": "", "auth_chain": [], "state": []}, 200]);
        assert_matches!(
            deserialize(json).unwrap(),
            RoomState { origin, auth_chain, state }
            if origin == ""
              && auth_chain.is_empty()
              && state.is_empty()
        );
    }
}
<commit_msg>Rerun cargo fmt for ruma-federation-api<commit_after>//! A module to deserialize a RoomState struct from incorrectly specified v1
//! send_join endpoint.
//!
//! For more information, see this [GitHub issue](https://github.com/matrix-org/matrix-doc/issues/2541).

use std::fmt;

use serde::{
    de::{Deserializer, Error, IgnoredAny, SeqAccess, Visitor},
    ser::{SerializeSeq, Serializer},
};

use crate::membership::create_join_event::RoomState;

pub fn serialize<S>(room_state: &RoomState, serializer: S) -> Result<S::Ok, S::Error>
where
    S: Serializer,
{
    let mut seq = serializer.serialize_seq(Some(2))?;
    seq.serialize_element(&200)?;
    seq.serialize_element(room_state)?;
    seq.end()
}

pub fn deserialize<'de, D>(deserializer: D) -> Result<RoomState, D::Error>
where
    D: Deserializer<'de>,
{
    deserializer.deserialize_seq(RoomStateVisitor)
}

struct RoomStateVisitor;

impl<'de> Visitor<'de> for RoomStateVisitor {
    type Value = RoomState;
    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("Room State response wrapped in an array.")
    }

    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
    where
        A: SeqAccess<'de>,
    {
        let expected = "a two-element list in the response";
        if seq.next_element::<IgnoredAny>()?.is_none() {
            return Err(A::Error::invalid_length(0, &expected));
        }

        let room_state =
            seq.next_element()?.ok_or_else(|| A::Error::invalid_length(1, &expected))?;

        while let Some(IgnoredAny) = seq.next_element()? {
            // ignore extra elements
        }

        Ok(room_state)
    }
}

#[cfg(test)]
mod tests {
    use matches::assert_matches;
    use serde_json::{json, to_value as to_json_value};

    use super::{deserialize, serialize, RoomState};

    #[test]
    fn test_deserialize_response() {
        let response = json!([
            200,
            {
                "origin": "example.com",
                "auth_chain": [],
                "state": []
            }
        ]);

        let parsed = deserialize(response).unwrap();

        assert_matches!(
            parsed,
            RoomState { origin, auth_chain, state }
            if origin == "example.com"
                && auth_chain.is_empty()
                && state.is_empty()
        );
    }

    #[test]
    fn test_serialize_response() {
        let room_state = RoomState {
            origin: "matrix.org".to_string(),
            auth_chain: Vec::new(),
            state: Vec::new(),
        };

        let serialized = serialize(&room_state, serde_json::value::Serializer).unwrap();
        let expected = to_json_value(&json!(
            [
                200,
                {
                    "origin": "matrix.org",
                    "auth_chain": [],
                    "state": []
                }
            ]
        ))
        .unwrap();

        assert_eq!(serialized, expected);
    }

    #[test]
    fn test_too_short_array() {
        let json = json!([200]);
        let failed_room_state = deserialize(json);
        assert_eq!(
            failed_room_state.unwrap_err().to_string(),
            "invalid length 1, expected a two-element list in the response"
        );
    }

    #[test]
    fn test_not_an_array() {
        let json = json!({
            "origin": "matrix.org",
            "auth_chain": [],
            "state": []
        });
        let failed_room_state = deserialize(json);

        assert_eq!(
            failed_room_state.unwrap_err().to_string(),
            "invalid type: map, expected Room State response wrapped in an array.",
        )
    }

    #[test]
    fn test_too_long_array() {
        let json = json!([200, {"origin": "", "auth_chain": [], "state": []}, 200]);
        assert_matches!(
            deserialize(json).unwrap(),
            RoomState { origin, auth_chain, state }
            if origin == ""
              && auth_chain.is_empty()
              && state.is_empty()
        );
    }
}
<|endoftext|>


<commit_before>#[derive(Debug, PartialEq)]
pub enum ParserError {
    IllegalOperator(usize),
    MissingOpeningBracket(usize),
    MissingClosingBracket(usize),
}

#[derive(Debug, PartialEq)]
pub enum EvaluatorError {
    // RadixError(usize),
    // KeywordError(usize, String),
    UnknownIdentifier(usize, String),
    MissingArgument(usize),
}
<commit_msg>Comment out UnknownIdentifier error<commit_after>#[derive(Debug, PartialEq)]
pub enum ParserError {
    IllegalOperator(usize),
    MissingOpeningBracket(usize),
    MissingClosingBracket(usize),
}

#[derive(Debug, PartialEq)]
pub enum EvaluatorError {
    // RadixError(usize),
    // KeywordError(usize, String),
    // UnknownIdentifier(usize, String),
    MissingArgument(usize),
}
<|endoftext|>


<commit_before>use std::error;
use std::fmt;
use std::path::PathBuf;
use std::str;
use std::os::raw::c_int;
use {ffi, errmsg_to_string};
use types::Type;

/// Old name for `Error`. `SqliteError` is deprecated.
#[deprecated(since = "0.6.0", note = "Use Error instead")]
pub type SqliteError = Error;

/// Enum listing possible errors from rusqlite.
#[derive(Debug)]
#[allow(enum_variant_names)]
pub enum Error {
    /// An error from an underlying SQLite call.
    SqliteFailure(ffi::Error, Option<String>),

    /// Error reported when attempting to open a connection when SQLite was configured to
    /// allow single-threaded use only.
    SqliteSingleThreadedMode,

    /// Error when the value of a particular column is requested, but it cannot be converted to
    /// the requested Rust type.
    FromSqlConversionFailure(usize, Type, Box<error::Error + Send + Sync>),

    /// Error when SQLite gives us an integral value outside the range of the requested type (e.g.,
    /// trying to get the value 1000 into a `u8`).  The associated `c_int` is the column index, and
    /// the associated `i64` is the value returned by SQLite.
    IntegralValueOutOfRange(c_int, i64),

    /// Error converting a string to UTF-8.
    Utf8Error(str::Utf8Error),

    /// Error converting a string to a C-compatible string because it contained an embedded nul.
    NulError(::std::ffi::NulError),

    /// Error when using SQL named parameters and passing a parameter name not present in the SQL.
    InvalidParameterName(String),

    /// Error converting a file path to a string.
    InvalidPath(PathBuf),

    /// Error returned when an `execute` call returns rows.
    ExecuteReturnedResults,

    /// Error when a query that was expected to return at least one row (e.g., for `query_row`)
    /// did not return any.
    QueryReturnedNoRows,

    /// Error when the value of a particular column is requested, but the index is out of range
    /// for the statement.
    InvalidColumnIndex(c_int),

    /// Error when the value of a named column is requested, but no column matches the name
    /// for the statement.
    InvalidColumnName(String),

    /// Error when the value of a particular column is requested, but the type of the result in
    /// that column cannot be converted to the requested Rust type.
    InvalidColumnType(c_int, Type),

    /// Error when a query that was expected to insert one row did not insert any or insert many.
    StatementChangedRows(c_int),

    /// Error returned by `functions::Context::get` when the function argument cannot be converted
    /// to the requested type.
    #[cfg(feature = "functions")]
    InvalidFunctionParameterType(usize, Type),

    /// An error case available for implementors of custom user functions (e.g.,
    /// `create_scalar_function`).
    #[cfg(feature = "functions")]
    #[allow(dead_code)]
    UserFunctionError(Box<error::Error + Send + Sync>),
}

impl From<str::Utf8Error> for Error {
    fn from(err: str::Utf8Error) -> Error {
        Error::Utf8Error(err)
    }
}

impl From<::std::ffi::NulError> for Error {
    fn from(err: ::std::ffi::NulError) -> Error {
        Error::NulError(err)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::SqliteFailure(ref err, None) => err.fmt(f),
            Error::SqliteFailure(_, Some(ref s)) => write!(f, "{}", s),
            Error::SqliteSingleThreadedMode => {
                write!(f,
                       "SQLite was compiled or configured for single-threaded use only")
            }
            Error::FromSqlConversionFailure(i, ref t, ref err) => {
                write!(f,
                       "Conversion error from type {} at index: {}, {}",
                       t,
                       i,
                       err)
            }
            Error::IntegralValueOutOfRange(col, val) => {
                write!(f, "Integer {} out of range at index {}", val, col)
            }
            Error::Utf8Error(ref err) => err.fmt(f),
            Error::NulError(ref err) => err.fmt(f),
            Error::InvalidParameterName(ref name) => write!(f, "Invalid parameter name: {}", name),
            Error::InvalidPath(ref p) => write!(f, "Invalid path: {}", p.to_string_lossy()),
            Error::ExecuteReturnedResults => {
                write!(f, "Execute returned results - did you mean to call query?")
            }
            Error::QueryReturnedNoRows => write!(f, "Query returned no rows"),
            Error::InvalidColumnIndex(i) => write!(f, "Invalid column index: {}", i),
            Error::InvalidColumnName(ref name) => write!(f, "Invalid column name: {}", name),
            Error::InvalidColumnType(i, ref t) => {
                write!(f, "Invalid column type {} at index: {}", t, i)
            }
            Error::StatementChangedRows(i) => write!(f, "Query changed {} rows", i),

            #[cfg(feature = "functions")]
            Error::InvalidFunctionParameterType(i, ref t) => {
                write!(f, "Invalid function parameter type {} at index {}", t, i)
            }
            #[cfg(feature = "functions")]
            Error::UserFunctionError(ref err) => err.fmt(f),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::SqliteFailure(ref err, None) => err.description(),
            Error::SqliteFailure(_, Some(ref s)) => s,
            Error::SqliteSingleThreadedMode => {
                "SQLite was compiled or configured for single-threaded use only"
            }
            Error::FromSqlConversionFailure(_, _, ref err) => err.description(),
            Error::IntegralValueOutOfRange(_, _) => "integral value out of range of requested type",
            Error::Utf8Error(ref err) => err.description(),
            Error::InvalidParameterName(_) => "invalid parameter name",
            Error::NulError(ref err) => err.description(),
            Error::InvalidPath(_) => "invalid path",
            Error::ExecuteReturnedResults => {
                "execute returned results - did you mean to call query?"
            }
            Error::QueryReturnedNoRows => "query returned no rows",
            Error::InvalidColumnIndex(_) => "invalid column index",
            Error::InvalidColumnName(_) => "invalid column name",
            Error::InvalidColumnType(_, _) => "invalid column type",
            Error::StatementChangedRows(_) => "query inserted zero or more than one row",

            #[cfg(feature = "functions")]
            Error::InvalidFunctionParameterType(_, _) => "invalid function parameter type",
            #[cfg(feature = "functions")]
            Error::UserFunctionError(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::SqliteFailure(ref err, _) => Some(err),
            Error::FromSqlConversionFailure(_, _, ref err) => Some(&**err),
            Error::Utf8Error(ref err) => Some(err),
            Error::NulError(ref err) => Some(err),

            Error::IntegralValueOutOfRange(_, _) |
            Error::SqliteSingleThreadedMode |
            Error::InvalidParameterName(_) |
            Error::ExecuteReturnedResults |
            Error::QueryReturnedNoRows |
            Error::InvalidColumnIndex(_) |
            Error::InvalidColumnName(_) |
            Error::InvalidColumnType(_, _) |
            Error::InvalidPath(_) |
            Error::StatementChangedRows(_) => None,

            #[cfg(feature = "functions")]
            Error::InvalidFunctionParameterType(_, _) => None,

            #[cfg(feature = "functions")]
            Error::UserFunctionError(ref err) => Some(&**err),
        }
    }
}

// These are public but not re-exported by lib.rs, so only visible within crate.

pub fn error_from_sqlite_code(code: c_int, message: Option<String>) -> Error {
    Error::SqliteFailure(ffi::Error::new(code), message)
}

pub fn error_from_handle(db: *mut ffi::sqlite3, code: c_int) -> Error {
    let message = if db.is_null() {
        None
    } else {
        Some(unsafe { errmsg_to_string(ffi::sqlite3_errmsg(db)) })
    };
    error_from_sqlite_code(code, message)
}
<commit_msg>Add Other variant for the Error type<commit_after>use std::error;
use std::fmt;
use std::path::PathBuf;
use std::str;
use std::os::raw::c_int;
use {ffi, errmsg_to_string};
use types::Type;

/// Old name for `Error`. `SqliteError` is deprecated.
#[deprecated(since = "0.6.0", note = "Use Error instead")]
pub type SqliteError = Error;

/// Enum listing possible errors from rusqlite.
#[derive(Debug)]
#[allow(enum_variant_names)]
pub enum Error {
    /// An error from an underlying SQLite call.
    SqliteFailure(ffi::Error, Option<String>),

    /// Error reported when attempting to open a connection when SQLite was configured to
    /// allow single-threaded use only.
    SqliteSingleThreadedMode,

    /// Error when the value of a particular column is requested, but it cannot be converted to
    /// the requested Rust type.
    FromSqlConversionFailure(usize, Type, Box<error::Error + Send + Sync>),

    /// Error when SQLite gives us an integral value outside the range of the requested type (e.g.,
    /// trying to get the value 1000 into a `u8`).  The associated `c_int` is the column index, and
    /// the associated `i64` is the value returned by SQLite.
    IntegralValueOutOfRange(c_int, i64),

    /// Error converting a string to UTF-8.
    Utf8Error(str::Utf8Error),

    /// Error converting a string to a C-compatible string because it contained an embedded nul.
    NulError(::std::ffi::NulError),

    /// Error when using SQL named parameters and passing a parameter name not present in the SQL.
    InvalidParameterName(String),

    /// Error converting a file path to a string.
    InvalidPath(PathBuf),

    /// Error returned when an `execute` call returns rows.
    ExecuteReturnedResults,

    /// Error when a query that was expected to return at least one row (e.g., for `query_row`)
    /// did not return any.
    QueryReturnedNoRows,

    /// Error when the value of a particular column is requested, but the index is out of range
    /// for the statement.
    InvalidColumnIndex(c_int),

    /// Error when the value of a named column is requested, but no column matches the name
    /// for the statement.
    InvalidColumnName(String),

    /// Error when the value of a particular column is requested, but the type of the result in
    /// that column cannot be converted to the requested Rust type.
    InvalidColumnType(c_int, Type),

    /// Error when a query that was expected to insert one row did not insert any or insert many.
    StatementChangedRows(c_int),

    /// Error returned by `functions::Context::get` when the function argument cannot be converted
    /// to the requested type.
    #[cfg(feature = "functions")]
    InvalidFunctionParameterType(usize, Type),

    /// An error case available for implementors of custom user functions (e.g.,
    /// `create_scalar_function`).
    #[cfg(feature = "functions")]
    #[allow(dead_code)]
    UserFunctionError(Box<error::Error + Send + Sync>),

    /// Error available for the implementors of the `FromSql` trait.
    Other(Box<error::Error + Send + Sync>),
}

impl From<str::Utf8Error> for Error {
    fn from(err: str::Utf8Error) -> Error {
        Error::Utf8Error(err)
    }
}

impl From<::std::ffi::NulError> for Error {
    fn from(err: ::std::ffi::NulError) -> Error {
        Error::NulError(err)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::SqliteFailure(ref err, None) => err.fmt(f),
            Error::SqliteFailure(_, Some(ref s)) => write!(f, "{}", s),
            Error::SqliteSingleThreadedMode => {
                write!(f,
                       "SQLite was compiled or configured for single-threaded use only")
            }
            Error::FromSqlConversionFailure(i, ref t, ref err) => {
                write!(f,
                       "Conversion error from type {} at index: {}, {}",
                       t,
                       i,
                       err)
            }
            Error::IntegralValueOutOfRange(col, val) => {
                write!(f, "Integer {} out of range at index {}", val, col)
            }
            Error::Utf8Error(ref err) => err.fmt(f),
            Error::NulError(ref err) => err.fmt(f),
            Error::InvalidParameterName(ref name) => write!(f, "Invalid parameter name: {}", name),
            Error::InvalidPath(ref p) => write!(f, "Invalid path: {}", p.to_string_lossy()),
            Error::ExecuteReturnedResults => {
                write!(f, "Execute returned results - did you mean to call query?")
            }
            Error::QueryReturnedNoRows => write!(f, "Query returned no rows"),
            Error::InvalidColumnIndex(i) => write!(f, "Invalid column index: {}", i),
            Error::InvalidColumnName(ref name) => write!(f, "Invalid column name: {}", name),
            Error::InvalidColumnType(i, ref t) => {
                write!(f, "Invalid column type {} at index: {}", t, i)
            }
            Error::StatementChangedRows(i) => write!(f, "Query changed {} rows", i),

            #[cfg(feature = "functions")]
            Error::InvalidFunctionParameterType(i, ref t) => {
                write!(f, "Invalid function parameter type {} at index {}", t, i)
            }
            #[cfg(feature = "functions")]
            Error::UserFunctionError(ref err) => err.fmt(f),
            Error::Other(ref err) => err.fmt(f),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::SqliteFailure(ref err, None) => err.description(),
            Error::SqliteFailure(_, Some(ref s)) => s,
            Error::SqliteSingleThreadedMode => {
                "SQLite was compiled or configured for single-threaded use only"
            }
            Error::FromSqlConversionFailure(_, _, ref err) => err.description(),
            Error::IntegralValueOutOfRange(_, _) => "integral value out of range of requested type",
            Error::Utf8Error(ref err) => err.description(),
            Error::InvalidParameterName(_) => "invalid parameter name",
            Error::NulError(ref err) => err.description(),
            Error::InvalidPath(_) => "invalid path",
            Error::ExecuteReturnedResults => {
                "execute returned results - did you mean to call query?"
            }
            Error::QueryReturnedNoRows => "query returned no rows",
            Error::InvalidColumnIndex(_) => "invalid column index",
            Error::InvalidColumnName(_) => "invalid column name",
            Error::InvalidColumnType(_, _) => "invalid column type",
            Error::StatementChangedRows(_) => "query inserted zero or more than one row",

            #[cfg(feature = "functions")]
            Error::InvalidFunctionParameterType(_, _) => "invalid function parameter type",
            #[cfg(feature = "functions")]
            Error::UserFunctionError(ref err) => err.description(),
            Error::Other(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::SqliteFailure(ref err, _) => Some(err),
            Error::FromSqlConversionFailure(_, _, ref err) => Some(&**err),
            Error::Utf8Error(ref err) => Some(err),
            Error::NulError(ref err) => Some(err),

            Error::IntegralValueOutOfRange(_, _) |
            Error::SqliteSingleThreadedMode |
            Error::InvalidParameterName(_) |
            Error::ExecuteReturnedResults |
            Error::QueryReturnedNoRows |
            Error::InvalidColumnIndex(_) |
            Error::InvalidColumnName(_) |
            Error::InvalidColumnType(_, _) |
            Error::InvalidPath(_) |
            Error::StatementChangedRows(_) => None,

            #[cfg(feature = "functions")]
            Error::InvalidFunctionParameterType(_, _) => None,

            #[cfg(feature = "functions")]
            Error::UserFunctionError(ref err) => Some(&**err),
            Error::Other(ref err) => Some(&**err),
        }
    }
}

// These are public but not re-exported by lib.rs, so only visible within crate.

pub fn error_from_sqlite_code(code: c_int, message: Option<String>) -> Error {
    Error::SqliteFailure(ffi::Error::new(code), message)
}

pub fn error_from_handle(db: *mut ffi::sqlite3, code: c_int) -> Error {
    let message = if db.is_null() {
        None
    } else {
        Some(unsafe { errmsg_to_string(ffi::sqlite3_errmsg(db)) })
    };
    error_from_sqlite_code(code, message)
}
<|endoftext|>


<commit_before>//! Process window events
use std::borrow::Cow;
use std::fs::File;
use std::io::Write;
use std::sync::mpsc;

use serde_json as json;
use parking_lot::MutexGuard;
use glutin::{self, ElementState};

use config::Config;
use display::OnResize;
use index::{Line, Column, Side};
use input::{self, ActionContext, MouseBinding, KeyBinding};
use selection::Selection;
use sync::FairMutex;
use term::{Term, SizeInfo};
use util::limit;
use window::Window;

/// Byte sequences are sent to a `Notify` in response to some events
pub trait Notify {
    /// Notify that an escape sequence should be written to the pty
    ///
    /// TODO this needs to be able to error somehow
    fn notify<B: Into<Cow<'static, [u8]>>>(&mut self, B);
}

/// State of the mouse
pub struct Mouse {
    pub x: u32,
    pub y: u32,
    pub left_button_state: ElementState,
    pub scroll_px: i32,
    pub line: Line,
    pub column: Column,
    pub cell_side: Side
}

impl Default for Mouse {
    fn default() -> Mouse {
        Mouse {
            x: 0,
            y: 0,
            left_button_state: ElementState::Released,
            scroll_px: 0,
            line: Line(0),
            column: Column(0),
            cell_side: Side::Left,
        }
    }
}

/// The event processor
///
/// Stores some state from received events and dispatches actions when they are
/// triggered.
pub struct Processor<N> {
    key_bindings: Vec<KeyBinding>,
    mouse_bindings: Vec<MouseBinding>,
    notifier: N,
    mouse: Mouse,
    resize_tx: mpsc::Sender<(u32, u32)>,
    ref_test: bool,
    size_info: SizeInfo,
    pub selection: Selection,
}

/// Notify that the terminal was resized
///
/// Currently this just forwards the notice to the input processor.
impl<N> OnResize for Processor<N> {
    fn on_resize(&mut self, size: &SizeInfo) {
        self.size_info = size.to_owned();
    }
}

impl<N: Notify> Processor<N> {
    /// Create a new event processor
    ///
    /// Takes a writer which is expected to be hooked up to the write end of a
    /// pty.
    pub fn new(
        notifier: N,
        resize_tx: mpsc::Sender<(u32, u32)>,
        config: &Config,
        ref_test: bool,
        size_info: SizeInfo,
    ) -> Processor<N> {
        Processor {
            key_bindings: config.key_bindings().to_vec(),
            mouse_bindings: config.mouse_bindings().to_vec(),
            notifier: notifier,
            resize_tx: resize_tx,
            ref_test: ref_test,
            mouse: Default::default(),
            selection: Default::default(),
            size_info: size_info,
        }
    }

    /// Handle events from glutin
    ///
    /// Doesn't take self mutably due to borrow checking. Kinda uggo but w/e.
    fn handle_event<'a>(
        processor: &mut input::Processor<'a, N>,
        event: glutin::Event,
        ref_test: bool,
        resize_tx: &mpsc::Sender<(u32, u32)>,
    ) {
        match event {
            glutin::Event::Closed => {
                if ref_test {
                    // dump grid state
                    let grid = processor.ctx.terminal.grid();

                    let serialized_grid = json::to_string(&grid)
                        .expect("serialize grid");

                    let serialized_size = json::to_string(processor.ctx.terminal.size_info())
                        .expect("serialize size");

                    File::create("./grid.json")
                        .and_then(|mut f| f.write_all(serialized_grid.as_bytes()))
                        .expect("write grid.json");

                    File::create("./size.json")
                        .and_then(|mut f| f.write_all(serialized_size.as_bytes()))
                        .expect("write size.json");
                }

                // FIXME
                panic!("window closed");
            },
            glutin::Event::Resized(w, h) => {
                resize_tx.send((w, h)).expect("send new size");
                processor.ctx.terminal.dirty = true;
            },
            glutin::Event::KeyboardInput(state, _code, key, mods, string) => {
                processor.process_key(state, key, mods, string);
            },
            glutin::Event::MouseInput(state, button) => {
                processor.mouse_input(state, button);
                processor.ctx.terminal.dirty = true;
            },
            glutin::Event::MouseMoved(x, y) => {
                let x = limit(x, 0, processor.ctx.size_info.width as i32);
                let y = limit(y, 0, processor.ctx.size_info.height as i32);

                processor.mouse_moved(x as u32, y as u32);

                if !processor.ctx.selection.is_empty() {
                    processor.ctx.terminal.dirty = true;
                }
            },
            glutin::Event::Focused(true) => {
                processor.ctx.terminal.dirty = true;
            },
            glutin::Event::MouseWheel(scroll_delta, touch_phase) => {
                processor.on_mouse_wheel(scroll_delta, touch_phase);
            },
            glutin::Event::Awakened => {
                processor.ctx.terminal.dirty = true;
            },
            _ => (),
        }
    }

    /// Process at least one event and handle any additional queued events.
    pub fn process_events<'a>(
        &mut self,
        term: &'a FairMutex<Term>,
        window: &Window
    ) -> MutexGuard<'a, Term> {
        // Terminal is lazily initialized the first time an event is returned
        // from the blocking WaitEventsIterator. Otherwise, the pty reader would
        // be blocked the entire time we wait for input!
        let mut terminal;

        {
            // Ditto on lazy initialization for context and processor.
            let context;
            let mut processor: input::Processor<N>;

            // Convenience macro which curries most arguments to handle_event.
            macro_rules! process {
                ($event:expr) => {
                    Processor::handle_event(
                        &mut processor,
                        $event,
                        self.ref_test,
                        &self.resize_tx,
                    )
                }
            }

            match window.wait_events().next() {
                Some(event) => {
                    terminal = term.lock();
                    context = ActionContext {
                        terminal: &mut terminal,
                        notifier: &mut self.notifier,
                        selection: &mut self.selection,
                        mouse: &mut self.mouse,
                        size_info: &self.size_info,
                    };

                    processor = input::Processor {
                        ctx: context,
                        key_bindings: &self.key_bindings[..],
                        mouse_bindings: &self.mouse_bindings[..]
                    };

                    process!(event);
                },
                // Glutin guarantees the WaitEventsIterator never returns None.
                None => unreachable!(),
            }

            for event in window.poll_events() {
                process!(event);
            }
        }

        terminal
    }

    pub fn update_config(&mut self, config: &Config) {
        self.key_bindings = config.key_bindings().to_vec();
        self.mouse_bindings = config.mouse_bindings().to_vec();
    }
}
<commit_msg>Draw the screen when Refresh event arrives<commit_after>//! Process window events
use std::borrow::Cow;
use std::fs::File;
use std::io::Write;
use std::sync::mpsc;

use serde_json as json;
use parking_lot::MutexGuard;
use glutin::{self, ElementState};

use config::Config;
use display::OnResize;
use index::{Line, Column, Side};
use input::{self, ActionContext, MouseBinding, KeyBinding};
use selection::Selection;
use sync::FairMutex;
use term::{Term, SizeInfo};
use util::limit;
use window::Window;

/// Byte sequences are sent to a `Notify` in response to some events
pub trait Notify {
    /// Notify that an escape sequence should be written to the pty
    ///
    /// TODO this needs to be able to error somehow
    fn notify<B: Into<Cow<'static, [u8]>>>(&mut self, B);
}

/// State of the mouse
pub struct Mouse {
    pub x: u32,
    pub y: u32,
    pub left_button_state: ElementState,
    pub scroll_px: i32,
    pub line: Line,
    pub column: Column,
    pub cell_side: Side
}

impl Default for Mouse {
    fn default() -> Mouse {
        Mouse {
            x: 0,
            y: 0,
            left_button_state: ElementState::Released,
            scroll_px: 0,
            line: Line(0),
            column: Column(0),
            cell_side: Side::Left,
        }
    }
}

/// The event processor
///
/// Stores some state from received events and dispatches actions when they are
/// triggered.
pub struct Processor<N> {
    key_bindings: Vec<KeyBinding>,
    mouse_bindings: Vec<MouseBinding>,
    notifier: N,
    mouse: Mouse,
    resize_tx: mpsc::Sender<(u32, u32)>,
    ref_test: bool,
    size_info: SizeInfo,
    pub selection: Selection,
}

/// Notify that the terminal was resized
///
/// Currently this just forwards the notice to the input processor.
impl<N> OnResize for Processor<N> {
    fn on_resize(&mut self, size: &SizeInfo) {
        self.size_info = size.to_owned();
    }
}

impl<N: Notify> Processor<N> {
    /// Create a new event processor
    ///
    /// Takes a writer which is expected to be hooked up to the write end of a
    /// pty.
    pub fn new(
        notifier: N,
        resize_tx: mpsc::Sender<(u32, u32)>,
        config: &Config,
        ref_test: bool,
        size_info: SizeInfo,
    ) -> Processor<N> {
        Processor {
            key_bindings: config.key_bindings().to_vec(),
            mouse_bindings: config.mouse_bindings().to_vec(),
            notifier: notifier,
            resize_tx: resize_tx,
            ref_test: ref_test,
            mouse: Default::default(),
            selection: Default::default(),
            size_info: size_info,
        }
    }

    /// Handle events from glutin
    ///
    /// Doesn't take self mutably due to borrow checking. Kinda uggo but w/e.
    fn handle_event<'a>(
        processor: &mut input::Processor<'a, N>,
        event: glutin::Event,
        ref_test: bool,
        resize_tx: &mpsc::Sender<(u32, u32)>,
    ) {
        match event {
            glutin::Event::Closed => {
                if ref_test {
                    // dump grid state
                    let grid = processor.ctx.terminal.grid();

                    let serialized_grid = json::to_string(&grid)
                        .expect("serialize grid");

                    let serialized_size = json::to_string(processor.ctx.terminal.size_info())
                        .expect("serialize size");

                    File::create("./grid.json")
                        .and_then(|mut f| f.write_all(serialized_grid.as_bytes()))
                        .expect("write grid.json");

                    File::create("./size.json")
                        .and_then(|mut f| f.write_all(serialized_size.as_bytes()))
                        .expect("write size.json");
                }

                // FIXME
                panic!("window closed");
            },
            glutin::Event::Resized(w, h) => {
                resize_tx.send((w, h)).expect("send new size");
                processor.ctx.terminal.dirty = true;
            },
            glutin::Event::KeyboardInput(state, _code, key, mods, string) => {
                processor.process_key(state, key, mods, string);
            },
            glutin::Event::MouseInput(state, button) => {
                processor.mouse_input(state, button);
                processor.ctx.terminal.dirty = true;
            },
            glutin::Event::MouseMoved(x, y) => {
                let x = limit(x, 0, processor.ctx.size_info.width as i32);
                let y = limit(y, 0, processor.ctx.size_info.height as i32);

                processor.mouse_moved(x as u32, y as u32);

                if !processor.ctx.selection.is_empty() {
                    processor.ctx.terminal.dirty = true;
                }
            },
            glutin::Event::Focused(true) => {
                processor.ctx.terminal.dirty = true;
            },
            glutin::Event::MouseWheel(scroll_delta, touch_phase) => {
                processor.on_mouse_wheel(scroll_delta, touch_phase);
            },
            glutin::Event::Refresh |
            glutin::Event::Awakened => {
                processor.ctx.terminal.dirty = true;
            },
            _ => (),
        }
    }

    /// Process at least one event and handle any additional queued events.
    pub fn process_events<'a>(
        &mut self,
        term: &'a FairMutex<Term>,
        window: &Window
    ) -> MutexGuard<'a, Term> {
        // Terminal is lazily initialized the first time an event is returned
        // from the blocking WaitEventsIterator. Otherwise, the pty reader would
        // be blocked the entire time we wait for input!
        let mut terminal;

        {
            // Ditto on lazy initialization for context and processor.
            let context;
            let mut processor: input::Processor<N>;

            // Convenience macro which curries most arguments to handle_event.
            macro_rules! process {
                ($event:expr) => {
                    Processor::handle_event(
                        &mut processor,
                        $event,
                        self.ref_test,
                        &self.resize_tx,
                    )
                }
            }

            match window.wait_events().next() {
                Some(event) => {
                    terminal = term.lock();
                    context = ActionContext {
                        terminal: &mut terminal,
                        notifier: &mut self.notifier,
                        selection: &mut self.selection,
                        mouse: &mut self.mouse,
                        size_info: &self.size_info,
                    };

                    processor = input::Processor {
                        ctx: context,
                        key_bindings: &self.key_bindings[..],
                        mouse_bindings: &self.mouse_bindings[..]
                    };

                    process!(event);
                },
                // Glutin guarantees the WaitEventsIterator never returns None.
                None => unreachable!(),
            }

            for event in window.poll_events() {
                process!(event);
            }
        }

        terminal
    }

    pub fn update_config(&mut self, config: &Config) {
        self.key_bindings = config.key_bindings().to_vec();
        self.mouse_bindings = config.mouse_bindings().to_vec();
    }
}
<|endoftext|>