<commit_before>use std::collections::hash_map::Entry::{Occupied, Vacant};

use std::collections::HashMap;
use std::error::Error;
use std::fmt;
use std::iter;

// use failure::{err_msg, Error};
use ggez::nalgebra::{Point2, Vector2};
use ggez::{graphics, timer, Context, GameResult};
use ggez_goodies::scene::{Scene, SceneSwitch};
use serde_derive::{Deserialize, Serialize};
use specs::world::{Builder, Index};
use specs::{Dispatcher, DispatcherBuilder, EntityBuilder, Join, World, WorldExt};
use warmy::load::Load;
use warmy::{Res, SimpleKey, Store, StoreErrorOr};
// use warmy::ron::Ron;

use loadable_yaml_macro_derive::LoadableYaml;

use crate::animation::Image as SpriteImage;
use crate::animation::{Frame, Sprite};
// TODO: move these components to common module out of combat
use crate::campaign::components::{HitBox, MapIntent, OnHoverImage, TimeSpentOnTerrain};
use crate::campaign::movement_cost::CampaignMap;
use crate::campaign::systems::map_boundary::Boundary;
use crate::campaign::systems::{
    HighlightOnHover, HighlightPlayer, MapCommander, RestrictMovementToMapBoundary, SetMapVelocity,
    TerrainCost,
};
use crate::combat::components::{Controller, Draw, Facing, Palette, Position, Velocity};
use crate::combat::systems::Movement;
use crate::components::RenderOrder;
use crate::error::{LoadError, MoonstoneError};
use crate::game::{Game, SceneState};
use crate::input;
use crate::input::{Axis, Button, InputEvent};
use crate::objects::TextureAtlas;
use crate::piv::{extract_palette, palette_swap, Colour, ColourOscillate, PivImage};
// use crate::ron::GameRon;
use crate::ron::{FromRon, GameRon};
use crate::scenes::world::draw_entities;
use crate::scenes::FSceneSwitch;
use crate::text::Image;

const MAP_ANIMATION_SPEED: u32 = 12;

pub struct FlashingPalettes {
    pub palettes: Vec<Vec<Colour>>,
}

#[derive(Debug, Default, Clone, Serialize, Deserialize, LoadableYaml)]
pub struct MapData {
    pub background: String,
    pub lairs: Vec<Image>,
    pub images: HashMap<String, Image>,
}

impl fmt::Display for MapData {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "MapData {}", self.background)
    }
}

#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
pub enum LocationKind {
    Lair,
    Village,
    City,
    Stonehenge,
    Valley,
    WizardTower,
}

impl Default for LocationKind {
    fn default() -> Self {
        LocationKind::Lair
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Location {
    pub kind: LocationKind,
    pub image: Option<SpriteImage>,
    pub hover_image: Option<SpriteImage>,
    pub x: i32,
    pub y: i32,
    pub player: Option<u32>,
    pub name: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Locations {
    pub locations: Vec<Location>,
}

pub struct MapScene<'a> {
    pub specs_world: World,
    pub dispatcher: Dispatcher<'a, 'a>,

    map_data: MapData,
    pub background: Vec<graphics::Image>,
    background_frame: u32,
    current_background_image: usize,

    pub palette: Vec<Colour>,
}

impl<'a> MapScene<'a> {
    fn build_world() -> World {
        let mut world = World::new();
        world.register::<Draw>();
        world.register::<HitBox>();
        world.register::<OnHoverImage>();
        world.register::<Palette>();
        world.register::<Position>();
        world.register::<RenderOrder>();
        world.register::<Velocity>();
        world.register::<Controller>();
        world.register::<MapIntent>();
        world.register::<TimeSpentOnTerrain>();
        world
    }

    fn build_dispatcher() -> Dispatcher<'a, 'a> {
        DispatcherBuilder::new()
            .with(MapCommander, "map_commander", &[])
            .with(TerrainCost, "terrain_cost", &["map_commander"])
            .with(SetMapVelocity, "velocity", &["terrain_cost"])
            .with(
                RestrictMovementToMapBoundary,
                "restrict_movement",
                &["velocity"],
            )
            .with(Movement, "movement", &["restrict_movement"])
            .with(HighlightOnHover, "highlight_on_hover", &["movement"])
            .with(HighlightPlayer, "highlight_player", &[])
            .build()
    }

    fn setup_background_map(
        ctx: &mut Context,
        store: &mut Store<Context, SimpleKey>,
        background_name: &str,
    ) -> Result<Vec<graphics::Image>, MoonstoneError> {
        let piv_res = store.get::<PivImage>(&SimpleKey::from(background_name), ctx)?;
        let mut background: Vec<graphics::Image> = Vec::new();
        let mut piv = piv_res.borrow_mut();
        background.push(graphics::Image::from_rgba8(
            ctx,
            512,
            512,
            &piv.to_rgba8_512(),
        )?);

        piv.palette[21..24].rotate_right(1);
        background.push(graphics::Image::from_rgba8(
            ctx,
            512,
            512,
            &piv.to_rgba8_512(),
        )?);

        piv.palette[21..24].rotate_right(1);
        background.push(graphics::Image::from_rgba8(
            ctx,
            512,
            512,
            &piv.to_rgba8_512(),
        )?);

        piv.palette[21..24].rotate_right(1);
        Ok(background)
    }

    fn build_knight_entity(
        ctx: &mut Context,
        store: &mut Store<Context, SimpleKey>,
        world: &'a mut World,
        background_name: &str,
    ) -> Result<(), MoonstoneError> {
        let piv_res = store
            .get::<PivImage>(&SimpleKey::from(background_name), ctx)
            .unwrap();
        let piv = piv_res.borrow();

        let atlas = store.get::<TextureAtlas>(&SimpleKey::from("mi.c"), ctx)?;
        // the first image in mi.c is the blue knight head.
        let knight_rect = atlas.borrow().rects[0];
        let knight_width = atlas.borrow().visible_widths[0];

        let sprite_res = store.get::<Sprite>(&SimpleKey::from(format!("/{}.yaml", "mi")), ctx)?;
        let sprite = sprite_res.borrow();
        let entity_builder = world
            .create_entity()
            .with(Position { x: 10, y: 10 })
            .with(Velocity {
                ..Default::default()
            })
            .with(Draw {
                frame: sprite.animations["blue_knight"].frames[0].clone(),
                animation: "blue_knight".to_string(),
                resource_name: "mi".to_string(),
                direction: Facing::default(),
            })
            .with(Palette {
                name: "0".to_string(),
                palette: piv.palette.clone(),
            })
            .with(HitBox {
                w: knight_width,
                h: knight_rect.h,
            })
            .with(Controller {
                x_axis: Axis::Horz1,
                y_axis: Axis::Vert1,
                button: Button::Fire1,
                ..Default::default()
            })
            .with(RenderOrder { depth: 1 })
            .with(MapIntent {
                ..Default::default()
            })
            .with(TimeSpentOnTerrain {
                ..Default::default()
            })
            .build();
        Ok(())
    }

    fn build_locations(
        ctx: &mut Context,
        store: &mut Store<Context, SimpleKey>,
        world: &'a mut World,
        background_name: &str,
    ) -> Result<(), MoonstoneError> {
        let locations_res = store.get_by::<GameRon<Locations>, FromRon>(
            &SimpleKey::from("/locations.ron"),
            ctx,
            FromRon,
        )?;
        let piv_res = store
            .get::<PivImage>(&SimpleKey::from(background_name), ctx)
            .unwrap();
        let piv = piv_res.borrow();

        let atlas = store.get::<TextureAtlas>(&SimpleKey::from("mi.c"), ctx)?;
        for l in locations_res.borrow().0.locations.iter() {
            let sprite_res =
                store.get::<Sprite>(&SimpleKey::from(format!("/{}.yaml", "mi")), ctx)?;
            let sprite = sprite_res.borrow();

            let mut entity_builder = world
                .create_entity()
                .with(Position { x: l.x, y: l.y })
                .with(Palette {
                    name: "0".to_string(),
                    palette: piv.palette.clone(),
                })
                .with(RenderOrder { depth: 0 })
                .with(OnHoverImage {
                    image: l.image.clone(),
                    hover: l.hover_image.clone(),
                })
                .with(Draw {
                    frame: Frame { images: vec![] },
                    animation: "".to_string(),
                    resource_name: "mi".to_string(),
                    direction: Facing::default(),
                });

            if let Some(i) = l.image.as_ref().or(l.hover_image.as_ref()) {
                let rect = atlas.borrow().rects[i.image];
                let width = atlas.borrow().visible_widths[i.image];
                entity_builder = entity_builder.with(HitBox {
                    w: width,
                    h: rect.h,
                })
            }

            entity_builder.build();
        }
        Ok(())
    }

    pub fn new(
        ctx: &mut Context,
        store: &mut Store<Context, SimpleKey>,
        background_name: &str,
    ) -> Result<Self, MoonstoneError> {
        let map_data = store
            .get::<MapData>(&warmy::SimpleKey::from("/map.yaml"), ctx)?
            .borrow()
            .clone();
        let background = MapScene::setup_background_map(ctx, store, &map_data.background)?;

        let mut specs_world = Self::build_world();
        specs_world.insert(Boundary {
            x: 0,
            y: 0,
            w: 310,
            h: 190,
        });

        MapScene::build_knight_entity(ctx, store, &mut specs_world, &map_data.background);
        let piv_res = store.get::<PivImage>(&SimpleKey::from(map_data.background.clone()), ctx)?;
        let piv = piv_res.borrow();

        let campaign_map_res = store.get_by::<GameRon<CampaignMap>, FromRon>(
            &SimpleKey::from("/campaign_map.ron"),
            ctx,
            FromRon,
        )?;
        specs_world.insert(campaign_map_res.borrow().0.clone());

        let mut swap_colour = extract_palette(&[0xff]).first().unwrap().clone();
        swap_colour.a = 255;
        let mut oscillate = ColourOscillate::new(piv.palette[31], swap_colour);
        let mut colours = (0..30)
            .map(|_| oscillate.next().unwrap())
            .collect::<Vec<_>>();
        colours.insert(0, piv.palette[31].clone());

        let mut palettes = Vec::new();
        for c in &colours {
            let mut p = piv.palette.clone();
            p[31] = c.clone();
            palettes.push(p);
        }
        specs_world.insert(FlashingPalettes { palettes });
        MapScene::build_locations(ctx, store, &mut specs_world, &map_data.background)?;

        Ok(Self {
            specs_world: specs_world,
            dispatcher: Self::build_dispatcher(),
            map_data,
            background,
            background_frame: 0,
            current_background_image: 0,
            palette: piv.palette.to_vec(),
        })
    }

    fn draw_background_map(&mut self, game: &mut Game, ctx: &mut Context) -> GameResult<()> {
        // let draw_params = graphics::DrawParam::default().scale(game.screen_scale);
        graphics::draw(
            ctx,
            &self.background[self.current_background_image],
            // draw_params,
            graphics::DrawParam::default(),
        )?;
        Ok(())
    }

    fn update_controllers(&mut self, input: &input::InputState) {
        let entities = self.specs_world.entities();
        let mut controllers = self.specs_world.write_storage::<Controller>();
        for (e, controller) in (&*entities, &mut controllers).join() {
            controller.x = input.get_axis_raw(controller.x_axis) as i32;
            controller.y = input.get_axis_raw(controller.y_axis) as i32;
            controller.fire = input.get_button_down(controller.button);
        }
    }
}

impl<'a> Scene<Game, InputEvent> for MapScene<'a> {
    fn update(&mut self, game: &mut Game, _ctx: &mut Context) -> FSceneSwitch {
        self.update_controllers(&game.input);
        self.dispatcher.dispatch_par(&self.specs_world);
        self.specs_world.maintain();
        self.background_frame += 1;
        if self.background_frame == MAP_ANIMATION_SPEED {
            self.current_background_image += 1;
            self.current_background_image %= self.background.len();
        }
        self.background_frame %= MAP_ANIMATION_SPEED;
        SceneSwitch::None
    }

    fn draw(&mut self, game: &mut Game, ctx: &mut Context) -> GameResult<()> {
        // since some of the campaign map is transparent, a sprite passing over
        // the transparent area would "colour in" that area, leaving behind the
        // ghost image of the sprite on those pixels, we clear the screen each
        // frame to get rid of these artifacts.
        graphics::clear(ctx, graphics::Color::new(0.0, 0.0, 0.0, 1.0));
        self.draw_background_map(game, ctx);
        draw_entities(&self.specs_world, &self.palette, None, game, ctx);
        Ok(())
    }

    fn name(&self) -> &str {
        "Map"
    }

    fn input(&mut self, gameworld: &mut Game, event: InputEvent, started: bool) {
        // let entities = self.specs_world.entities();
        // let mut controllers = self.specs_world.write_storage::<Controller>();
        // for (e, controller) in (&*entities, &mut controllers).join() {
        //     let x = gameworld.input.get_axis_raw(controller.x_axis);
        //     controller.x = gameworld.input.get_axis_raw(controller.x_axis) as i32;
        //     controller.y = gameworld.input.get_axis_raw(controller.y_axis) as i32;
        //     controller.fire = gameworld.input.get_button_down(controller.button);
        //     // println!("input {:?}", controller);
        // }
    }
}
<commit_msg>minor refactor<commit_after>use std::collections::hash_map::Entry::{Occupied, Vacant};

use std::collections::HashMap;
use std::error::Error;
use std::fmt;
use std::iter;

// use failure::{err_msg, Error};
use ggez::nalgebra::{Point2, Vector2};
use ggez::{graphics, timer, Context, GameResult};
use ggez_goodies::scene::{Scene, SceneSwitch};
use serde_derive::{Deserialize, Serialize};
use specs::world::{Builder, Index};
use specs::{Dispatcher, DispatcherBuilder, EntityBuilder, Join, World, WorldExt};
use warmy::load::Load;
use warmy::{Res, SimpleKey, Store, StoreErrorOr};
// use warmy::ron::Ron;

use loadable_yaml_macro_derive::LoadableYaml;

use crate::animation::Image as SpriteImage;
use crate::animation::{Frame, Sprite};
// TODO: move these components to common module out of combat
use crate::campaign::components::{HitBox, MapIntent, OnHoverImage, TimeSpentOnTerrain};
use crate::campaign::movement_cost::CampaignMap;
use crate::campaign::systems::map_boundary::Boundary;
use crate::campaign::systems::{
    HighlightOnHover, HighlightPlayer, MapCommander, RestrictMovementToMapBoundary, SetMapVelocity,
    TerrainCost,
};
use crate::combat::components::{Controller, Draw, Facing, Palette, Position, Velocity};
use crate::combat::systems::Movement;
use crate::components::RenderOrder;
use crate::error::{LoadError, MoonstoneError};
use crate::game::{Game, SceneState};
use crate::input;
use crate::input::{Axis, Button, InputEvent};
use crate::objects::TextureAtlas;
use crate::piv::{extract_palette, palette_swap, Colour, ColourOscillate, PivImage};
// use crate::ron::GameRon;
use crate::ron::{FromRon, GameRon};
use crate::scenes::world::draw_entities;
use crate::scenes::FSceneSwitch;
use crate::text::Image;

const MAP_ANIMATION_SPEED: u32 = 12;

pub struct FlashingPalettes {
    pub palettes: Vec<Vec<Colour>>,
}

#[derive(Debug, Default, Clone, Serialize, Deserialize, LoadableYaml)]
pub struct MapData {
    pub background: String,
    pub lairs: Vec<Image>,
    pub images: HashMap<String, Image>,
}

impl fmt::Display for MapData {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "MapData {}", self.background)
    }
}

#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
pub enum LocationKind {
    Lair,
    Village,
    City,
    Stonehenge,
    Valley,
    WizardTower,
}

impl Default for LocationKind {
    fn default() -> Self {
        LocationKind::Lair
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Location {
    pub kind: LocationKind,
    pub image: Option<SpriteImage>,
    pub hover_image: Option<SpriteImage>,
    pub x: i32,
    pub y: i32,
    pub player: Option<u32>,
    pub name: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Locations {
    pub locations: Vec<Location>,
}

pub struct MapScene<'a> {
    pub specs_world: World,
    pub dispatcher: Dispatcher<'a, 'a>,

    // map_data: MapData,
    pub background: Vec<graphics::Image>,
    background_frame: u32,
    current_background_image: usize,

    pub palette: Vec<Colour>,
}

impl<'a> MapScene<'a> {
    fn build_world() -> World {
        let mut world = World::new();
        world.register::<Draw>();
        world.register::<HitBox>();
        world.register::<OnHoverImage>();
        world.register::<Palette>();
        world.register::<Position>();
        world.register::<RenderOrder>();
        world.register::<Velocity>();
        world.register::<Controller>();
        world.register::<MapIntent>();
        world.register::<TimeSpentOnTerrain>();
        world
    }

    fn build_dispatcher() -> Dispatcher<'a, 'a> {
        DispatcherBuilder::new()
            .with(MapCommander, "map_commander", &[])
            .with(TerrainCost, "terrain_cost", &["map_commander"])
            .with(SetMapVelocity, "velocity", &["terrain_cost"])
            .with(
                RestrictMovementToMapBoundary,
                "restrict_movement",
                &["velocity"],
            )
            .with(Movement, "movement", &["restrict_movement"])
            .with(HighlightOnHover, "highlight_on_hover", &["movement"])
            .with(HighlightPlayer, "highlight_player", &[])
            .build()
    }

    fn setup_background_map(
        ctx: &mut Context,
        store: &mut Store<Context, SimpleKey>,
        background_name: &str,
    ) -> Result<Vec<graphics::Image>, MoonstoneError> {
        let piv_res = store.get::<PivImage>(&SimpleKey::from(background_name), ctx)?;
        let mut background: Vec<graphics::Image> = Vec::new();
        let mut piv = piv_res.borrow_mut();
        background.push(graphics::Image::from_rgba8(
            ctx,
            512,
            512,
            &piv.to_rgba8_512(),
        )?);

        piv.palette[21..24].rotate_right(1);
        background.push(graphics::Image::from_rgba8(
            ctx,
            512,
            512,
            &piv.to_rgba8_512(),
        )?);

        piv.palette[21..24].rotate_right(1);
        background.push(graphics::Image::from_rgba8(
            ctx,
            512,
            512,
            &piv.to_rgba8_512(),
        )?);

        piv.palette[21..24].rotate_right(1);
        Ok(background)
    }

    fn build_knight_entity(
        ctx: &mut Context,
        store: &mut Store<Context, SimpleKey>,
        world: &'a mut World,
        background_name: &str,
    ) -> Result<(), MoonstoneError> {
        let piv_res = store
            .get::<PivImage>(&SimpleKey::from(background_name), ctx)
            .unwrap();
        let piv = piv_res.borrow();

        let atlas = store.get::<TextureAtlas>(&SimpleKey::from("mi.c"), ctx)?;
        // the first image in mi.c is the blue knight head.
        let knight_rect = atlas.borrow().rects[0];
        let knight_width = atlas.borrow().visible_widths[0];

        let sprite_res = store.get::<Sprite>(&SimpleKey::from(format!("/{}.yaml", "mi")), ctx)?;
        let sprite = sprite_res.borrow();
        let entity_builder = world
            .create_entity()
            .with(Position { x: 10, y: 10 })
            .with(Velocity {
                ..Default::default()
            })
            .with(Draw {
                frame: sprite.animations["blue_knight"].frames[0].clone(),
                animation: "blue_knight".to_string(),
                resource_name: "mi".to_string(),
                direction: Facing::default(),
            })
            .with(Palette {
                name: "0".to_string(),
                palette: piv.palette.clone(),
            })
            .with(HitBox {
                w: knight_width,
                h: knight_rect.h,
            })
            .with(Controller {
                x_axis: Axis::Horz1,
                y_axis: Axis::Vert1,
                button: Button::Fire1,
                ..Default::default()
            })
            .with(RenderOrder { depth: 1 })
            .with(MapIntent {
                ..Default::default()
            })
            .with(TimeSpentOnTerrain {
                ..Default::default()
            })
            .build();
        Ok(())
    }

    fn build_locations(
        ctx: &mut Context,
        store: &mut Store<Context, SimpleKey>,
        world: &'a mut World,
        background_name: &str,
    ) -> Result<(), MoonstoneError> {
        let locations_res = store.get_by::<GameRon<Locations>, FromRon>(
            &SimpleKey::from("/locations.ron"),
            ctx,
            FromRon,
        )?;
        let piv_res = store
            .get::<PivImage>(&SimpleKey::from(background_name), ctx)
            .unwrap();
        let piv = piv_res.borrow();

        let atlas = store.get::<TextureAtlas>(&SimpleKey::from("mi.c"), ctx)?;
        for l in locations_res.borrow().0.locations.iter() {
            let sprite_res =
                store.get::<Sprite>(&SimpleKey::from(format!("/{}.yaml", "mi")), ctx)?;
            let sprite = sprite_res.borrow();

            let mut entity_builder = world
                .create_entity()
                .with(Position { x: l.x, y: l.y })
                .with(Palette {
                    name: "0".to_string(),
                    palette: piv.palette.clone(),
                })
                .with(RenderOrder { depth: 0 })
                .with(OnHoverImage {
                    image: l.image.clone(),
                    hover: l.hover_image.clone(),
                })
                .with(Draw {
                    frame: Frame { images: vec![] },
                    animation: "".to_string(),
                    resource_name: "mi".to_string(),
                    direction: Facing::default(),
                });

            if let Some(i) = l.image.as_ref().or(l.hover_image.as_ref()) {
                let rect = atlas.borrow().rects[i.image];
                let width = atlas.borrow().visible_widths[i.image];
                entity_builder = entity_builder.with(HitBox {
                    w: width,
                    h: rect.h,
                })
            }

            entity_builder.build();
        }
        Ok(())
    }

    fn insert_palettes(specs_world: &mut World, piv: &PivImage) -> Result<(), MoonstoneError> {
        let mut swap_colour = extract_palette(&[0xff]).first().unwrap().clone();
        swap_colour.a = 255;
        let mut oscillate = ColourOscillate::new(piv.palette[31], swap_colour);
        let mut colours = (0..30)
            .map(|_| oscillate.next().unwrap())
            .collect::<Vec<_>>();
        colours.insert(0, piv.palette[31].clone());

        let mut palettes = Vec::new();
        for c in &colours {
            let mut p = piv.palette.clone();
            p[31] = c.clone();
            palettes.push(p);
        }
        specs_world.insert(FlashingPalettes { palettes });
        Ok(())
    }

    fn insert_campaign_map(
        ctx: &mut Context,
        store: &mut Store<Context, SimpleKey>,
        specs_world: &mut World,
    ) -> Result<(), MoonstoneError> {
        let campaign_map_res = store.get_by::<GameRon<CampaignMap>, FromRon>(
            &SimpleKey::from("/campaign_map.ron"),
            ctx,
            FromRon,
        )?;
        specs_world.insert(campaign_map_res.borrow().0.clone());
        Ok(())
    }

    fn insert_boundary(specs_world: &mut World) -> Result<(), MoonstoneError> {
        specs_world.insert(Boundary {
            x: 0,
            y: 0,
            w: 310,
            h: 190,
        });
        Ok(())
    }

    pub fn new(
        ctx: &mut Context,
        store: &mut Store<Context, SimpleKey>,
        background_name: &str,
        num_players: u32,
    ) -> Result<Self, MoonstoneError> {
        let background = MapScene::setup_background_map(ctx, store, &background_name)?;

        let mut specs_world = Self::build_world();

        MapScene::build_knight_entity(ctx, store, &mut specs_world, &background_name);

        MapScene::insert_boundary(&mut specs_world)?;
        MapScene::insert_campaign_map(ctx, store, &mut specs_world)?;

        let piv_res = store.get::<PivImage>(&SimpleKey::from(background_name), ctx)?;
        let piv = piv_res.borrow();
        MapScene::insert_palettes(&mut specs_world, &*piv)?;
        MapScene::build_locations(ctx, store, &mut specs_world, background_name)?;

        // let map_data = store
        //     .get::<MapData>(&warmy::SimpleKey::from("/map.yaml"), ctx)?
        //     .borrow()
        //     .clone();
        Ok(Self {
            specs_world: specs_world,
            dispatcher: Self::build_dispatcher(),
            // map_data,
            background,
            background_frame: 0,
            current_background_image: 0,
            palette: piv.palette.to_vec(),
        })
    }

    fn draw_background_map(&mut self, game: &mut Game, ctx: &mut Context) -> GameResult<()> {
        // let draw_params = graphics::DrawParam::default().scale(game.screen_scale);
        graphics::draw(
            ctx,
            &self.background[self.current_background_image],
            // draw_params,
            graphics::DrawParam::default(),
        )?;
        Ok(())
    }

    fn update_controllers(&mut self, input: &input::InputState) {
        let entities = self.specs_world.entities();
        let mut controllers = self.specs_world.write_storage::<Controller>();
        for (e, controller) in (&*entities, &mut controllers).join() {
            controller.x = input.get_axis_raw(controller.x_axis) as i32;
            controller.y = input.get_axis_raw(controller.y_axis) as i32;
            controller.fire = input.get_button_down(controller.button);
        }
    }
}

impl<'a> Scene<Game, InputEvent> for MapScene<'a> {
    fn update(&mut self, game: &mut Game, _ctx: &mut Context) -> FSceneSwitch {
        self.update_controllers(&game.input);
        self.dispatcher.dispatch_par(&self.specs_world);
        self.specs_world.maintain();
        self.background_frame += 1;
        if self.background_frame == MAP_ANIMATION_SPEED {
            self.current_background_image += 1;
            self.current_background_image %= self.background.len();
        }
        self.background_frame %= MAP_ANIMATION_SPEED;
        SceneSwitch::None
    }

    fn draw(&mut self, game: &mut Game, ctx: &mut Context) -> GameResult<()> {
        // since some of the campaign map is transparent, a sprite passing over
        // the transparent area would "colour in" that area, leaving behind the
        // ghost image of the sprite on those pixels, we clear the screen each
        // frame to get rid of these artifacts.
        graphics::clear(ctx, graphics::Color::new(0.0, 0.0, 0.0, 1.0));
        self.draw_background_map(game, ctx);
        draw_entities(&self.specs_world, &self.palette, None, game, ctx);
        Ok(())
    }

    fn name(&self) -> &str {
        "Map"
    }

    fn input(&mut self, gameworld: &mut Game, event: InputEvent, started: bool) {
        // let entities = self.specs_world.entities();
        // let mut controllers = self.specs_world.write_storage::<Controller>();
        // for (e, controller) in (&*entities, &mut controllers).join() {
        //     let x = gameworld.input.get_axis_raw(controller.x_axis);
        //     controller.x = gameworld.input.get_axis_raw(controller.x_axis) as i32;
        //     controller.y = gameworld.input.get_axis_raw(controller.y_axis) as i32;
        //     controller.fire = gameworld.input.get_button_down(controller.button);
        //     // println!("input {:?}", controller);
        // }
    }
}
<|endoftext|>


<commit_before>pub mod tag_command;
pub mod autotag;
pub mod update_tags;

pub use self::tag_command::TagCommand;
pub use self::autotag::AutoTagCommand;
pub use self::update_tags::UpdateTagsCommand;

use LalafellBot;
use database::AutotagUser;

use xivdb::error::*;

use discord::model::{UserId, LiveServer, Role, RoleId};

use std::sync::Arc;

pub struct Tagger;

impl Tagger {
  pub fn search_tag(bot: Arc<LalafellBot>, who: UserId, on: &LiveServer, server: &str, character_name: &str, ignore_verified: bool) -> Result<Option<String>> {
    let params = &[
      ("one", "characters"),
      ("strict", "on"),
      ("server|et", server)
    ];

    let res = bot.xivdb.search(character_name, params).chain_err(|| "could not query XIVDB")?;

    let search_chars = res.characters.unwrap().results;
    if search_chars.is_empty() {
      return Ok(Some(format!("Could not find any character by the name {} on {}.", character_name, server)));
    }

    let char_id = match search_chars[0]["id"].as_u64() {
      Some(u) => u,
      None => return Err("character ID was not a u64".into())
    };

    let name = match search_chars[0]["name"].as_str() {
      Some(s) => s,
      None => return Err("character name was not a string".into())
    };

    if name.to_lowercase() != character_name.to_lowercase() {
      return Ok(Some(format!("Could not find any character by the name {} on {}.", character_name, server)));
    }

    Tagger::tag(bot, who, on, char_id, ignore_verified)
  }

  pub fn tag(bot: Arc<LalafellBot>, who: UserId, on: &LiveServer, char_id: u64, ignore_verified: bool) -> Result<Option<String>> {
    let is_verified = match bot.database.lock().unwrap().autotags.users.iter().find(|u| u.user_id == who.0 && u.server_id == on.id.0) {
      Some(u) => {
        if u.verification.verified && !ignore_verified && char_id != u.character_id {
          return Ok(Some(format!("{} is verified as {} on {}, so they cannot switch to another account.", who.mention(), u.character, u.server)));
        }
        u.verification.verified
      },
      None => false
    };

    let member = bot.discord.get_member(on.id, who).chain_err(|| "could not get member for tagging")?;

    let character = bot.xivdb.character(char_id).chain_err(|| "could not look up character")?;

    bot.database.lock().unwrap().autotags.update_or_add(AutotagUser::new(
      who.0,
      on.id.0,
      character.lodestone_id,
      &character.name,
      &character.server
    ));

    let roles = &on.roles;
    let mut add_roles = Vec::new();
    match roles.iter().find(|x| x.name.to_lowercase() == character.data.race.to_lowercase()) {
      Some(r) => add_roles.push(r),
      None => {
        let role = bot.discord.create_role(on.id, Some(character.data.race), None, None, None, None).chain_err(|| "could not create role");
        add_roles.push(r);
      }
    }
    match roles.iter().find(|x| x.name.to_lowercase() == character.data.gender.to_lowercase()) {
      Some(r) => add_roles.push(r),
      None => {
        let role = bot.discord.create_role(on.id, Some(character.data.gender), None, None, None, None).chain_err(|| "could not create role");
        add_roles.push(r);
      }
    }
    match roles.iter().find(|x| x.name.to_lowercase() == character.server.to_lowercase()) {
      Some(r) => add_roles.push(r),
      None => {
        let role = bot.discord.create_role(on.id, Some(character.server), None, None, None, None).chain_err(|| "could not create role");
        add_roles.push(r);
      }
    }
    if is_verified {
      match roles.iter().find(|x| x.name.to_lowercase() == "verified") {
        Some(r) => add_roles.push(r),
        None => {
          let role = bot.discord.create_role(on.id, Some("Verified"), None, None, None, None).chain_err(|| "could not create role");
          add_roles.push(r);
        }
      }
    }

    let all_group_roles: Vec<&String> = bot.config.roles.groups.iter().flat_map(|x| x).collect();
    let keep: Vec<&Role> = roles.iter().filter(|x| member.roles.contains(&x.id)).collect();
    let keep: Vec<&Role> = keep.into_iter().filter(|x| !all_group_roles.contains(&&x.name)).collect();
    let mut role_set: Vec<RoleId> = add_roles.iter().map(|r| r.id).chain(keep.into_iter().map(|r| r.id)).collect();
    role_set.sort();
    role_set.dedup();

    if !role_set.iter().all(|r| member.roles.contains(r)) {
      bot.discord.edit_member_roles(on.id, who, &role_set).chain_err(|| "could not add roles")?;
    }

    // cannot edit nickname of those with a higher role
    let nick = match member.nick {
      Some(n) => n,
      None => Default::default()
    };
    if nick != character.name {
      bot.discord.edit_member(on.id, who, |e| e.nickname(&character.name)).ok();
    }
    Ok(None)
  }
}
<commit_msg>fix: use &str, not String<commit_after>pub mod tag_command;
pub mod autotag;
pub mod update_tags;

pub use self::tag_command::TagCommand;
pub use self::autotag::AutoTagCommand;
pub use self::update_tags::UpdateTagsCommand;

use LalafellBot;
use database::AutotagUser;

use xivdb::error::*;

use discord::model::{UserId, LiveServer, Role, RoleId};

use std::sync::Arc;

pub struct Tagger;

impl Tagger {
  pub fn search_tag(bot: Arc<LalafellBot>, who: UserId, on: &LiveServer, server: &str, character_name: &str, ignore_verified: bool) -> Result<Option<String>> {
    let params = &[
      ("one", "characters"),
      ("strict", "on"),
      ("server|et", server)
    ];

    let res = bot.xivdb.search(character_name, params).chain_err(|| "could not query XIVDB")?;

    let search_chars = res.characters.unwrap().results;
    if search_chars.is_empty() {
      return Ok(Some(format!("Could not find any character by the name {} on {}.", character_name, server)));
    }

    let char_id = match search_chars[0]["id"].as_u64() {
      Some(u) => u,
      None => return Err("character ID was not a u64".into())
    };

    let name = match search_chars[0]["name"].as_str() {
      Some(s) => s,
      None => return Err("character name was not a string".into())
    };

    if name.to_lowercase() != character_name.to_lowercase() {
      return Ok(Some(format!("Could not find any character by the name {} on {}.", character_name, server)));
    }

    Tagger::tag(bot, who, on, char_id, ignore_verified)
  }

  pub fn tag(bot: Arc<LalafellBot>, who: UserId, on: &LiveServer, char_id: u64, ignore_verified: bool) -> Result<Option<String>> {
    let is_verified = match bot.database.lock().unwrap().autotags.users.iter().find(|u| u.user_id == who.0 && u.server_id == on.id.0) {
      Some(u) => {
        if u.verification.verified && !ignore_verified && char_id != u.character_id {
          return Ok(Some(format!("{} is verified as {} on {}, so they cannot switch to another account.", who.mention(), u.character, u.server)));
        }
        u.verification.verified
      },
      None => false
    };

    let member = bot.discord.get_member(on.id, who).chain_err(|| "could not get member for tagging")?;

    let character = bot.xivdb.character(char_id).chain_err(|| "could not look up character")?;

    bot.database.lock().unwrap().autotags.update_or_add(AutotagUser::new(
      who.0,
      on.id.0,
      character.lodestone_id,
      &character.name,
      &character.server
    ));

    let roles = &on.roles;
    let mut add_roles = Vec::new();
    match roles.iter().find(|x| x.name.to_lowercase() == character.data.race.to_lowercase()) {
      Some(r) => add_roles.push(r),
      None => {
        let role = bot.discord.create_role(on.id, Some(&character.data.race), None, None, None, None).chain_err(|| "could not create role");
        add_roles.push(r);
      }
    }
    match roles.iter().find(|x| x.name.to_lowercase() == character.data.gender.to_lowercase()) {
      Some(r) => add_roles.push(r),
      None => {
        let role = bot.discord.create_role(on.id, Some(&character.data.gender), None, None, None, None).chain_err(|| "could not create role");
        add_roles.push(r);
      }
    }
    match roles.iter().find(|x| x.name.to_lowercase() == character.server.to_lowercase()) {
      Some(r) => add_roles.push(r),
      None => {
        let role = bot.discord.create_role(on.id, Some(&character.server), None, None, None, None).chain_err(|| "could not create role");
        add_roles.push(r);
      }
    }
    if is_verified {
      match roles.iter().find(|x| x.name.to_lowercase() == "verified") {
        Some(r) => add_roles.push(r),
        None => {
          let role = bot.discord.create_role(on.id, Some("Verified"), None, None, None, None).chain_err(|| "could not create role");
          add_roles.push(r);
        }
      }
    }

    let all_group_roles: Vec<&String> = bot.config.roles.groups.iter().flat_map(|x| x).collect();
    let keep: Vec<&Role> = roles.iter().filter(|x| member.roles.contains(&x.id)).collect();
    let keep: Vec<&Role> = keep.into_iter().filter(|x| !all_group_roles.contains(&&x.name)).collect();
    let mut role_set: Vec<RoleId> = add_roles.iter().map(|r| r.id).chain(keep.into_iter().map(|r| r.id)).collect();
    role_set.sort();
    role_set.dedup();

    if !role_set.iter().all(|r| member.roles.contains(r)) {
      bot.discord.edit_member_roles(on.id, who, &role_set).chain_err(|| "could not add roles")?;
    }

    // cannot edit nickname of those with a higher role
    let nick = match member.nick {
      Some(n) => n,
      None => Default::default()
    };
    if nick != character.name {
      bot.discord.edit_member(on.id, who, |e| e.nickname(&character.name)).ok();
    }
    Ok(None)
  }
}
<|endoftext|>


<commit_before>// Copyright 2015-2017 Intecture Developers.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

//! Endpoint for managing packages.
//!
//! A package is represented by the `Package` struct, which is idempotent. This
//! means you can execute it repeatedly and it'll only run as needed.

pub mod providers;

use command::{ExitStatus, parse_body_stream};
use errors::*;
use futures::{future, Future};
use futures::stream::Stream;
use host::Host;
use remote::{Request, Response};
use self::providers::PackageProvider;

/// Represents a system package to be managed for a host.
///
///## Examples
///
pub struct Package<H: Host> {
    host: H,
    provider: Option<Box<PackageProvider>>,
    name: String,
}

impl<H: Host + 'static> Package<H> {
    /// Create a new `Package` with the default `PackageProvider`.
    pub fn new(host: &H, name: &str) -> Package<H> {
        Package {
            host: host.clone(),
            provider: None,
            name: name.into(),
        }
    }

    /// Create a new `Package` with the specified `PackageProvider`.
    ///
    ///## Example
    ///```
    ///extern crate futures;
    ///extern crate intecture_api;
    ///extern crate tokio_core;
    ///
    ///use futures::Future;
    ///use intecture_api::package::providers::Yum;
    ///use intecture_api::prelude::*;
    ///use tokio_core::reactor::Core;
    ///
    ///# fn main() {
    ///let mut core = Core::new().unwrap();
    ///let handle = core.handle();
    ///
    ///let host = Local::new(&handle).wait().unwrap();
    ///
    ///Package::with_provider(&host, Yum, "nginx");
    ///# }
    pub fn with_provider<P>(host: &H, provider: P, name: &str) -> Package<H>
        where P: PackageProvider + 'static
    {
        Package {
            host: host.clone(),
            provider: Some(Box::new(provider)),
            name: name.into(),
        }
    }

    /// Check if the package is installed.
    pub fn installed(&self) -> Box<Future<Item = bool, Error = Error>> {
        let request = Request::PackageInstalled(self.provider.as_ref().map(|p| p.name()), self.name.clone());
        Box::new(self.host.request(request)
            .chain_err(|| ErrorKind::Request { endpoint: "Package", func: "installed" })
            .map(|msg| {
                match msg.into_inner() {
                    Response::Bool(b) => b,
                    _ => unreachable!(),
                }
            }))
    }

    /// Install the package.
    ///
    /// This function is idempotent, which is represented by the type
    /// `Future<Item = Option<..>, ...>`. Thus if it returns `Option::None`
    /// then the package is already installed, and if it returns `Option::Some`
    /// then Intecture is attempting to install the package.
    ///
    /// If this fn returns `Option::Some<..>`, the nested tuple will hold
    /// handles to the live output and the result of the installation. Under
    /// the hood this reuses the `Command` endpoint, so see
    /// [`Command` docs](../command/struct.Command.html) for detailed
    /// usage.
    ///
    ///# Example
    ///
    /// Install a package and print the result.
    ///
    ///```
    ///extern crate futures;
    ///extern crate intecture_api;
    ///extern crate tokio_core;
    ///
    ///use futures::{future, Future, Stream};
    ///use intecture_api::errors::Error;
    ///use intecture_api::prelude::*;
    ///use tokio_core::reactor::Core;
    ///
    ///# fn main() {
    ///let mut core = Core::new().unwrap();
    ///let handle = core.handle();
    ///
    ///let host = Local::new(&handle).wait().unwrap();
    ///
    ///let nginx = Package::new(&host, "nginx");
    ///let result = nginx.install().and_then(|status| {
    ///    match status {
    ///        // We're performing the install
    ///        Some((stream, status)) => Box::new(stream.fold(String::new(), |mut acc, line| {
    ///                acc.push_str(&line);
    ///                future::ok::<_, Error>(acc)
    ///            })
    ///            .join(status)
    ///            .map(|(output, status)| {
    ///                if status.success {
    ///                    println!("Installed");
    ///                } else {
    ///                    println!("Failed with output: {}", output);
    ///                }
    ///            })) as Box<Future<Item = _, Error = Error>>,
    ///        None => {
    ///            println!("Already installed");
    ///            Box::new(future::ok(()))
    ///        },
    ///    }
    ///});
    ///
    ///core.run(result).unwrap();
    ///# }
    ///```
    pub fn install(&self) -> Box<Future<Item = Option<(
            Box<Stream<Item = String, Error = Error>>,
            Box<Future<Item = ExitStatus, Error = Error>>
        )>, Error = Error>>
    {
        let host = self.host.clone();
        let provider = self.provider.as_ref().map(|p| p.name());
        let name = self.name.clone();

        Box::new(self.installed()
            .and_then(move |installed| {
                if installed {
                    Box::new(future::ok(None)) as Box<Future<Item = _, Error = Error>>
                } else {
                    Box::new(host.request(Request::PackageInstall(provider, name))
                        .chain_err(|| ErrorKind::Request { endpoint: "Package", func: "install" })
                        .map(|msg| {
                            Some(parse_body_stream(msg))
                        }))
                }
            }))
    }

    /// Uninstall the package.
    ///
    /// This function is idempotent, which is represented by the type
    /// `Future<Item = Option<..>, ...>`. Thus if it returns `Option::None`
    /// then the package is already uninstalled, and if it returns
    /// `Option::Some` then Intecture is attempting to uninstall the package.
    ///
    /// If this fn returns `Option::Some<..>`, the nested tuple will hold
    /// handles to the live output and the result of the deinstallation. Under
    /// the hood this reuses the `Command` endpoint, so see
    /// [`Command` docs](../command/struct.Command.html) for detailed
    /// usage.
    pub fn uninstall(&self) -> Box<Future<Item = Option<(
            Box<Stream<Item = String, Error = Error>>,
            Box<Future<Item = ExitStatus, Error = Error>>
        )>, Error = Error>>
    {
        let host = self.host.clone();
        let provider = self.provider.as_ref().map(|p| p.name());
        let name = self.name.clone();

        Box::new(self.installed()
            .and_then(move |installed| {
                if installed {
                    Box::new(host.request(Request::PackageUninstall(provider, name))
                        .chain_err(|| ErrorKind::Request { endpoint: "Package", func: "uninstall" })
                        .map(|msg| {
                            Some(parse_body_stream(msg))
                        }))
                } else {
                    Box::new(future::ok(None)) as Box<Future<Item = _, Error = Error>>
                }
            }))
    }
}
<commit_msg>Prevent Package doc test from running<commit_after>// Copyright 2015-2017 Intecture Developers.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

//! Endpoint for managing packages.
//!
//! A package is represented by the `Package` struct, which is idempotent. This
//! means you can execute it repeatedly and it'll only run as needed.

pub mod providers;

use command::{ExitStatus, parse_body_stream};
use errors::*;
use futures::{future, Future};
use futures::stream::Stream;
use host::Host;
use remote::{Request, Response};
use self::providers::PackageProvider;

/// Represents a system package to be managed for a host.
///
///## Examples
///
pub struct Package<H: Host> {
    host: H,
    provider: Option<Box<PackageProvider>>,
    name: String,
}

impl<H: Host + 'static> Package<H> {
    /// Create a new `Package` with the default `PackageProvider`.
    pub fn new(host: &H, name: &str) -> Package<H> {
        Package {
            host: host.clone(),
            provider: None,
            name: name.into(),
        }
    }

    /// Create a new `Package` with the specified `PackageProvider`.
    ///
    ///## Example
    ///```
    ///extern crate futures;
    ///extern crate intecture_api;
    ///extern crate tokio_core;
    ///
    ///use futures::Future;
    ///use intecture_api::package::providers::Yum;
    ///use intecture_api::prelude::*;
    ///use tokio_core::reactor::Core;
    ///
    ///# fn main() {
    ///let mut core = Core::new().unwrap();
    ///let handle = core.handle();
    ///
    ///let host = Local::new(&handle).wait().unwrap();
    ///
    ///Package::with_provider(&host, Yum, "nginx");
    ///# }
    pub fn with_provider<P>(host: &H, provider: P, name: &str) -> Package<H>
        where P: PackageProvider + 'static
    {
        Package {
            host: host.clone(),
            provider: Some(Box::new(provider)),
            name: name.into(),
        }
    }

    /// Check if the package is installed.
    pub fn installed(&self) -> Box<Future<Item = bool, Error = Error>> {
        let request = Request::PackageInstalled(self.provider.as_ref().map(|p| p.name()), self.name.clone());
        Box::new(self.host.request(request)
            .chain_err(|| ErrorKind::Request { endpoint: "Package", func: "installed" })
            .map(|msg| {
                match msg.into_inner() {
                    Response::Bool(b) => b,
                    _ => unreachable!(),
                }
            }))
    }

    /// Install the package.
    ///
    /// This function is idempotent, which is represented by the type
    /// `Future<Item = Option<..>, ...>`. Thus if it returns `Option::None`
    /// then the package is already installed, and if it returns `Option::Some`
    /// then Intecture is attempting to install the package.
    ///
    /// If this fn returns `Option::Some<..>`, the nested tuple will hold
    /// handles to the live output and the result of the installation. Under
    /// the hood this reuses the `Command` endpoint, so see
    /// [`Command` docs](../command/struct.Command.html) for detailed
    /// usage.
    ///
    ///# Example
    ///
    /// Install a package and print the result.
    ///
    ///```no_run
    ///extern crate futures;
    ///extern crate intecture_api;
    ///extern crate tokio_core;
    ///
    ///use futures::{future, Future, Stream};
    ///use intecture_api::errors::Error;
    ///use intecture_api::prelude::*;
    ///use tokio_core::reactor::Core;
    ///
    ///# fn main() {
    ///let mut core = Core::new().unwrap();
    ///let handle = core.handle();
    ///
    ///let host = Local::new(&handle).wait().unwrap();
    ///
    ///let nginx = Package::new(&host, "nginx");
    ///let result = nginx.install().and_then(|status| {
    ///    match status {
    ///        // We're performing the install
    ///        Some((stream, status)) => Box::new(stream.fold(String::new(), |mut acc, line| {
    ///                acc.push_str(&line);
    ///                future::ok::<_, Error>(acc)
    ///            })
    ///            .join(status)
    ///            .map(|(output, status)| {
    ///                if status.success {
    ///                    println!("Installed");
    ///                } else {
    ///                    println!("Failed with output: {}", output);
    ///                }
    ///            })) as Box<Future<Item = _, Error = Error>>,
    ///        None => {
    ///            println!("Already installed");
    ///            Box::new(future::ok(()))
    ///        },
    ///    }
    ///});
    ///
    ///core.run(result).unwrap();
    ///# }
    ///```
    pub fn install(&self) -> Box<Future<Item = Option<(
            Box<Stream<Item = String, Error = Error>>,
            Box<Future<Item = ExitStatus, Error = Error>>
        )>, Error = Error>>
    {
        let host = self.host.clone();
        let provider = self.provider.as_ref().map(|p| p.name());
        let name = self.name.clone();

        Box::new(self.installed()
            .and_then(move |installed| {
                if installed {
                    Box::new(future::ok(None)) as Box<Future<Item = _, Error = Error>>
                } else {
                    Box::new(host.request(Request::PackageInstall(provider, name))
                        .chain_err(|| ErrorKind::Request { endpoint: "Package", func: "install" })
                        .map(|msg| {
                            Some(parse_body_stream(msg))
                        }))
                }
            }))
    }

    /// Uninstall the package.
    ///
    /// This function is idempotent, which is represented by the type
    /// `Future<Item = Option<..>, ...>`. Thus if it returns `Option::None`
    /// then the package is already uninstalled, and if it returns
    /// `Option::Some` then Intecture is attempting to uninstall the package.
    ///
    /// If this fn returns `Option::Some<..>`, the nested tuple will hold
    /// handles to the live output and the result of the deinstallation. Under
    /// the hood this reuses the `Command` endpoint, so see
    /// [`Command` docs](../command/struct.Command.html) for detailed
    /// usage.
    pub fn uninstall(&self) -> Box<Future<Item = Option<(
            Box<Stream<Item = String, Error = Error>>,
            Box<Future<Item = ExitStatus, Error = Error>>
        )>, Error = Error>>
    {
        let host = self.host.clone();
        let provider = self.provider.as_ref().map(|p| p.name());
        let name = self.name.clone();

        Box::new(self.installed()
            .and_then(move |installed| {
                if installed {
                    Box::new(host.request(Request::PackageUninstall(provider, name))
                        .chain_err(|| ErrorKind::Request { endpoint: "Package", func: "uninstall" })
                        .map(|msg| {
                            Some(parse_body_stream(msg))
                        }))
                } else {
                    Box::new(future::ok(None)) as Box<Future<Item = _, Error = Error>>
                }
            }))
    }
}
<|endoftext|>


<commit_before>// Std
use std::io::Write;

// Internal
use app::App;
use args::{Arg, ArgSettings};
use completions;

pub struct BashGen<'a, 'b>(&'b App<'a, 'b>)
where
    'a: 'b;

impl<'a, 'b> BashGen<'a, 'b> {
    pub fn new(app: &'b App<'a, 'b>) -> Self { BashGen(app) }

    pub fn generate_to<W: Write>(&self, buf: &mut W) {
        w!(
            buf,
            format!(
                "_{name}() {{
    local i cur prev opts cmds
    COMPREPLY=()
    cur=\"${{COMP_WORDS[COMP_CWORD]}}\"
    prev=\"${{COMP_WORDS[COMP_CWORD-1]}}\"
    cmd=\"\"
    opts=\"\"

    for i in ${{COMP_WORDS[@]}}
    do
        case \"${{i}}\" in
            {name})
                cmd=\"{name}\"
                ;;
            {subcmds}
            *)
                ;;
        esac
    done

    case \"${{cmd}}\" in
        {name})
            opts=\"{name_opts}\"
            if [[ ${{cur}} == -* || ${{COMP_CWORD}} -eq 1 ]] ; then
                COMPREPLY=( $(compgen -W \"${{opts}}\" -- ${{cur}}) )
                return 0
            fi
            case \"${{prev}}\" in
                {name_opts_details}
                *)
                    COMPREPLY=()
                    ;;
            esac
            COMPREPLY=( $(compgen -W \"${{opts}}\" -- ${{cur}}) )
            return 0
            ;;
        {subcmd_details}
    esac
}}

complete -F _{name} -o bashdefault -o default {name}
",
                name = self.0.bin_name.as_ref().unwrap(),
                name_opts = self.all_options_for_path(self.0.bin_name.as_ref().unwrap()),
                name_opts_details = self.option_details_for_path(self.0.bin_name.as_ref().unwrap()),
                subcmds = self.all_subcommands(),
                subcmd_details = self.subcommand_details()
            ).as_bytes()
        );
    }

    fn all_subcommands(&self) -> String {
        debugln!("BashGen::all_subcommands;");
        let mut subcmds = String::new();
        let scs = completions::all_subcommand_names(self.0);

        for sc in &scs {
            subcmds = format!(
                "{}
            {name})
                cmd+=\"__{fn_name}\"
                ;;",
                subcmds,
                name = sc,
                fn_name = sc.replace("-", "__")
            );
        }

        subcmds
    }

    fn subcommand_details(&self) -> String {
        debugln!("BashGen::subcommand_details;");
        let mut subcmd_dets = String::new();
        let mut scs = completions::get_all_subcommand_paths(self.0, true);
        scs.sort();
        scs.dedup();

        for sc in &scs {
            subcmd_dets = format!(
                "{}
        {subcmd})
            opts=\"{sc_opts}\"
            if [[ ${{cur}} == -* || ${{COMP_CWORD}} -eq {level} ]] ; then
                COMPREPLY=( $(compgen -W \"${{opts}}\" -- ${{cur}}) )
                return 0
            fi
            case \"${{prev}}\" in
                {opts_details}
                *)
                    COMPREPLY=()
                    ;;
            esac
            COMPREPLY=( $(compgen -W \"${{opts}}\" -- ${{cur}}) )
            return 0
            ;;",
                subcmd_dets,
                subcmd = sc.replace("-", "__"),
                sc_opts = self.all_options_for_path(&*sc),
                level = sc.split("__").map(|_| 1).fold(0, |acc, n| acc + n),
                opts_details = self.option_details_for_path(&*sc)
            );
        }

        subcmd_dets
    }

    fn option_details_for_path(&self, path: &str) -> String {
        debugln!("BashGen::option_details_for_path: path={}", path);
        let mut p = self.0;
        for sc in path.split("__").skip(1) {
            debugln!("BashGen::option_details_for_path:iter: sc={}", sc);
            p = &find_subcmd!(p, sc).unwrap();
        }
        let mut opts = String::new();
        for o in opts!(p) {
            if let Some(l) = o.long {
                opts = format!(
                    "{}
                --{})
                    COMPREPLY=({})
                    return 0
                    ;;",
                    opts,
                    l,
                    self.vals_for(o)
                );
            }
            if let Some(s) = o.short {
                opts = format!(
                    "{}
                    -{})
                    COMPREPLY=({})
                    return 0
                    ;;",
                    opts,
                    s,
                    self.vals_for(o)
                );
            }
        }
        opts
    }

    fn vals_for(&self, o: &Arg) -> String {
        debugln!("BashGen::vals_for: o={}", o.name);
        let mut ret = String::new();
        let mut needs_quotes = true;
        if let Some(ref vals) = o.possible_vals {
            needs_quotes = false;
            ret = format!("$(compgen -W \"{}\" -- ${{cur}})", vals.join(" "));
        } else if let Some(ref vec) = o.val_names {
            let mut it = vec.iter().peekable();
            while let Some((_, val)) = it.next() {
                ret = format!(
                    "{}<{}>{}",
                    ret,
                    val,
                    if it.peek().is_some() { " " } else { "" }
                );
            }
            let num = vec.len();
            if (o.is_set(ArgSettings::MultipleValues) || o.is_set(ArgSettings::MultipleOccurrences))
                && num == 1
            {
                ret = format!("{}...", ret);
            }
        } else if let Some(num) = o.num_vals {
            let mut it = (0..num).peekable();
            while let Some(_) = it.next() {
                ret = format!(
                    "{}<{}>{}",
                    ret,
                    o.name,
                    if it.peek().is_some() { " " } else { "" }
                );
            }
            if (o.is_set(ArgSettings::MultipleValues) || o.is_set(ArgSettings::MultipleOccurrences))
                && num == 1
            {
                ret = format!("{}...", ret);
            }
        } else {
            ret = format!("<{}>", o.name);
            if o.is_set(ArgSettings::MultipleValues) || o.is_set(ArgSettings::MultipleOccurrences) {
                ret = format!("{}...", ret);
            }
        }
        if needs_quotes {
            ret = format!("\"{}\"", ret);
        }
        ret
    }
    fn all_options_for_path(&self, path: &str) -> String {
        debugln!("BashGen::all_options_for_path: path={}", path);
        let mut p = self.0;
        for sc in path.split("__").skip(1) {
            debugln!("BashGen::all_options_for_path:iter: sc={}", sc);
            p = &find_subcmd!(p, sc).unwrap();
        }
        let opts = format!(
            "{shorts} {longs} {pos} {subcmds}",
            shorts = shorts!(p).fold(String::new(), |acc, s| format!("{} -{}", acc, s)),
            // Handles aliases too
            longs = longs!(p).fold(String::new(), |acc, l| format!("{} --{}", acc, l)),
            pos = positionals!(p).fold(String::new(), |acc, p| format!("{} {}", acc, p)),
            // Handles aliases too
            subcmds = sc_names!(p).fold(String::new(), |acc, s| format!("{} {}", acc, s))
        );
        opts
    }
}
<commit_msg>imp(Bash Completions): instead of completing a generic option name, all bash completions fall back to file completions UNLESS Arg::possible_values was used<commit_after>// Std
use std::io::Write;

// Internal
use app::App;
use args::{Arg, ArgSettings};
use completions;

pub struct BashGen<'a, 'b>(&'b App<'a, 'b>)
where
    'a: 'b;

impl<'a, 'b> BashGen<'a, 'b> {
    pub fn new(app: &'b App<'a, 'b>) -> Self { BashGen(app) }

    pub fn generate_to<W: Write>(&self, buf: &mut W) {
        w!(
            buf,
            format!(
                "_{name}() {{
    local i cur prev opts cmds
    COMPREPLY=()
    cur=\"${{COMP_WORDS[COMP_CWORD]}}\"
    prev=\"${{COMP_WORDS[COMP_CWORD-1]}}\"
    cmd=\"\"
    opts=\"\"

    for i in ${{COMP_WORDS[@]}}
    do
        case \"${{i}}\" in
            {name})
                cmd=\"{name}\"
                ;;
            {subcmds}
            *)
                ;;
        esac
    done

    case \"${{cmd}}\" in
        {name})
            opts=\"{name_opts}\"
            if [[ ${{cur}} == -* || ${{COMP_CWORD}} -eq 1 ]] ; then
                COMPREPLY=( $(compgen -W \"${{opts}}\" -- ${{cur}}) )
                return 0
            fi
            case \"${{prev}}\" in
                {name_opts_details}
                *)
                    COMPREPLY=()
                    ;;
            esac
            COMPREPLY=( $(compgen -W \"${{opts}}\" -- ${{cur}}) )
            return 0
            ;;
        {subcmd_details}
    esac
}}

complete -F _{name} -o bashdefault -o default {name}
",
                name = self.0.bin_name.as_ref().unwrap(),
                name_opts = self.all_options_for_path(self.0.bin_name.as_ref().unwrap()),
                name_opts_details = self.option_details_for_path(self.0.bin_name.as_ref().unwrap()),
                subcmds = self.all_subcommands(),
                subcmd_details = self.subcommand_details()
            ).as_bytes()
        );
    }

    fn all_subcommands(&self) -> String {
        debugln!("BashGen::all_subcommands;");
        let mut subcmds = String::new();
        let scs = completions::all_subcommand_names(self.0);

        for sc in &scs {
            subcmds = format!(
                "{}
            {name})
                cmd+=\"__{fn_name}\"
                ;;",
                subcmds,
                name = sc,
                fn_name = sc.replace("-", "__")
            );
        }

        subcmds
    }

    fn subcommand_details(&self) -> String {
        debugln!("BashGen::subcommand_details;");
        let mut subcmd_dets = String::new();
        let mut scs = completions::get_all_subcommand_paths(self.0, true);
        scs.sort();
        scs.dedup();

        for sc in &scs {
            subcmd_dets = format!(
                "{}
        {subcmd})
            opts=\"{sc_opts}\"
            if [[ ${{cur}} == -* || ${{COMP_CWORD}} -eq {level} ]] ; then
                COMPREPLY=( $(compgen -W \"${{opts}}\" -- ${{cur}}) )
                return 0
            fi
            case \"${{prev}}\" in
                {opts_details}
                *)
                    COMPREPLY=()
                    ;;
            esac
            COMPREPLY=( $(compgen -W \"${{opts}}\" -- ${{cur}}) )
            return 0
            ;;",
                subcmd_dets,
                subcmd = sc.replace("-", "__"),
                sc_opts = self.all_options_for_path(&*sc),
                level = sc.split("__").map(|_| 1).fold(0, |acc, n| acc + n),
                opts_details = self.option_details_for_path(&*sc)
            );
        }

        subcmd_dets
    }

    fn option_details_for_path(&self, path: &str) -> String {
        debugln!("BashGen::option_details_for_path: path={}", path);
        let mut p = self.0;
        for sc in path.split("__").skip(1) {
            debugln!("BashGen::option_details_for_path:iter: sc={}", sc);
            p = &find_subcmd!(p, sc).unwrap();
        }
        let mut opts = String::new();
        for o in opts!(p) {
            if let Some(l) = o.long {
                opts = format!(
                    "{}
                --{})
                    COMPREPLY=({})
                    return 0
                    ;;",
                    opts,
                    l,
                    self.vals_for(o)
                );
            }
            if let Some(s) = o.short {
                opts = format!(
                    "{}
                    -{})
                    COMPREPLY=({})
                    return 0
                    ;;",
                    opts,
                    s,
                    self.vals_for(o)
                );
            }
        }
        opts
    }

    fn vals_for(&self, o: &Arg) -> String {
        debugln!("BashGen::vals_for: o={}", o.name);
        if let Some(ref vals) = o.possible_vals {
            format!("$(compgen -W \"{}\" -- ${{cur}})", vals.join(" "))
        } else {
            String::from("$(compgen -f ${cur})")
        }
    }

    fn all_options_for_path(&self, path: &str) -> String {
        debugln!("BashGen::all_options_for_path: path={}", path);
        let mut p = self.0;
        for sc in path.split("__").skip(1) {
            debugln!("BashGen::all_options_for_path:iter: sc={}", sc);
            p = &find_subcmd!(p, sc).unwrap();
        }
        let opts = format!(
            "{shorts} {longs} {pos} {subcmds}",
            shorts = shorts!(p).fold(String::new(), |acc, s| format!("{} -{}", acc, s)),
            // Handles aliases too
            longs = longs!(p).fold(String::new(), |acc, l| format!("{} --{}", acc, l)),
            pos = positionals!(p).fold(String::new(), |acc, p| format!("{} {}", acc, p)),
            // Handles aliases too
            subcmds = sc_names!(p).fold(String::new(), |acc, s| format!("{} {}", acc, s))
        );
        opts
    }
}
<|endoftext|>


<commit_before>extern mod std;
use std::hashmap::HashMap;
use sexpr;

// A very simple LISP-like language
// Globally scoped, no closures

/// Our value types
#[deriving(Clone)]
pub enum LispValue {
	List(~[LispValue]),
	Atom(~str),
	Str(~str),
	Num(float),
	Fn(~[~str], ~LispValue), // args, body
	BIF(~str, ~[~str], extern fn(@mut HashMap<~str, ~LispValue>, ~[~LispValue])->~LispValue) // built-in function (args, closure)
}

// XXX: this is ugly but it won't automatically derive Eq because of the extern fn
impl Eq for LispValue {
	fn eq(&self, other: &LispValue) -> bool {
		match (self.clone(), other.clone()) {
			(BIF(ref x, _, _), BIF(ref y, _, _)) if *x == *y => true,
			(Str(ref x), Str(ref y)) if *x == *y => true,
			(Num(ref x), Num(ref y)) if *x == *y => true,
			(Atom(ref x), Atom(ref y)) if *x == *y => true,
			(List(ref x), List(ref y)) if *x == *y => true,
			(Fn(ref x, ref x2), Fn(ref y, ref y2)) if *x == *y && *x2 == *y2 => true,
			_ => false
		}
	}
}

fn from_sexpr(sexpr: &sexpr::Value) -> ~LispValue {
	match *sexpr {
		sexpr::List(ref v) => ~List(v.map(|x| *from_sexpr(x))),
		sexpr::Num(v) => ~Num(v),
		sexpr::Str(ref v) => ~Str(v.clone()),
		sexpr::Atom(ref v) => ~Atom(v.clone())
	}
}

/// The type of the global symbol table (string to a value mapping).
type SymbolTable = HashMap<~str, ~LispValue>;

/// Returns a value representing the empty list
#[inline]
pub fn nil() -> ~LispValue {
	~List(~[])
}

/// Creates a new symbol table and returns it
pub fn new_symt() -> SymbolTable {
	HashMap::new()
}

/// Binds a symbol in the symbol table. Replaces if it already exists.
pub fn bind(symt: @mut SymbolTable, name: ~str, value: ~LispValue) {
	symt.insert(name, value);
}

/// Look up a symbol in the symbol table. Fails if not found.
pub fn lookup(symt: @mut SymbolTable, name: ~str) -> ~LispValue {
	match symt.find(&name) {
		Some(v) => v.clone(),
		None => fail!("couldn't find symbol: %s", name)
	}
}

/// Identity function
fn id_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue { v[0] }

fn cons_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue {
	match v {
		[~a, ~b, .._] => ~List(~[a, b]),
		_ => fail!("cons: requires two arguments")
	}
}

fn car_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue {
	match v[0] {
		~List(v_) => ~v_[0],
		_ => fail!("car: need a list")
	}
}

fn cdr_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue {
	match v[0] {
		~List(v_) => ~v_[1],
		_ => fail!("cdr: need a list")
	}
}

// Print function
fn print_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue {
	match v[0] {
		~Str(s) => printfln!("%s", s),
		_ => fail!("print takes an str")
	}
	nil()
}

/// Initializes standard library functions
pub fn init_std(symt: @mut SymbolTable) {
	bind(symt, ~"id", ~BIF(~"id", ~[~"x"], id_));
	bind(symt, ~"print", ~BIF(~"print", ~[~"msg"], print_));
	bind(symt, ~"cons", ~BIF(~"cons", ~[~"x", ~"y"], cons_));
	bind(symt, ~"car", ~BIF(~"car", ~[~"x"], car_));
	bind(symt, ~"cdr", ~BIF(~"cdr", ~[~"x"], cdr_));
}

fn apply(symt: @mut SymbolTable, f: ~LispValue, args: ~[~LispValue]) -> ~LispValue {
	match *f {
		BIF(name, fnargs, bif) => {
			// apply built-in function
			if fnargs.len() != args.len() {
				fail!("function '%s' requires %u arguments, but it received %u arguments",
					name, fnargs.len(), args.len())
			}

			bif(symt, args)
		}

		_ => fail!("apply: need function")
	}
}

/// Evaluates an s-expression and returns a value.
pub fn eval(symt: @mut SymbolTable, input: sexpr::Value) -> ~LispValue {
	match input {
		sexpr::List(v) => {
			if(v.len() == 0) {
				fail!("eval given empty list")
			}

			// evaluate a list as a function call
			match v {
				[sexpr::Atom(sym), ..args] => {
					let f = lookup(symt, sym);
					let xargs = args.map(|x| eval(symt, x.clone())); // eval'd args
					apply(symt, f, xargs)
				}
				_ => fail!("function calls take an atom"),
			}

		}
		_ => from_sexpr(&input) // return non-list values as they are
	}
}

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

	fn read(input: &str) -> sexpr::Value {
		from_str(input).unwrap()
	}

	#[test]
	fn test_eval() {
		let symt = @mut new_symt();
		init_std(symt);
		assert_eq!(eval(symt, read("123")), ~Num(123.0));
		assert_eq!(eval(symt, read("(id 123)")), ~Num(123.0));
		assert_eq!(eval(symt, read("(id (id (id 123)))")), ~Num(123.0));
		// should fail: assert_eq!(eval(&mut symt, read("(1 2 3)")), ~List(~[Num(1.0), Num(2.0), Num(3.0)]));
	}

	#[test]
	fn test_cons() {
		let symt = @mut new_symt();
		init_std(symt);
		assert_eq!(eval(symt, read("(cons 1 2)")), ~List(~[Num(1.0), Num(2.0)]));
		assert_eq!(eval(symt, read("(cons 1 (cons 2 3))")), ~List(~[Num(1.0),
			List(~[Num(2.0), Num(3.0)])]));
	}

	#[test]
	fn test_car() {
		let symt = @mut new_symt();
		init_std(symt);
		assert_eq!(eval(symt, read("(car (cons 1 2))")), ~Num(1.0));
	}

	#[test]
	fn test_cdr() {
		let symt = @mut new_symt();
		init_std(symt);
		assert_eq!(eval(symt, read("(cdr (cons 1 2))")), ~Num(2.0));
		assert_eq!(eval(symt, read("(cdr (cons 1 (cons 2 3)))")), ~List(~[Num(2.0), Num(3.0)]));
	}
}<commit_msg>add simple string test<commit_after>extern mod std;
use std::hashmap::HashMap;
use sexpr;

// A very simple LISP-like language
// Globally scoped, no closures

/// Our value types
#[deriving(Clone)]
pub enum LispValue {
	List(~[LispValue]),
	Atom(~str),
	Str(~str),
	Num(float),
	Fn(~[~str], ~LispValue), // args, body
	BIF(~str, ~[~str], extern fn(@mut HashMap<~str, ~LispValue>, ~[~LispValue])->~LispValue) // built-in function (args, closure)
}

// XXX: this is ugly but it won't automatically derive Eq because of the extern fn
impl Eq for LispValue {
	fn eq(&self, other: &LispValue) -> bool {
		match (self.clone(), other.clone()) {
			(BIF(ref x, _, _), BIF(ref y, _, _)) if *x == *y => true,
			(Str(ref x), Str(ref y)) if *x == *y => true,
			(Num(ref x), Num(ref y)) if *x == *y => true,
			(Atom(ref x), Atom(ref y)) if *x == *y => true,
			(List(ref x), List(ref y)) if *x == *y => true,
			(Fn(ref x, ref x2), Fn(ref y, ref y2)) if *x == *y && *x2 == *y2 => true,
			_ => false
		}
	}
}

fn from_sexpr(sexpr: &sexpr::Value) -> ~LispValue {
	match *sexpr {
		sexpr::List(ref v) => ~List(v.map(|x| *from_sexpr(x))),
		sexpr::Num(v) => ~Num(v),
		sexpr::Str(ref v) => ~Str(v.clone()),
		sexpr::Atom(ref v) => ~Atom(v.clone())
	}
}

/// The type of the global symbol table (string to a value mapping).
type SymbolTable = HashMap<~str, ~LispValue>;

/// Returns a value representing the empty list
#[inline]
pub fn nil() -> ~LispValue {
	~List(~[])
}

/// Creates a new symbol table and returns it
pub fn new_symt() -> SymbolTable {
	HashMap::new()
}

/// Binds a symbol in the symbol table. Replaces if it already exists.
pub fn bind(symt: @mut SymbolTable, name: ~str, value: ~LispValue) {
	symt.insert(name, value);
}

/// Look up a symbol in the symbol table. Fails if not found.
pub fn lookup(symt: @mut SymbolTable, name: ~str) -> ~LispValue {
	match symt.find(&name) {
		Some(v) => v.clone(),
		None => fail!("couldn't find symbol: %s", name)
	}
}

/// Identity function
fn id_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue { v[0] }

fn cons_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue {
	match v {
		[~a, ~b, .._] => ~List(~[a, b]),
		_ => fail!("cons: requires two arguments")
	}
}

fn car_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue {
	match v[0] {
		~List(v_) => ~v_[0],
		_ => fail!("car: need a list")
	}
}

fn cdr_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue {
	match v[0] {
		~List(v_) => ~v_[1],
		_ => fail!("cdr: need a list")
	}
}

// Print function
fn print_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue {
	match v[0] {
		~Str(s) => printfln!("%s", s),
		_ => fail!("print takes an str")
	}
	nil()
}

/// Initializes standard library functions
pub fn init_std(symt: @mut SymbolTable) {
	bind(symt, ~"id", ~BIF(~"id", ~[~"x"], id_));
	bind(symt, ~"print", ~BIF(~"print", ~[~"msg"], print_));
	bind(symt, ~"cons", ~BIF(~"cons", ~[~"x", ~"y"], cons_));
	bind(symt, ~"car", ~BIF(~"car", ~[~"x"], car_));
	bind(symt, ~"cdr", ~BIF(~"cdr", ~[~"x"], cdr_));
}

fn apply(symt: @mut SymbolTable, f: ~LispValue, args: ~[~LispValue]) -> ~LispValue {
	match *f {
		BIF(name, fnargs, bif) => {
			// apply built-in function
			if fnargs.len() != args.len() {
				fail!("function '%s' requires %u arguments, but it received %u arguments",
					name, fnargs.len(), args.len())
			}

			bif(symt, args)
		}

		_ => fail!("apply: need function")
	}
}

/// Evaluates an s-expression and returns a value.
pub fn eval(symt: @mut SymbolTable, input: sexpr::Value) -> ~LispValue {
	match input {
		sexpr::List(v) => {
			if(v.len() == 0) {
				fail!("eval given empty list")
			}

			// evaluate a list as a function call
			match v {
				[sexpr::Atom(sym), ..args] => {
					let f = lookup(symt, sym);
					let xargs = args.map(|x| eval(symt, x.clone())); // eval'd args
					apply(symt, f, xargs)
				}
				_ => fail!("function calls take an atom"),
			}

		}
		_ => from_sexpr(&input) // return non-list values as they are
	}
}

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

	fn read(input: &str) -> sexpr::Value {
		from_str(input).unwrap()
	}

	#[test]
	fn test_eval() {
		let symt = @mut new_symt();
		init_std(symt);
		assert_eq!(eval(symt, read("123")), ~Num(123.0));
		assert_eq!(eval(symt, read("(id 123)")), ~Num(123.0));
		assert_eq!(eval(symt, read("(id (id (id 123)))")), ~Num(123.0));
		// should fail: assert_eq!(eval(&mut symt, read("(1 2 3)")), ~List(~[Num(1.0), Num(2.0), Num(3.0)]));
	}

	#[test]
	fn test_str() {
		let symt = @mut new_symt();
		init_std(symt);
		assert_eq!(eval(symt, read("(id \"hi\")")), ~Str(~"hi"));
		assert_eq!(eval(symt, read("(car (cons \"a\" \"b\"))")), ~Str(~"a"));
	}

	#[test]
	fn test_cons() {
		let symt = @mut new_symt();
		init_std(symt);
		assert_eq!(eval(symt, read("(cons 1 2)")), ~List(~[Num(1.0), Num(2.0)]));
		assert_eq!(eval(symt, read("(cons 1 (cons 2 3))")), ~List(~[Num(1.0),
			List(~[Num(2.0), Num(3.0)])]));
	}

	#[test]
	fn test_car() {
		let symt = @mut new_symt();
		init_std(symt);
		assert_eq!(eval(symt, read("(car (cons 1 2))")), ~Num(1.0));
	}

	#[test]
	fn test_cdr() {
		let symt = @mut new_symt();
		init_std(symt);
		assert_eq!(eval(symt, read("(cdr (cons 1 2))")), ~Num(2.0));
		assert_eq!(eval(symt, read("(cdr (cons 1 (cons 2 3)))")), ~List(~[Num(2.0), Num(3.0)]));
	}
}<|endoftext|>


<commit_before>
use std::fs::File;
use std::io::{self, BufRead};
use regex::Regex;

#[macro_use]
extern crate lazy_static;

pub fn get_number(filename: &str) -> io::Result<u32> {
    lazy_static! {
        static ref RE: Regex = Regex::new(r"NUMBER=(\d+)").unwrap();
    }
    let mut matches = match_lines(filename, &*RE)?;
    return Ok(matches.next().unwrap().parse().unwrap());
}

pub fn get_output(filename: &str) -> io::Result<impl Iterator<Item = u32>> {
    lazy_static! {
        static ref RE: Regex = Regex::new(r"OUTPUT:(.*)").unwrap();
    }
    get_numbers(filename, &*RE)
}

pub fn get_collection(filename: &str, idx: u32) -> io::Result<impl Iterator<Item = u32>> {
    let regex: Regex = {
        let r = format!("COLLECTION{}:(.*)", idx);
        Regex::new(&r).unwrap()
    };
    get_numbers(filename, &regex)
}

pub fn get_numbers(filename: &str, regex: &Regex) -> io::Result<impl Iterator<Item = u32>> {
    let matches = match_lines(filename, regex)?;
    let values = matches.map(|s| {
        let numbers = s.split(',').map(|v| v.parse::<u32>().unwrap());
        numbers.collect::<Vec<_>>()
    }).flatten();
    Ok(values)
}

fn match_lines(filename: &str, regex: &Regex) -> io::Result<impl Iterator<Item = String>> {
    let read_lines = move || -> io::Result<_> {
        let file = File::open(filename)?;
        Ok(io::BufReader::new(file).lines().map(|line|
            line.unwrap()))
    };
    let lines = read_lines()?;
    let r = regex.clone(); // TODO
    let matches = lines.filter_map(move |line| {
        r.captures(&line).map(|captures|
            captures[1].to_string()
        )
    });
    Ok(matches)
}

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

    #[test]
    fn test_number() {
        assert_eq!(get_number("../data/test.txt").unwrap() , 3);
    }

    #[test]
    fn test_output() {
        let output = [1,1,2,2,3,4,4,6,7,9,9,20,21];
        assert_eq!(get_output("../data/test.txt").unwrap().collect::<Vec<_>>(), output);
    }

    #[test]
    fn test_collection() {
        let output = [2, 4, 6, 9, 20];
        assert_eq!(get_collection("../data/test.txt", 1).unwrap().collect::<Vec<_>>(), output);
    }
}
<commit_msg>implemented merge<commit_after>
use std::fs::File;
use std::io::{self, BufRead};
use regex::Regex;

#[macro_use]
extern crate lazy_static;

struct State<T>(Box<dyn Iterator<Item = T>>, Option<T>);
pub struct Merge {
    count: usize,
    states: Vec<State<u32>>
}

impl Merge {
    pub fn new(filename: &str) -> Self {
        let count = get_number(filename).unwrap();
        let mut states: Vec<State<u32>> = Vec::with_capacity(count);
        for i in 0..count {
            let collection = Box::new(get_collection(filename, i).unwrap());
            let state = State(collection, None);
            states.push(state);
        }
        Merge{count: count, states: states}
    }
}

impl Iterator for Merge  {
    type Item = u32;
    fn next(&mut self) -> Option<Self::Item> {
        let count = self.count;
        let states = &mut self.states;
        loop {
            for i in 0..count {
                let mut state = &mut states[i];
                if state.1.is_none() {
                    state.1 = state.0.next();
                }
            }
            let not_done = states.iter().any(|s| s.1.is_some());
            if !not_done {
                return None;
            }

            let mut min = u32::MAX;
            let mut min_index = usize::MIN;
            for i in 0..count {
                let state = &mut states[i];
                if let Some(val) = state.1 {
                    if val < min {
                        min = val;
                        min_index = i;
                    }
                }
            }
            states[min_index].1 = None;
            return Some(min);
        }
    }
}

pub fn get_number(filename: &str) -> io::Result<usize> {
    lazy_static! {
        static ref RE: Regex = Regex::new(r"NUMBER=(\d+)").unwrap();
    }
    let mut matches = match_lines(filename, &*RE)?;
    return Ok(matches.next().unwrap().parse().unwrap());
}

pub fn get_output(filename: &str) -> io::Result<impl Iterator<Item = u32>> {
    lazy_static! {
        static ref RE: Regex = Regex::new(r"OUTPUT:(.*)").unwrap();
    }
    get_numbers(filename, &*RE)
}

pub fn get_collection(filename: &str, idx: usize) -> io::Result<impl Iterator<Item = u32>> {
    let regex: Regex = {
        let r = format!("COLLECTION{}:(.*)", idx);
        Regex::new(&r).unwrap()
    };
    get_numbers(filename, &regex)
}

fn get_numbers(filename: &str, regex: &Regex) -> io::Result<impl Iterator<Item = u32>> {
    let matches = match_lines(filename, regex)?;
    let values = matches.map(|s| {
        let numbers = s.split(',').map(|v| v.parse::<u32>().unwrap());
        numbers.collect::<Vec<_>>()
    }).flatten();
    Ok(values)
}

fn match_lines(filename: &str, regex: &Regex) -> io::Result<impl Iterator<Item = String>> {
    let read_lines = move || -> io::Result<_> {
        let file = File::open(filename)?;
        Ok(io::BufReader::new(file).lines().map(|line|
            line.unwrap()))
    };
    let lines = read_lines()?;
    let r = regex.clone(); // TODO
    let matches = lines.filter_map(move |line| {
        r.captures(&line).map(|captures|
            captures[1].to_string()
        )
    });
    Ok(matches)
}

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

    #[test]
    fn test_number() {
        assert_eq!(get_number("../data/test.txt").unwrap() , 3);
    }

    #[test]
    fn test_output() {
        let output = [1,1,2,2,3,4,4,6,7,9,9,20,21];
        assert_eq!(get_output("../data/test.txt").unwrap().collect::<Vec<_>>(), output);
    }

    #[test]
    fn test_collection() {
        let output = [2, 4, 6, 9, 20];
        assert_eq!(get_collection("../data/test.txt", 1).unwrap().collect::<Vec<_>>(), output);
    }

    #[test]
    fn test_merge() {
        let file_name = "../data/test.txt";
        let result = Merge::new(file_name).collect::<Vec<u32>>();
        let output = get_output(file_name).unwrap().collect::<Vec<u32>>();
        assert_eq!(result, output);
    }
}
<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

use std::str;

use bytes::{BufMut, BytesMut};

use super::buffer::Buffer;

pub struct List<T> {
    pub data: Buffer<T>,
    pub offsets: Buffer<i32>,
}

impl<T> List<T> {
    pub fn len(&self) -> i32 {
        self.offsets.len() - 1
    }

    pub fn slice(&self, index: usize) -> &[T] {
        let start = *self.offsets.get(index) as usize;
        let end = *self.offsets.get(index + 1) as usize;
        &self.data.slice(start, end)
    }
}

impl From<Vec<String>> for List<u8> {
    fn from(v: Vec<String>) -> Self {
        let mut offsets: Vec<i32> = Vec::with_capacity(v.len() + 1);
        let mut buf = BytesMut::with_capacity(v.len() * 32);
        offsets.push(0_i32);
        v.iter().for_each(|s| {
            buf.put(s.as_bytes());
            offsets.push(buf.len() as i32);
        });
        List {
            data: Buffer::from(buf.freeze()),
            offsets: Buffer::from(offsets),
        }
    }
}

/// This method mostly just used for unit tests
impl From<Vec<&'static str>> for List<u8> {
    fn from(v: Vec<&'static str>) -> Self {
        List::from(v.iter().map(|s| s.to_string()).collect::<Vec<String>>())
    }
}

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

    #[test]
    fn test_utf8_slices() {
        let list = List::from(vec!["this", "is", "a", "test"]);
        assert_eq!(4, list.len());
        assert_eq!("this", str::from_utf8(list.slice(0)).unwrap());
        assert_eq!("is", str::from_utf8(list.slice(1)).unwrap());
        assert_eq!("a", str::from_utf8(list.slice(2)).unwrap());
        assert_eq!("test", str::from_utf8(list.slice(3)).unwrap());
    }

}
<commit_msg>ARROW-2418: [Rust] BUG FIX: reserve memory when building list<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

use std::str;

use bytes::{BufMut, BytesMut};

use super::buffer::Buffer;

pub struct List<T> {
    pub data: Buffer<T>,
    pub offsets: Buffer<i32>,
}

impl<T> List<T> {
    pub fn len(&self) -> i32 {
        self.offsets.len() - 1
    }

    pub fn slice(&self, index: usize) -> &[T] {
        let start = *self.offsets.get(index) as usize;
        let end = *self.offsets.get(index + 1) as usize;
        &self.data.slice(start, end)
    }
}

impl From<Vec<String>> for List<u8> {
    fn from(v: Vec<String>) -> Self {
        let mut offsets: Vec<i32> = Vec::with_capacity(v.len() + 1);
        let mut buf = BytesMut::with_capacity(v.len() * 32);
        offsets.push(0_i32);
        v.iter().for_each(|s| {
            let slice = s.as_bytes();
            buf.reserve(slice.len());
            buf.put(slice);
            offsets.push(buf.len() as i32);
        });
        List {
            data: Buffer::from(buf.freeze()),
            offsets: Buffer::from(offsets),
        }
    }
}

/// This method mostly just used for unit tests
impl From<Vec<&'static str>> for List<u8> {
    fn from(v: Vec<&'static str>) -> Self {
        List::from(v.iter().map(|s| s.to_string()).collect::<Vec<String>>())
    }
}

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

    #[test]
    fn test_utf8_slices() {
        let list = List::from(vec!["this", "is", "a", "test"]);
        assert_eq!(4, list.len());
        assert_eq!("this", str::from_utf8(list.slice(0)).unwrap());
        assert_eq!("is", str::from_utf8(list.slice(1)).unwrap());
        assert_eq!("a", str::from_utf8(list.slice(2)).unwrap());
        assert_eq!("test", str::from_utf8(list.slice(3)).unwrap());
    }

}
<|endoftext|>


<commit_before>
const ROW_SIZE: usize = 9;

#[derive(Debug)]
struct Board([[u32; ROW_SIZE]; ROW_SIZE]);

impl Board {
    fn from_str(sudoku: &str) -> Board {
        let mut board = [[0; ROW_SIZE]; ROW_SIZE];
        let mut row = 0;
        let mut col = 0;
        for c in sudoku.chars() {
            board[row][col] = c.to_digit(10).unwrap();
            col += 1;
            if col == ROW_SIZE {
                col = 0;
                row += 1;
            }
        }
        Board(board)
    }
}

fn main() {
    let sudoku_example = "200000060000075030048090100000300000300010009000008000001020570080730000090000004";
    let board = Board::from_str(sudoku_example);
    println!("{:?}", board)
}

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

//     #[test]
//     fn read_sudoku_string_to_struct() {
//         let sudoku_example = "200000060000075030048090100000300000300010009000008000001020570080730000090000004";
//         println!("{:?}", board)
//     }
// }
<commit_msg>add formatted display for Sudoku struct<commit_after>use std::fmt;

const ROW_SIZE: usize = 9;

#[derive(Debug)]
struct Sudoku([[u32; ROW_SIZE]; ROW_SIZE]);

impl Sudoku {
    fn from_str(sudoku: &str) -> Sudoku {
        let mut board = [[0; ROW_SIZE]; ROW_SIZE];
    let mut row = 0;
    let mut col = 0;
    for c in sudoku.chars() {
        board[row][col] = c.to_digit(10).unwrap();
        col += 1;
        if col == ROW_SIZE {
            col = 0;
            row += 1;
        }
    }
    Sudoku(board)
    }
}

impl fmt::Display for Sudoku {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut s: String = String::new();
        for row in self.0.iter() {
            s.push_str(
                &row.iter().map(|&x| x.to_string()).collect::<Vec<String>>().join(" "));
            s.push_str("\n");
        }
        write!(f, "{}", s)
    }
}

fn main() {
    let sudoku_example = "200000060000075030048090100000300000300010009000008000001020570080730000090000004";
    let board = Sudoku::from_str(sudoku_example);
    println!("{}", board)
}

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

//     #[test]
//     fn read_sudoku_string_to_struct() {
//         let sudoku_example = "200000060000075030048090100000300000300010009000008000001020570080730000090000004";
//         println!("{:?}", board)
//     }
// }
<|endoftext|>


<commit_before>// This file is part of the uutils coreutils package.
//
// (c) Derek Chiang <derekchiang93@gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

#[macro_use]
extern crate uucore;

use clap::{crate_version, App, Arg};
use std::path::Path;
use uucore::error::{UResult, USimpleError};
use uucore::InvalidEncodingHandling;

static ABOUT: &str = "strip last component from file name";

mod options {
    pub const ZERO: &str = "zero";
    pub const DIR: &str = "dir";
}

fn get_usage() -> String {
    format!("{0} [OPTION] NAME...", executable!())
}

fn get_long_usage() -> String {
    String::from(
        "Output each NAME with its last non-slash component and trailing slashes
        removed; if NAME contains no /'s, output '.' (meaning the current directory).",
    )
}

#[uucore_procs::gen_uumain]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    let args = args
        .collect_str(InvalidEncodingHandling::ConvertLossy)
        .accept_any();

    let usage = get_usage();
    let after_help = get_long_usage();

    let matches = uu_app()
        .usage(&usage[..])
        .after_help(&after_help[..])
        .get_matches_from(args);

    let separator = if matches.is_present(options::ZERO) {
        "\0"
    } else {
        "\n"
    };

    let dirnames: Vec<String> = matches
        .values_of(options::DIR)
        .unwrap_or_default()
        .map(str::to_owned)
        .collect();

    if !dirnames.is_empty() {
        for path in dirnames.iter() {
            let p = Path::new(path);
            match p.parent() {
                Some(d) => {
                    if d.components().next() == None {
                        print!(".")
                    } else {
                        print!("{}", d.to_string_lossy());
                    }
                }
                None => {
                    if p.is_absolute() || path == "/" {
                        print!("/");
                    } else {
                        print!(".");
                    }
                }
            }
            print!("{}", separator);
        }
    } else {
        return Err(UUsageError::new(1, "missing operand".to_string()));
    }

    Ok(())
}

pub fn uu_app() -> App<'static, 'static> {
    App::new(executable!())
        .about(ABOUT)
        .version(crate_version!())
        .arg(
            Arg::with_name(options::ZERO)
                .long(options::ZERO)
                .short("z")
                .help("separate output with NUL rather than newline"),
        )
        .arg(Arg::with_name(options::DIR).hidden(true).multiple(true))
}
<commit_msg>imported UUsageError<commit_after>// This file is part of the uutils coreutils package.
//
// (c) Derek Chiang <derekchiang93@gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

#[macro_use]
extern crate uucore;

use clap::{crate_version, App, Arg};
use std::path::Path;
use uucore::error::{UResult, UUsageError};
use uucore::InvalidEncodingHandling;

static ABOUT: &str = "strip last component from file name";

mod options {
    pub const ZERO: &str = "zero";
    pub const DIR: &str = "dir";
}

fn get_usage() -> String {
    format!("{0} [OPTION] NAME...", executable!())
}

fn get_long_usage() -> String {
    String::from(
        "Output each NAME with its last non-slash component and trailing slashes
        removed; if NAME contains no /'s, output '.' (meaning the current directory).",
    )
}

#[uucore_procs::gen_uumain]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    let args = args
        .collect_str(InvalidEncodingHandling::ConvertLossy)
        .accept_any();

    let usage = get_usage();
    let after_help = get_long_usage();

    let matches = uu_app()
        .usage(&usage[..])
        .after_help(&after_help[..])
        .get_matches_from(args);

    let separator = if matches.is_present(options::ZERO) {
        "\0"
    } else {
        "\n"
    };

    let dirnames: Vec<String> = matches
        .values_of(options::DIR)
        .unwrap_or_default()
        .map(str::to_owned)
        .collect();

    if !dirnames.is_empty() {
        for path in dirnames.iter() {
            let p = Path::new(path);
            match p.parent() {
                Some(d) => {
                    if d.components().next() == None {
                        print!(".")
                    } else {
                        print!("{}", d.to_string_lossy());
                    }
                }
                None => {
                    if p.is_absolute() || path == "/" {
                        print!("/");
                    } else {
                        print!(".");
                    }
                }
            }
            print!("{}", separator);
        }
    } else {
        return Err(UUsageError::new(1, "missing operand".to_string()));
    }

    Ok(())
}

pub fn uu_app() -> App<'static, 'static> {
    App::new(executable!())
        .about(ABOUT)
        .version(crate_version!())
        .arg(
            Arg::with_name(options::ZERO)
                .long(options::ZERO)
                .short("z")
                .help("separate output with NUL rather than newline"),
        )
        .arg(Arg::with_name(options::DIR).hidden(true).multiple(true))
}
<|endoftext|>