<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use engine::Engine;
use engine::EngineError;
use engine::EngineResult;
use engine::ErrorEnum;

use engine::Pool;
use engine::RenameAction;
use engine::Redundancy;

use std::cell::RefCell;
use std::collections::BTreeMap;
use std::collections::btree_map::Entry;
use std::collections::BTreeSet;
use std::iter::FromIterator;
use std::path::Path;
use std::path::PathBuf;
use std::rc::Rc;

use super::pool::SimPool;
use super::randomization::Randomizer;

#[derive(Debug)]
pub struct SimEngine {
    pools: BTreeMap<String, SimPool>,
    rdm: Rc<RefCell<Randomizer>>,
}

impl SimEngine {
    pub fn new() -> SimEngine {
        SimEngine {
            pools: BTreeMap::new(),
            rdm: Rc::new(RefCell::new(Randomizer::new())),
        }
    }
}

impl Engine for SimEngine {
    fn create_pool(&mut self,
                   name: &str,
                   blockdev_paths: &[&Path],
                   redundancy: Option<u16>,
                   _force: bool)
                   -> EngineResult<Vec<PathBuf>> {

        let redundancy = calculate_redundancy!(redundancy);

        if self.pools.contains_key(name) {
            return Err(EngineError::Engine(ErrorEnum::AlreadyExists, name.into()));
        }

        let devices =
            BTreeSet::from_iter(blockdev_paths).into_iter().map(|x| *x).collect::<Vec<&Path>>();

        let pool = SimPool::new(self.rdm.clone(), &devices, redundancy);

        if self.rdm.borrow_mut().throw_die() {
            return Err(EngineError::Engine(ErrorEnum::Error, "X".into()));
        }

        let bdev_paths = pool.block_devs.values().map(|p| p.devnode.clone()).collect();
        self.pools.insert(name.to_owned(), pool);

        Ok(bdev_paths)
    }

    fn destroy_pool(&mut self, name: &str) -> EngineResult<bool> {
        destroy_pool!{self; name}
    }

    fn rename_pool(&mut self, old_name: &str, new_name: &str) -> EngineResult<RenameAction> {
        rename_pool!{self; old_name; new_name}
    }

    /// Looks up the pool by its unique name
    fn get_pool(&mut self, name: &str) -> EngineResult<&mut Pool> {
        get_pool!(self; name)
    }

    /// Returns a collection of the Pool objects that belong to this engine
    fn pools(&mut self) -> BTreeMap<&str, &mut Pool> {
        pools!(self)
    }

    /// Set properties of the simulator
    fn configure_simulator(&mut self, denominator: u32) -> EngineResult<()> {
        self.rdm.borrow_mut().set_probability(denominator);
        Ok(())
    }
}

#[cfg(test)]
mod tests {

    use std;
    use std::path::Path;

    use quickcheck::QuickCheck;

    use super::SimEngine;

    use engine::Engine;
    use engine::EngineError;
    use engine::ErrorEnum;
    use engine::RenameAction;

    #[test]
    fn prop_configure_simulator_runs() {

        /// Configure simulator should always return Ok.
        fn configure_simulator_runs(denominator: u32) -> bool {
            SimEngine::new().configure_simulator(denominator).is_ok()
        }

        QuickCheck::new().tests(10).quickcheck(configure_simulator_runs as fn(u32) -> bool);
    }

    #[test]
    /// When an engine has no pools, any name lookup should fail
    fn get_pool_err() {
        assert!(match SimEngine::new().get_pool("name") {
            Err(EngineError::Engine(ErrorEnum::NotFound, _)) => true,
            _ => false,
        });
    }

    #[test]
    /// When an engine has no pools, the thing returned by pools() is empty
    fn pools_empty() {
        assert!(SimEngine::new().pools().is_empty());
    }

    #[test]
    /// When an engine has no pools, destroying any pool must succeed
    fn destroy_pool_empty() {
        assert!(SimEngine::new().destroy_pool("name").is_ok());
    }

    #[test]
    /// Destroying an empty pool should succeed.
    fn destroy_empty_pool() {
        let name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(name, &[], None, false).unwrap();
        assert!(engine.destroy_pool(name).is_ok());
    }

    #[test]
    /// Destroying a pool with devices should succeed
    fn destroy_pool_w_devices() {
        let name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(name, &[Path::new("/s/d")], None, false).unwrap();
        assert!(engine.destroy_pool(name).is_ok());
    }

    #[test]
    #[ignore]
    /// Creating a new pool identical to the previous should succeed
    fn create_new_pool_twice() {
        let name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(name, &[], None, false).unwrap();
        assert!(match engine.create_pool(name, &[], None, false) {
            Ok(devs) => devs.is_empty(),
            Err(_) => false,
        });
    }

    #[test]
    /// Creating a new pool with the same name should fail
    fn create_pool_name_collision() {
        let name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(name, &[Path::new("/s/d")], None, false).unwrap();
        assert!(match engine.create_pool(name, &[], None, false) {
            Err(EngineError::Engine(ErrorEnum::AlreadyExists, _)) => true,
            _ => false,
        });
    }

    #[test]
    /// Creating a pool with duplicate devices should succeed
    fn create_pool_duplicate_devices() {
        let path = "/s/d";
        let mut engine = SimEngine::new();
        let devices = vec![Path::new(path), Path::new(path)];
        assert!(match engine.create_pool("name", &devices, None, false) {
            Ok(devs) => devs.len() == 1,
            _ => false,
        });
    }

    #[test]
    /// Creating a pool with an impossible raid level should fail
    fn create_pool_max_u16_raid() {
        let mut engine = SimEngine::new();
        assert!(engine.create_pool("name", &[], Some(std::u16::MAX), false).is_err());
    }

    #[test]
    /// Renaming a pool on an empty engine always works
    fn rename_empty() {
        let mut engine = SimEngine::new();
        assert!(match engine.rename_pool("old_name", "new_name") {
            Ok(RenameAction::NoSource) => true,
            _ => false,
        });
    }

    #[test]
    /// Renaming a pool to itself in an empty engine always works
    fn rename_empty_identity() {
        let mut engine = SimEngine::new();
        assert!(match engine.rename_pool("old_name", "old_name") {
            Ok(RenameAction::Identity) => true,
            _ => false,
        });
    }

    #[test]
    /// Renaming a pool to itself always works
    fn rename_identity() {
        let name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(name, &[], None, false).unwrap();
        assert!(match engine.rename_pool(name, name) {
            Ok(RenameAction::Identity) => true,
            _ => false,
        });
    }

    #[test]
    /// Renaming a pool to another pool should work if new name not taken
    fn rename_happens() {
        let name = "old_name";
        let mut engine = SimEngine::new();
        engine.create_pool(name, &[], None, false).unwrap();
        assert!(match engine.rename_pool(name, "new_name") {
            Ok(RenameAction::Renamed) => true,
            _ => false,
        });
    }

    #[test]
    /// Renaming a pool to another pool should fail if new name taken
    fn rename_fails() {
        let old_name = "old_name";
        let new_name = "new_name";
        let mut engine = SimEngine::new();
        engine.create_pool(old_name, &[], None, false).unwrap();
        engine.create_pool(new_name, &[], None, false).unwrap();
        assert!(match engine.rename_pool(old_name, new_name) {
            Err(EngineError::Engine(ErrorEnum::AlreadyExists, _)) => true,
            _ => false,
        });
    }

    #[test]
    /// Renaming should succeed if old_name absent, new present
    fn rename_no_op() {
        let old_name = "old_name";
        let new_name = "new_name";
        let mut engine = SimEngine::new();
        engine.create_pool(new_name, &[], None, false).unwrap();
        assert!(match engine.rename_pool(old_name, new_name) {
            Ok(RenameAction::NoSource) => true,
            _ => false,
        });
    }

}
<commit_msg>add sim destroy_pool_w_filesystem test<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use engine::Engine;
use engine::EngineError;
use engine::EngineResult;
use engine::ErrorEnum;

use engine::Pool;
use engine::RenameAction;
use engine::Redundancy;

use std::cell::RefCell;
use std::collections::BTreeMap;
use std::collections::btree_map::Entry;
use std::collections::BTreeSet;
use std::iter::FromIterator;
use std::path::Path;
use std::path::PathBuf;
use std::rc::Rc;

use super::pool::SimPool;
use super::randomization::Randomizer;

#[derive(Debug)]
pub struct SimEngine {
    pools: BTreeMap<String, SimPool>,
    rdm: Rc<RefCell<Randomizer>>,
}

impl SimEngine {
    pub fn new() -> SimEngine {
        SimEngine {
            pools: BTreeMap::new(),
            rdm: Rc::new(RefCell::new(Randomizer::new())),
        }
    }
}

impl Engine for SimEngine {
    fn create_pool(&mut self,
                   name: &str,
                   blockdev_paths: &[&Path],
                   redundancy: Option<u16>,
                   _force: bool)
                   -> EngineResult<Vec<PathBuf>> {

        let redundancy = calculate_redundancy!(redundancy);

        if self.pools.contains_key(name) {
            return Err(EngineError::Engine(ErrorEnum::AlreadyExists, name.into()));
        }

        let devices =
            BTreeSet::from_iter(blockdev_paths).into_iter().map(|x| *x).collect::<Vec<&Path>>();

        let pool = SimPool::new(self.rdm.clone(), &devices, redundancy);

        if self.rdm.borrow_mut().throw_die() {
            return Err(EngineError::Engine(ErrorEnum::Error, "X".into()));
        }

        let bdev_paths = pool.block_devs.values().map(|p| p.devnode.clone()).collect();
        self.pools.insert(name.to_owned(), pool);

        Ok(bdev_paths)
    }

    fn destroy_pool(&mut self, name: &str) -> EngineResult<bool> {
        destroy_pool!{self; name}
    }

    fn rename_pool(&mut self, old_name: &str, new_name: &str) -> EngineResult<RenameAction> {
        rename_pool!{self; old_name; new_name}
    }

    /// Looks up the pool by its unique name
    fn get_pool(&mut self, name: &str) -> EngineResult<&mut Pool> {
        get_pool!(self; name)
    }

    /// Returns a collection of the Pool objects that belong to this engine
    fn pools(&mut self) -> BTreeMap<&str, &mut Pool> {
        pools!(self)
    }

    /// Set properties of the simulator
    fn configure_simulator(&mut self, denominator: u32) -> EngineResult<()> {
        self.rdm.borrow_mut().set_probability(denominator);
        Ok(())
    }
}

#[cfg(test)]
mod tests {

    use std;
    use std::path::Path;

    use quickcheck::QuickCheck;

    use super::SimEngine;

    use engine::Engine;
    use engine::EngineError;
    use engine::ErrorEnum;
    use engine::RenameAction;

    #[test]
    fn prop_configure_simulator_runs() {

        /// Configure simulator should always return Ok.
        fn configure_simulator_runs(denominator: u32) -> bool {
            SimEngine::new().configure_simulator(denominator).is_ok()
        }

        QuickCheck::new().tests(10).quickcheck(configure_simulator_runs as fn(u32) -> bool);
    }

    #[test]
    /// When an engine has no pools, any name lookup should fail
    fn get_pool_err() {
        assert!(match SimEngine::new().get_pool("name") {
            Err(EngineError::Engine(ErrorEnum::NotFound, _)) => true,
            _ => false,
        });
    }

    #[test]
    /// When an engine has no pools, the thing returned by pools() is empty
    fn pools_empty() {
        assert!(SimEngine::new().pools().is_empty());
    }

    #[test]
    /// When an engine has no pools, destroying any pool must succeed
    fn destroy_pool_empty() {
        assert!(SimEngine::new().destroy_pool("name").is_ok());
    }

    #[test]
    /// Destroying an empty pool should succeed.
    fn destroy_empty_pool() {
        let name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(name, &[], None, false).unwrap();
        assert!(engine.destroy_pool(name).is_ok());
    }

    #[test]
    /// Destroying a pool with devices should succeed
    fn destroy_pool_w_devices() {
        let name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(name, &[Path::new("/s/d")], None, false).unwrap();
        assert!(engine.destroy_pool(name).is_ok());
    }

    #[test]
    /// Destroying a pool with filesystems should fail
    fn destroy_pool_w_filesystem() {
        let name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(name, &[Path::new("/s/d")], None, false).unwrap();
        {
            let pool = engine.get_pool(name).unwrap();
            pool.create_filesystems(&[("test", "/mnt/temp", None)]).unwrap();
        }
        assert!(engine.destroy_pool(name).is_err());
    }

    #[test]
    #[ignore]
    /// Creating a new pool identical to the previous should succeed
    fn create_new_pool_twice() {
        let name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(name, &[], None, false).unwrap();
        assert!(match engine.create_pool(name, &[], None, false) {
            Ok(devs) => devs.is_empty(),
            Err(_) => false,
        });
    }

    #[test]
    /// Creating a new pool with the same name should fail
    fn create_pool_name_collision() {
        let name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(name, &[Path::new("/s/d")], None, false).unwrap();
        assert!(match engine.create_pool(name, &[], None, false) {
            Err(EngineError::Engine(ErrorEnum::AlreadyExists, _)) => true,
            _ => false,
        });
    }

    #[test]
    /// Creating a pool with duplicate devices should succeed
    fn create_pool_duplicate_devices() {
        let path = "/s/d";
        let mut engine = SimEngine::new();
        let devices = vec![Path::new(path), Path::new(path)];
        assert!(match engine.create_pool("name", &devices, None, false) {
            Ok(devs) => devs.len() == 1,
            _ => false,
        });
    }

    #[test]
    /// Creating a pool with an impossible raid level should fail
    fn create_pool_max_u16_raid() {
        let mut engine = SimEngine::new();
        assert!(engine.create_pool("name", &[], Some(std::u16::MAX), false).is_err());
    }

    #[test]
    /// Renaming a pool on an empty engine always works
    fn rename_empty() {
        let mut engine = SimEngine::new();
        assert!(match engine.rename_pool("old_name", "new_name") {
            Ok(RenameAction::NoSource) => true,
            _ => false,
        });
    }

    #[test]
    /// Renaming a pool to itself in an empty engine always works
    fn rename_empty_identity() {
        let mut engine = SimEngine::new();
        assert!(match engine.rename_pool("old_name", "old_name") {
            Ok(RenameAction::Identity) => true,
            _ => false,
        });
    }

    #[test]
    /// Renaming a pool to itself always works
    fn rename_identity() {
        let name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(name, &[], None, false).unwrap();
        assert!(match engine.rename_pool(name, name) {
            Ok(RenameAction::Identity) => true,
            _ => false,
        });
    }

    #[test]
    /// Renaming a pool to another pool should work if new name not taken
    fn rename_happens() {
        let name = "old_name";
        let mut engine = SimEngine::new();
        engine.create_pool(name, &[], None, false).unwrap();
        assert!(match engine.rename_pool(name, "new_name") {
            Ok(RenameAction::Renamed) => true,
            _ => false,
        });
    }

    #[test]
    /// Renaming a pool to another pool should fail if new name taken
    fn rename_fails() {
        let old_name = "old_name";
        let new_name = "new_name";
        let mut engine = SimEngine::new();
        engine.create_pool(old_name, &[], None, false).unwrap();
        engine.create_pool(new_name, &[], None, false).unwrap();
        assert!(match engine.rename_pool(old_name, new_name) {
            Err(EngineError::Engine(ErrorEnum::AlreadyExists, _)) => true,
            _ => false,
        });
    }

    #[test]
    /// Renaming should succeed if old_name absent, new present
    fn rename_no_op() {
        let old_name = "old_name";
        let new_name = "new_name";
        let mut engine = SimEngine::new();
        engine.create_pool(new_name, &[], None, false).unwrap();
        assert!(match engine.rename_pool(old_name, new_name) {
            Ok(RenameAction::NoSource) => true,
            _ => false,
        });
    }

}
<|endoftext|>


<commit_before>use sdl2;
use sdl2::AudioSubsystem;
use sdl2::EventPump;
use sdl2::event::Event;
use sdl2::render::Renderer;
use sdl2::pixels::Color;
use sdl2::rect::Rect;
use sdl2::image::LoadTexture;
use sdl2::mixer;
use sdl2::mixer::Sdl2MixerContext;
use sdl2::mixer::Channel;
use sdl2::mixer::Chunk;
use OptionAway;
use input_private;
use input::Input;
use game_object::GameObject;
use game_object;
use texture::Texture;
use texture;
use PolarCoords;
use Vector;
use transform::Transform;
use camera::Camera;
use nphysics2d::world::World;
use std::mem::replace;
use std::collections::HashMap;
use std::borrow::Borrow;
use std::path::PathBuf;
use std::f32;
use std::time::Instant;
use chrono::Duration;

pub struct App {
    exit: bool,
    renderer: Renderer<'static>,
    _audio: AudioSubsystem,
    _mixer: Sdl2MixerContext,
    event_pump: EventPump,
    game_objects: HashMap<u64, Option<Box<GameObject>>>,
    next_game_object_id: u64,
    pub input: Input,
    pub camera: Camera,
    pub world: World<f32>,
}

impl App {
    ///Constructs a new App using the given name for the window title.
    pub fn new(name: &str) -> App {
        let sdl_context = sdl2::init().expect("Failed to initialize SDL2.");
        let video_subsystem = sdl_context.video().expect("Failed to initialize video subsystem");
        let window = video_subsystem.window(name, 800, 600)
            .position_centered()
            .fullscreen_desktop()
            .opengl()
            .build()
            .unwrap();
        let renderer = window.renderer().build().expect("Failed to initialize renderer");
        let audio = sdl_context.audio().expect("Failed to initialize audio");
        let mixer = mixer::init(mixer::INIT_OGG).expect("Failed to initialize mixer");
        mixer::open_audio(mixer::DEFAULT_FREQUENCY, mixer::DEFAULT_FORMAT, 2, 1024)
            .expect("Failed to open audio");
        App {
            exit: false,
            next_game_object_id: 0,
            game_objects: HashMap::new(),
            input: Input::new(),
            renderer: renderer,
            _audio: audio,
            _mixer: mixer,
            event_pump: sdl_context.event_pump().expect("Failed to initalize event pump."),
            camera: Camera { transform: Transform::new() },
            world: World::new(),
        }
    }

    /// Called every frame to paint the scene. Do not put game logic here, that goes in update.
    fn render(&mut self) {
        use std::f32;
        let game_objs = &self.game_objects;
        let camera_transform = self.camera.transform;
        // Clear the screen with grey.
        self.renderer.set_draw_color(Color::RGB(240, 240, 240));
        self.renderer.clear();
        // Reset the draw color to white so subsequent draw calls are correct.
        self.renderer.set_draw_color(Color::RGB(255, 255, 255));
        let (screen_width, screen_height) = self.renderer.window().unwrap().size();
        for game_obj in game_objs.values() {
            if let Some(ref game_obj) = *game_obj {
                let mut render_transform = game_obj.transform;
                *render_transform.mut_x() -= *camera_transform.x();
                *render_transform.mut_y() -= *camera_transform.y();
                let mut polar = PolarCoords::from(render_transform.position().clone());
                polar.rotation -= *camera_transform.rotation();
                *render_transform.mut_position() = Vector::from(polar);
                *render_transform.mut_x() += (screen_width / 2) as f32;
                *render_transform.mut_y() += (screen_height / 2) as f32;
                *render_transform.mut_rotation() -= *camera_transform.rotation();
                let (tex_width, tex_height) = texture::size(&game_obj.texture);
                let render_rect =
                    Rect::new(((*render_transform.x()) as i32) - (tex_width as i32 / 2),
                              ((*render_transform.y()) as i32) - (tex_height as i32 / 2),
                              tex_width,
                              tex_height);
                if let &Some(ref texture) = texture::get_raw(&game_obj.texture) {
                    let result = self.renderer.copy_ex(&texture,
                                                       None,
                                                       Some(render_rect),
                                                       (*game_obj.transform.rotation() * 180.0 /
                                                        f32::consts::PI) as
                                                       f64,
                                                       None,
                                                       false,
                                                       false);
                    if let Err(err) = result {
                        println!("Unable to draw texture, Error: {:?}", err);
                    }
                }
            }
        }
        self.renderer.present();
    }

    /// Called every frame to simulate the game. Do not put rendering here, that goes in render.
    fn update(&mut self, delta_time: f32) {
        //Copy game_object to the physics world, step, then copy from physics to game_object
        for mut game_object in self.game_objects.values_mut() {
            if let Some(game_object) = game_object.as_mut() {
                game_object::copy_to_physics(game_object);
            }
        }
        self.world.step(delta_time);
        for mut game_object in self.game_objects.values_mut() {
            if let Some(game_object) = game_object.as_mut() {
                game_object::copy_from_physics(game_object);
            }
        }

        //Send update messages
        let keys = self.game_objects.keys().map(|x| *x).collect::<Vec<u64>>();
        for key in keys {
            let mut game_obj_option = None;
            if let Some(game_obj_ref) = self.game_objects.get_mut(&key) {
                game_obj_option = replace(game_obj_ref, None);
            }
            if let Some(ref mut game_obj) = game_obj_option {
                game_obj.update(self, delta_time);
                *game_obj.transform.mut_rotation() %= 2.0 * f32::consts::PI;
            }
            if let Some(game_obj_ref) = self.game_objects.get_mut(&key) {
                replace(game_obj_ref, game_obj_option);
            }
        }

        // Drop any game objects that need to be dropped.
        let mut dropped_keys = Vec::new();
        for (key, game_obj) in self.game_objects.iter() {
            if let Some(ref game_obj) = *game_obj {
                if game_object::was_dropped(game_obj.borrow()) {
                    dropped_keys.push(*key);
                }
            } else {
                dropped_keys.push(*key);
            }
        }
        for key in dropped_keys {
            self.game_objects.remove(&key);
        }

        input_private::input::shift_frame(&mut self.input);
    }

    /// Begin execution of the game.
    ///
    /// This function won't return until the game has been quit.
    pub fn run(&mut self) {
        mixer::allocate_channels(128);
        let mut last_frame_instant = Instant::now();
        while !self.exit {
            while let Some(e) = self.event_pump.poll_event() {
                if let Event::Quit { .. } = e {
                    self.exit = true;
                }
                input_private::input::process_event(&mut self.input, &e);
            }
            self.update(Duration::from_std(last_frame_instant.elapsed())
                .unwrap()
                .num_microseconds()
                .unwrap() as f32 / 1000000.0);
            last_frame_instant = Instant::now();
            self.render();
        }
    }

    /// Exit the game
    ///
    /// Signals that it's time to quit. Execution will stop at the end of the current frame.
    pub fn quit(&mut self) {
        self.exit = true;
    }

    pub fn camera(&self) -> &Camera {
        &self.camera
    }

    pub fn camera_mut(&mut self) -> &mut Camera {
        &mut self.camera
    }

    /// Plays a sound at a volume between 1.0 and 0.0
    ///
    /// path is a filename relative to assets/sounds (assets\sounds on Windows)
    pub fn play_sound(&mut self, path: &str, volume: f32) -> Result<(), String> {
        let mut file_path = PathBuf::from("assets");
        file_path.push("sounds");
        file_path.push(path);
        let mut sound = Chunk::from_file(file_path)?;
        sound.set_volume((volume * 128.0) as i32);
        let channel = Channel::all().play(&sound, 0)?;
        Ok(())
    }

    /// Creates a new GameObject
    ///
    /// GameObjects are typically physical objects in your game world, such as characters or
    /// decorative objects.
    ///
    /// Parameter f will be called on the newly created GameObject, allowing you to initialize it.
    /// Returns the id of the new GameObject, which can be used to retrieve this GameObject later.
    pub fn new_gameobject<F>(&mut self, f: F) -> u64
        where F: FnOnce(&mut App, &mut GameObject)
    {
        let mut game_object = Box::new(game_object::new(self));
        f(self, &mut game_object);
        let id = game_object.id();
        self.game_objects.insert(id, Some(game_object));
        id
    }

    /// Retrieves a reference to an existing GameObject by the GameObject's id.
    ///
    /// Returns Away if and only if the GameObject exists but is currently loaned out
    /// in another borrow.
    ///
    /// Hint: That borrow is most likely in the game_object parameter of the receive_message
    /// function.
    pub fn game_object_by_id(&self, id: u64) -> OptionAway<&GameObject> {
        OptionAway::from(self.game_objects.get(&id))
    }

    /// Retrieves a mutable reference to an existing GameObject by the GameObject's id.
    ///
    /// Returns Away if and only if the GameObject exists but is currently loaned out
    /// in another borrow.
    ///
    /// Hint: That borrow is most likely in the game_object parameter of the receive_message
    /// function.
    pub fn game_object_by_id_mut(&mut self, id: u64) -> OptionAway<&mut GameObject> {
        OptionAway::from(self.game_objects.get_mut(&id))
    }

    /// Loads a texture and returns it for use.
    ///
    /// texture_name is the file name of the texture relative to assets/textures
    /// (assets\textures on Windows)
    pub fn fetch_texture(&mut self, texture_name: &str) -> Result<Texture, String> {
        let mut texture_path = PathBuf::from("assets");
        texture_path.push("textures");
        texture_path.push(texture_name);
        let sdl_texture = self.renderer.load_texture(texture_path.as_path())?;
        let mut nitro_texture = Texture::new();
        texture::set_raw(&mut nitro_texture, sdl_texture);
        Ok(nitro_texture)
    }
}

// This function will never return 0.  0 can now be used as a null value.
pub fn next_game_object_id(app: &mut App) -> u64 {
    app.next_game_object_id += 1;
    app.next_game_object_id
}
<commit_msg>Fixed audio, hooray!<commit_after>use sdl2;
use sdl2::AudioSubsystem;
use sdl2::EventPump;
use sdl2::event::Event;
use sdl2::render::Renderer;
use sdl2::pixels::Color;
use sdl2::rect::Rect;
use sdl2::image::LoadTexture;
use sdl2::mixer;
use sdl2::mixer::Sdl2MixerContext;
use sdl2::mixer::Channel;
use sdl2::mixer::Chunk;
use OptionAway;
use input_private;
use input::Input;
use game_object::GameObject;
use game_object;
use texture::Texture;
use texture;
use PolarCoords;
use Vector;
use transform::Transform;
use camera::Camera;
use nphysics2d::world::World;
use std::mem::replace;
use std::collections::HashMap;
use std::borrow::Borrow;
use std::path::PathBuf;
use std::f32;
use std::time::Instant;
use chrono::Duration;

pub struct App {
    exit: bool,
    renderer: Renderer<'static>,
    _audio: AudioSubsystem,
    _mixer: Sdl2MixerContext,
    event_pump: EventPump,
    game_objects: HashMap<u64, Option<Box<GameObject>>>,
    sound_cache: HashMap<String, Chunk>,
    next_game_object_id: u64,
    pub input: Input,
    pub camera: Camera,
    pub world: World<f32>,
}

impl App {
    ///Constructs a new App using the given name for the window title.
    pub fn new(name: &str) -> App {
        let sdl_context = sdl2::init().expect("Failed to initialize SDL2.");
        let video_subsystem = sdl_context.video().expect("Failed to initialize video subsystem");
        let window = video_subsystem.window(name, 800, 600)
            .position_centered()
            .fullscreen_desktop()
            .opengl()
            .build()
            .unwrap();
        let renderer = window.renderer().build().expect("Failed to initialize renderer");
        let audio = sdl_context.audio().expect("Failed to initialize audio");
        let mixer = mixer::init(mixer::INIT_OGG).expect("Failed to initialize mixer");
        mixer::open_audio(mixer::DEFAULT_FREQUENCY, mixer::DEFAULT_FORMAT, 2, 1024)
            .expect("Failed to open audio");
        App {
            exit: false,
            next_game_object_id: 0,
            game_objects: HashMap::new(),
            input: Input::new(),
            renderer: renderer,
            sound_cache: HashMap::new(),
            _audio: audio,
            _mixer: mixer,
            event_pump: sdl_context.event_pump().expect("Failed to initalize event pump."),
            camera: Camera { transform: Transform::new() },
            world: World::new(),
        }
    }

    /// Called every frame to paint the scene. Do not put game logic here, that goes in update.
    fn render(&mut self) {
        use std::f32;
        let game_objs = &self.game_objects;
        let camera_transform = self.camera.transform;
        // Clear the screen with grey.
        self.renderer.set_draw_color(Color::RGB(240, 240, 240));
        self.renderer.clear();
        // Reset the draw color to white so subsequent draw calls are correct.
        self.renderer.set_draw_color(Color::RGB(255, 255, 255));
        let (screen_width, screen_height) = self.renderer.window().unwrap().size();
        for game_obj in game_objs.values() {
            if let Some(ref game_obj) = *game_obj {
                let mut render_transform = game_obj.transform;
                *render_transform.mut_x() -= *camera_transform.x();
                *render_transform.mut_y() -= *camera_transform.y();
                let mut polar = PolarCoords::from(render_transform.position().clone());
                polar.rotation -= *camera_transform.rotation();
                *render_transform.mut_position() = Vector::from(polar);
                *render_transform.mut_x() += (screen_width / 2) as f32;
                *render_transform.mut_y() += (screen_height / 2) as f32;
                *render_transform.mut_rotation() -= *camera_transform.rotation();
                let (tex_width, tex_height) = texture::size(&game_obj.texture);
                let render_rect =
                    Rect::new(((*render_transform.x()) as i32) - (tex_width as i32 / 2),
                              ((*render_transform.y()) as i32) - (tex_height as i32 / 2),
                              tex_width,
                              tex_height);
                if let &Some(ref texture) = texture::get_raw(&game_obj.texture) {
                    let result = self.renderer.copy_ex(&texture,
                                                       None,
                                                       Some(render_rect),
                                                       (*game_obj.transform.rotation() * 180.0 /
                                                        f32::consts::PI) as
                                                       f64,
                                                       None,
                                                       false,
                                                       false);
                    if let Err(err) = result {
                        println!("Unable to draw texture, Error: {:?}", err);
                    }
                }
            }
        }
        self.renderer.present();
    }

    /// Called every frame to simulate the game. Do not put rendering here, that goes in render.
    fn update(&mut self, delta_time: f32) {
        //Copy game_object to the physics world, step, then copy from physics to game_object
        for mut game_object in self.game_objects.values_mut() {
            if let Some(game_object) = game_object.as_mut() {
                game_object::copy_to_physics(game_object);
            }
        }
        self.world.step(delta_time);
        for mut game_object in self.game_objects.values_mut() {
            if let Some(game_object) = game_object.as_mut() {
                game_object::copy_from_physics(game_object);
            }
        }

        //Send update messages
        let keys = self.game_objects.keys().map(|x| *x).collect::<Vec<u64>>();
        for key in keys {
            let mut game_obj_option = None;
            if let Some(game_obj_ref) = self.game_objects.get_mut(&key) {
                game_obj_option = replace(game_obj_ref, None);
            }
            if let Some(ref mut game_obj) = game_obj_option {
                game_obj.update(self, delta_time);
                *game_obj.transform.mut_rotation() %= 2.0 * f32::consts::PI;
            }
            if let Some(game_obj_ref) = self.game_objects.get_mut(&key) {
                replace(game_obj_ref, game_obj_option);
            }
        }

        // Drop any game objects that need to be dropped.
        let mut dropped_keys = Vec::new();
        for (key, game_obj) in self.game_objects.iter() {
            if let Some(ref game_obj) = *game_obj {
                if game_object::was_dropped(game_obj.borrow()) {
                    dropped_keys.push(*key);
                }
            } else {
                dropped_keys.push(*key);
            }
        }
        for key in dropped_keys {
            self.game_objects.remove(&key);
        }

        input_private::input::shift_frame(&mut self.input);
    }

    /// Begin execution of the game.
    ///
    /// This function won't return until the game has been quit.
    pub fn run(&mut self) {
        mixer::allocate_channels(128);
        let mut last_frame_instant = Instant::now();
        while !self.exit {
            while let Some(e) = self.event_pump.poll_event() {
                if let Event::Quit { .. } = e {
                    self.exit = true;
                }
                input_private::input::process_event(&mut self.input, &e);
            }
            self.update(Duration::from_std(last_frame_instant.elapsed())
                .unwrap()
                .num_microseconds()
                .unwrap() as f32 / 1000000.0);
            last_frame_instant = Instant::now();
            self.render();
        }
    }

    /// Exit the game
    ///
    /// Signals that it's time to quit. Execution will stop at the end of the current frame.
    pub fn quit(&mut self) {
        self.exit = true;
    }

    pub fn camera(&self) -> &Camera {
        &self.camera
    }

    pub fn camera_mut(&mut self) -> &mut Camera {
        &mut self.camera
    }

    /// Plays a sound at a volume between 1.0 and 0.0
    ///
    /// path is a filename relative to assets/sounds (assets\sounds on Windows)
    pub fn play_sound(&mut self, path: &str, volume: f32) -> Result<(), String> {
        if let Some(chunk) = self.sound_cache.get(path) {
            let channel = Channel::all().play(chunk, 0)?;
            channel.set_volume((volume * 128.0) as i32);
            return Ok(());
        }
        let mut file_path = PathBuf::from("assets");
        file_path.push("sounds");
        file_path.push(path);
        let chunk = Chunk::from_file(file_path)?;
        let channel = Channel::all().play(&chunk, 0)?;
        channel.set_volume((volume * 128.0) as i32);
        self.sound_cache.insert(path.to_owned(), chunk);
        Ok(())
    }

    /// Creates a new GameObject
    ///
    /// GameObjects are typically physical objects in your game world, such as characters or
    /// decorative objects.
    ///
    /// Parameter f will be called on the newly created GameObject, allowing you to initialize it.
    /// Returns the id of the new GameObject, which can be used to retrieve this GameObject later.
    pub fn new_gameobject<F>(&mut self, f: F) -> u64
        where F: FnOnce(&mut App, &mut GameObject)
    {
        let mut game_object = Box::new(game_object::new(self));
        f(self, &mut game_object);
        let id = game_object.id();
        self.game_objects.insert(id, Some(game_object));
        id
    }

    /// Retrieves a reference to an existing GameObject by the GameObject's id.
    ///
    /// Returns Away if and only if the GameObject exists but is currently loaned out
    /// in another borrow.
    ///
    /// Hint: That borrow is most likely in the game_object parameter of the receive_message
    /// function.
    pub fn game_object_by_id(&self, id: u64) -> OptionAway<&GameObject> {
        OptionAway::from(self.game_objects.get(&id))
    }

    /// Retrieves a mutable reference to an existing GameObject by the GameObject's id.
    ///
    /// Returns Away if and only if the GameObject exists but is currently loaned out
    /// in another borrow.
    ///
    /// Hint: That borrow is most likely in the game_object parameter of the receive_message
    /// function.
    pub fn game_object_by_id_mut(&mut self, id: u64) -> OptionAway<&mut GameObject> {
        OptionAway::from(self.game_objects.get_mut(&id))
    }

    /// Loads a texture and returns it for use.
    ///
    /// texture_name is the file name of the texture relative to assets/textures
    /// (assets\textures on Windows)
    pub fn fetch_texture(&mut self, texture_name: &str) -> Result<Texture, String> {
        let mut texture_path = PathBuf::from("assets");
        texture_path.push("textures");
        texture_path.push(texture_name);
        let sdl_texture = self.renderer.load_texture(texture_path.as_path())?;
        let mut nitro_texture = Texture::new();
        texture::set_raw(&mut nitro_texture, sdl_texture);
        Ok(nitro_texture)
    }
}

// This function will never return 0.  0 can now be used as a null value.
pub fn next_game_object_id(app: &mut App) -> u64 {
    app.next_game_object_id += 1;
    app.next_game_object_id
}
<|endoftext|>


<commit_before>use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor};
use serde::ser::{Serialize, Serializer};
use std::collections::HashSet;
use std::fmt;

#[derive(Debug, Clone, Eq, PartialEq)]
struct Names {
    inner: HashSet<String>,
}

impl Serialize for Names {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut names: Vec<_> = self.inner.iter().collect();
        names.sort();
        names.serialize(serializer)
    }
}

impl<'de> Deserialize<'de> for Names {
    fn deserialize<D>(deserializer: D) -> Result<Names, D::Error>
    where
        D: Deserializer<'de>,
    {
        deserializer.deserialize_any(NamesVisitor)
    }
}

struct NamesVisitor;

impl<'de> Visitor<'de> for NamesVisitor {
    type Value = Names;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("names or list of names")
    }

    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    where
        E: serde::de::Error,
    {
        let mut out = HashSet::new();
        out.insert(v.to_string());
        Ok(Names { inner: out })
    }

    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
    where
        A: SeqAccess<'de>,
    {
        let mut out: HashSet<String> = HashSet::new();

        // FIXME: Change `&str` to String to make the error go away
        while let Some(s) = seq.next_element::<&str>()? {
            out.insert(s.to_string());
        }
        Ok(Names { inner: out })
    }
}

#[test]
#[ignore]
/// This test is an almost exact replica of the "string or struct" example
/// in the [serde guide](https://serde.rs/string-or-struct.html)
///
/// FIXME: it currently breaks. If you explicitly select `String` instead
/// of `&str` in the FIXME above, it works.
fn test_visitor() {
    let single = r#"
---
"foo"
"#;
    let single_expected = Names {
        inner: {
            let mut i = HashSet::new();
            i.insert("foo".into());
            i
        },
    };
    let multi = r#"
---
- "foo"
- "bar"
"#;
    let multi_expected = Names {
        inner: {
            let mut i = HashSet::new();
            i.insert("foo".into());
            i.insert("bar".into());
            i
        },
    };

    let result: Names = serde_yaml::from_str(single).expect("didn't deserialize");
    assert_eq!(result, single_expected);

    let result: Names = serde_yaml::from_str(multi).expect("didn't deserialize");
    assert_eq!(result, multi_expected);
}
<commit_msg>Delete disabled borrowed string deserializer test<commit_after><|endoftext|>


<commit_before>use base::{
    AbstractCFTypeRef,
    Boolean,
    CFAllocatorRef,
    CFIndex,
    CFType,
    CFTypeID,
    CFTypeRef,
    CFWrapper,
    kCFAllocatorDefault
};
use string::{CFString, CFStringRef};

use core::libc::c_void;

pub type CFDictionaryApplierFunction = *u8;
pub type CFDictionaryCopyDescriptionCallBack = *u8;
pub type CFDictionaryEqualCallBack = *u8;
pub type CFDictionaryHashCallBack = *u8;
pub type CFDictionaryReleaseCallBack = *u8;
pub type CFDictionaryRetainCallBack = *u8;

pub struct CFDictionaryKeyCallBacks {
    version: CFIndex,
    retain: CFDictionaryRetainCallBack,
    release: CFDictionaryReleaseCallBack,
    copyDescription: CFDictionaryCopyDescriptionCallBack,
    equal: CFDictionaryEqualCallBack,
    hash: CFDictionaryHashCallBack
}

pub struct CFDictionaryValueCallBacks {
    version: CFIndex,
    retain: CFDictionaryRetainCallBack,
    release: CFDictionaryReleaseCallBack,
    copyDescription: CFDictionaryCopyDescriptionCallBack,
    equal: CFDictionaryEqualCallBack
}

struct __CFDictionary { private: () }
pub type CFDictionaryRef = *__CFDictionary;

impl AbstractCFTypeRef for CFDictionaryRef {
    fn as_type_ref(&self) -> CFTypeRef { *self as CFTypeRef }

    fn type_id() -> CFTypeID {
        unsafe {
            CFDictionaryGetTypeID()
        }
    }
}

pub type CFDictionary<KeyRefType, ValueRefType> = CFWrapper<CFDictionaryRef, KeyRefType, ValueRefType>;
pub type UntypedCFDictionary = CFDictionary<CFStringRef, CFTypeRef>;

pub impl<KeyRefType: Copy + AbstractCFTypeRef, ValueRefType: Copy + AbstractCFTypeRef>
    CFDictionary<KeyRefType, ValueRefType> {

    fn new(pairs: &[(KeyRefType,ValueRefType)]) -> CFDictionary<KeyRefType, ValueRefType> {
        let mut keys : ~[CFTypeRef] = ~[];
        let mut values : ~[CFTypeRef] = ~[];
        for pairs.each |pair| {
            // FIXME: "let" would be much nicer here, but that doesn't work yet.
            match *pair {
                (key, value) => {
                    keys.push(key.as_type_ref());
                    values.push(value.as_type_ref());
                }
            }
        }

        assert!(keys.len() == values.len());

        let dictionary_ref : CFDictionaryRef;
        unsafe {
            dictionary_ref = CFDictionaryCreate(kCFAllocatorDefault,
                                                cast::transmute::<*CFTypeRef, **c_void>(vec::raw::to_ptr(keys)),
                                                cast::transmute::<*CFTypeRef, **c_void>(vec::raw::to_ptr(values)),
                                                keys.len() as CFIndex,
                                                ptr::to_unsafe_ptr(&kCFTypeDictionaryKeyCallBacks),
                                                ptr::to_unsafe_ptr(&kCFTypeDictionaryValueCallBacks));
        }

        CFWrapper::wrap_owned(dictionary_ref)
    }

    fn len(&self) -> uint {
        unsafe {
            return CFDictionaryGetCount(self.obj) as uint;
        }
    }

    fn is_empty(&self) -> bool { self.len() == 0 }

    fn contains_key(&self, key: &KeyRefType) -> bool {
        unsafe {
            return CFDictionaryContainsKey(self.obj,
                                           cast::transmute::<CFTypeRef, *c_void>(key.as_type_ref())) as bool;
        }
    }

    fn find(&self, key: &KeyRefType) -> Option<ValueRefType> {
        unsafe {
            let value : *c_void = ptr::null();
            let did_find_value = CFDictionaryGetValueIfPresent(self.obj,
                                                               cast::transmute::<CFTypeRef, *c_void>(key.as_type_ref()),
                                                               cast::transmute::<&*c_void, **c_void>(&value)) as bool;

            // FIXME: this will not handle non-CF dictionary entries
            // or ptr::null() values correctly.
            return if did_find_value {
                Some(cast::transmute::<*c_void, ValueRefType>(value))
            } else {
                None
            }
        }
    }

    fn get(&self, key: &KeyRefType) -> ValueRefType {
        let value = self.find(key);
        if value.is_none() {
            fail!(fmt!("No entry found for key: %?", key));
        }
        return option::unwrap(value);
    }

    fn each(&self, blk: &fn(&KeyRefType, &ValueRefType) -> bool) {
        unsafe {
            let len = self.len();
            let null_keys = cast::transmute::<*c_void,KeyRefType>(ptr::null());
            let keys: ~[KeyRefType] = vec::from_elem(len, null_keys);
            let null_vals = cast::transmute::<*c_void,ValueRefType>(ptr::null());
            let values: ~[ValueRefType] = vec::from_elem(len, null_vals);

            do uint::range(0,len) |i| { blk(&keys[i], &values[i]) }
        }
    }
}

#[link_args="-framework CoreFoundation"]
#[nolink]
extern {
    /*
     * CFDictionary.h
     */

    static kCFTypeDictionaryKeyCallBacks: CFDictionaryKeyCallBacks;
    static kCFTypeDictionaryValueCallBacks: CFDictionaryValueCallBacks;

    fn CFDictionaryApplyFunction(theDict: CFDictionaryRef, applier: CFDictionaryApplierFunction,
                                 context: *c_void);
    fn CFDictionaryContainsKey(theDict: CFDictionaryRef, key: *c_void) -> Boolean;
    fn CFDictionaryContainsValue(theDict: CFDictionaryRef, value: *c_void) -> Boolean;
    fn CFDictionaryCreate(allocator: CFAllocatorRef, keys: **c_void, values: **c_void,
                          numValues: CFIndex, keyCallBacks: *CFDictionaryKeyCallBacks,
                          valueCallBacks: *CFDictionaryValueCallBacks)
                       -> CFDictionaryRef;
    fn CFDictionaryCreateCopy(allocator: CFAllocatorRef,
                              theDict: CFDictionaryRef)
                           -> CFDictionaryRef;
    fn CFDictionaryGetCount(theDict: CFDictionaryRef) -> CFIndex;
    fn CFDictionaryGetCountOfKey(theDict: CFDictionaryRef, key: *c_void) -> CFIndex;
    fn CFDictionaryGetCountOfValue(theDict: CFDictionaryRef, value: *c_void) -> CFIndex;
    fn CFDictionaryGetKeysAndValues(theDict: CFDictionaryRef, keys: **c_void, values: **c_void);
    fn CFDictionaryGetTypeID() -> CFTypeID;
    fn CFDictionaryGetValue(theDict: CFDictionaryRef, key: *c_void) -> *c_void;
    fn CFDictionaryGetValueIfPresent(theDict: CFDictionaryRef,
                                     key: *c_void,
                                     value: **c_void)
                                  -> Boolean;
}

<commit_msg>Update code to use unwrap method.<commit_after>use base::{
    AbstractCFTypeRef,
    Boolean,
    CFAllocatorRef,
    CFIndex,
    CFType,
    CFTypeID,
    CFTypeRef,
    CFWrapper,
    kCFAllocatorDefault
};
use string::{CFString, CFStringRef};

use core::libc::c_void;

pub type CFDictionaryApplierFunction = *u8;
pub type CFDictionaryCopyDescriptionCallBack = *u8;
pub type CFDictionaryEqualCallBack = *u8;
pub type CFDictionaryHashCallBack = *u8;
pub type CFDictionaryReleaseCallBack = *u8;
pub type CFDictionaryRetainCallBack = *u8;

pub struct CFDictionaryKeyCallBacks {
    version: CFIndex,
    retain: CFDictionaryRetainCallBack,
    release: CFDictionaryReleaseCallBack,
    copyDescription: CFDictionaryCopyDescriptionCallBack,
    equal: CFDictionaryEqualCallBack,
    hash: CFDictionaryHashCallBack
}

pub struct CFDictionaryValueCallBacks {
    version: CFIndex,
    retain: CFDictionaryRetainCallBack,
    release: CFDictionaryReleaseCallBack,
    copyDescription: CFDictionaryCopyDescriptionCallBack,
    equal: CFDictionaryEqualCallBack
}

struct __CFDictionary { private: () }
pub type CFDictionaryRef = *__CFDictionary;

impl AbstractCFTypeRef for CFDictionaryRef {
    fn as_type_ref(&self) -> CFTypeRef { *self as CFTypeRef }

    fn type_id() -> CFTypeID {
        unsafe {
            CFDictionaryGetTypeID()
        }
    }
}

pub type CFDictionary<KeyRefType, ValueRefType> = CFWrapper<CFDictionaryRef, KeyRefType, ValueRefType>;
pub type UntypedCFDictionary = CFDictionary<CFStringRef, CFTypeRef>;

pub impl<KeyRefType: Copy + AbstractCFTypeRef, ValueRefType: Copy + AbstractCFTypeRef>
    CFDictionary<KeyRefType, ValueRefType> {

    fn new(pairs: &[(KeyRefType,ValueRefType)]) -> CFDictionary<KeyRefType, ValueRefType> {
        let mut keys : ~[CFTypeRef] = ~[];
        let mut values : ~[CFTypeRef] = ~[];
        for pairs.each |pair| {
            // FIXME: "let" would be much nicer here, but that doesn't work yet.
            match *pair {
                (key, value) => {
                    keys.push(key.as_type_ref());
                    values.push(value.as_type_ref());
                }
            }
        }

        assert!(keys.len() == values.len());

        let dictionary_ref : CFDictionaryRef;
        unsafe {
            dictionary_ref = CFDictionaryCreate(kCFAllocatorDefault,
                                                cast::transmute::<*CFTypeRef, **c_void>(vec::raw::to_ptr(keys)),
                                                cast::transmute::<*CFTypeRef, **c_void>(vec::raw::to_ptr(values)),
                                                keys.len() as CFIndex,
                                                ptr::to_unsafe_ptr(&kCFTypeDictionaryKeyCallBacks),
                                                ptr::to_unsafe_ptr(&kCFTypeDictionaryValueCallBacks));
        }

        CFWrapper::wrap_owned(dictionary_ref)
    }

    fn len(&self) -> uint {
        unsafe {
            return CFDictionaryGetCount(self.obj) as uint;
        }
    }

    fn is_empty(&self) -> bool { self.len() == 0 }

    fn contains_key(&self, key: &KeyRefType) -> bool {
        unsafe {
            return CFDictionaryContainsKey(self.obj,
                                           cast::transmute::<CFTypeRef, *c_void>(key.as_type_ref())) as bool;
        }
    }

    fn find(&self, key: &KeyRefType) -> Option<ValueRefType> {
        unsafe {
            let value : *c_void = ptr::null();
            let did_find_value = CFDictionaryGetValueIfPresent(self.obj,
                                                               cast::transmute::<CFTypeRef, *c_void>(key.as_type_ref()),
                                                               cast::transmute::<&*c_void, **c_void>(&value)) as bool;

            // FIXME: this will not handle non-CF dictionary entries
            // or ptr::null() values correctly.
            return if did_find_value {
                Some(cast::transmute::<*c_void, ValueRefType>(value))
            } else {
                None
            }
        }
    }

    fn get(&self, key: &KeyRefType) -> ValueRefType {
        let value = self.find(key);
        if value.is_none() {
            fail!(fmt!("No entry found for key: %?", key));
        }
        return value.unwrap();
    }

    fn each(&self, blk: &fn(&KeyRefType, &ValueRefType) -> bool) {
        unsafe {
            let len = self.len();
            let null_keys = cast::transmute::<*c_void,KeyRefType>(ptr::null());
            let keys: ~[KeyRefType] = vec::from_elem(len, null_keys);
            let null_vals = cast::transmute::<*c_void,ValueRefType>(ptr::null());
            let values: ~[ValueRefType] = vec::from_elem(len, null_vals);

            do uint::range(0,len) |i| { blk(&keys[i], &values[i]) }
        }
    }
}

#[link_args="-framework CoreFoundation"]
#[nolink]
extern {
    /*
     * CFDictionary.h
     */

    static kCFTypeDictionaryKeyCallBacks: CFDictionaryKeyCallBacks;
    static kCFTypeDictionaryValueCallBacks: CFDictionaryValueCallBacks;

    fn CFDictionaryApplyFunction(theDict: CFDictionaryRef, applier: CFDictionaryApplierFunction,
                                 context: *c_void);
    fn CFDictionaryContainsKey(theDict: CFDictionaryRef, key: *c_void) -> Boolean;
    fn CFDictionaryContainsValue(theDict: CFDictionaryRef, value: *c_void) -> Boolean;
    fn CFDictionaryCreate(allocator: CFAllocatorRef, keys: **c_void, values: **c_void,
                          numValues: CFIndex, keyCallBacks: *CFDictionaryKeyCallBacks,
                          valueCallBacks: *CFDictionaryValueCallBacks)
                       -> CFDictionaryRef;
    fn CFDictionaryCreateCopy(allocator: CFAllocatorRef,
                              theDict: CFDictionaryRef)
                           -> CFDictionaryRef;
    fn CFDictionaryGetCount(theDict: CFDictionaryRef) -> CFIndex;
    fn CFDictionaryGetCountOfKey(theDict: CFDictionaryRef, key: *c_void) -> CFIndex;
    fn CFDictionaryGetCountOfValue(theDict: CFDictionaryRef, value: *c_void) -> CFIndex;
    fn CFDictionaryGetKeysAndValues(theDict: CFDictionaryRef, keys: **c_void, values: **c_void);
    fn CFDictionaryGetTypeID() -> CFTypeID;
    fn CFDictionaryGetValue(theDict: CFDictionaryRef, key: *c_void) -> *c_void;
    fn CFDictionaryGetValueIfPresent(theDict: CFDictionaryRef,
                                     key: *c_void,
                                     value: **c_void)
                                  -> Boolean;
}

<|endoftext|>


<commit_before>//! Handle interface to creating a verifier

use std::sync::Arc;

use log::debug;

use pact_verifier::{FilterInfo, NullRequestFilterExecutor, PactSource, ProviderInfo, VerificationOptions, verify_provider_async};
use pact_verifier::callback_executors::HttpRequestProviderStateExecutor;

#[derive(Debug, Clone)]
/// Wraps a Pact verifier
pub struct VerifierHandle {
  provider: ProviderInfo,
  sources: Vec<PactSource>
}

impl VerifierHandle {
  /// Create a new verifier and return the handle to it
  pub fn new() -> VerifierHandle {
    VerifierHandle {
      provider: ProviderInfo::default(),
      sources: Vec::new()
    }
  }

  /// Update the provider info
  pub fn update_provider_info(
    &mut self,
    name: String,
    scheme: String,
    host: String,
    port: u16,
    path: String
  ) {
    self.provider = ProviderInfo {
      name,
      protocol: scheme,
      host,
      port: if port == 0 { None } else { Some(port) },
      path
    }
  }

  /// Add a file source to be verified
  pub fn add_file_source(&mut self, file: &str) {
    self.sources.push(PactSource::File(file.to_string()));
  }

  /// Execute the verifier
  pub fn execute(&self) -> i32 {
    let filter = FilterInfo::None;
    let provider_state_executor = Arc::new(HttpRequestProviderStateExecutor {
      state_change_url: None,
      state_change_teardown: false,
      state_change_body: false
    });

    let options = VerificationOptions {
      request_filter: None::<Arc<NullRequestFilterExecutor>>,
      .. VerificationOptions::default()
    };

    for s in &self.sources {
      debug!("Pact source to verify = {}", s);
    };

    let runtime = tokio::runtime::Runtime::new().unwrap();
    runtime.block_on(async {
      if verify_provider_async(
        self.provider.clone(),
        self.sources.clone(),
        filter,
        vec![],
        options,
        &provider_state_executor
      ).await {
        0
      } else {
        1
      }
    })
  }
}
<commit_msg>chore: fix build after merge from master<commit_after>//! Handle interface to creating a verifier

use std::sync::Arc;

use log::debug;

use pact_verifier::{FilterInfo, NullRequestFilterExecutor, PactSource, ProviderInfo, VerificationOptions, verify_provider_async};
use pact_verifier::callback_executors::HttpRequestProviderStateExecutor;

#[derive(Debug, Clone)]
/// Wraps a Pact verifier
pub struct VerifierHandle {
  provider: ProviderInfo,
  sources: Vec<PactSource>
}

impl VerifierHandle {
  /// Create a new verifier and return the handle to it
  pub fn new() -> VerifierHandle {
    VerifierHandle {
      provider: ProviderInfo::default(),
      sources: Vec::new()
    }
  }

  /// Update the provider info
  pub fn update_provider_info(
    &mut self,
    name: String,
    scheme: String,
    host: String,
    port: u16,
    path: String
  ) {
    self.provider = ProviderInfo {
      name,
      protocol: scheme,
      host,
      port: if port == 0 { None } else { Some(port) },
      path
    }
  }

  /// Add a file source to be verified
  pub fn add_file_source(&mut self, file: &str) {
    self.sources.push(PactSource::File(file.to_string()));
  }

  /// Execute the verifier
  ///
  /// This will return an integer value based on the status of the verification:
  /// * 0 - verification was successful
  /// * 1 - verification was not successful
  /// * 2 - failed to run the verification
  pub fn execute(&self) -> i32 {
    let filter = FilterInfo::None;
    let provider_state_executor = Arc::new(HttpRequestProviderStateExecutor {
      state_change_url: None,
      state_change_teardown: false,
      state_change_body: false
    });

    let options = VerificationOptions {
      request_filter: None::<Arc<NullRequestFilterExecutor>>,
      .. VerificationOptions::default()
    };

    for s in &self.sources {
      debug!("Pact source to verify = {}", s);
    };

    let runtime = tokio::runtime::Runtime::new().unwrap();
    runtime.block_on(async {
      verify_provider_async(
        self.provider.clone(),
        self.sources.clone(),
        filter,
        vec![],
        options,
        &provider_state_executor
      ).await
    })
      .map(|result| if result { 0 } else { 2 })
      .unwrap_or(2)
  }
}
<|endoftext|>


<commit_before>use super::*;

pub(super) const PATTERN_FIRST: TokenSet = expressions::LITERAL_FIRST
    .union(paths::PATH_FIRST)
    .union(token_set![BOX_KW, REF_KW, MUT_KW, L_PAREN, L_BRACK, AMP, UNDERSCORE, MINUS]);

pub(crate) fn pattern(p: &mut Parser) {
    pattern_r(p, PAT_RECOVERY_SET);
}

/// Parses a pattern list separated by pipes `|`
pub(super) fn pattern_list(p: &mut Parser) {
    pattern_list_r(p, PAT_RECOVERY_SET)
}

/// Parses a pattern list separated by pipes `|`
/// using the given `recovery_set`
pub(super) fn pattern_list_r(p: &mut Parser, recovery_set: TokenSet) {
    p.eat(T![|]);
    pattern_r(p, recovery_set);

    while p.eat(T![|]) {
        pattern_r(p, recovery_set);
    }
}

pub(super) fn pattern_r(p: &mut Parser, recovery_set: TokenSet) {
    if let Some(lhs) = atom_pat(p, recovery_set) {
        // test range_pat
        // fn main() {
        //     match 92 {
        //         0 ... 100 => (),
        //         101 ..= 200 => (),
        //         200 .. 301=> (),
        //     }
        // }
        for &range_op in [T![...], T![..=], T![..]].iter() {
            if p.at(range_op) {
                let m = lhs.precede(p);
                p.bump(range_op);
                atom_pat(p, recovery_set);
                m.complete(p, RANGE_PAT);
                return;
            }
        }
        // test marco_pat
        // fn main() {
        //     let m!(x) = 0;
        // }
        if lhs.kind() == PATH_PAT && p.at(T![!]) {
            let m = lhs.precede(p);
            items::macro_call_after_excl(p);
            m.complete(p, MACRO_CALL);
        }
    }
}

const PAT_RECOVERY_SET: TokenSet =
    token_set![LET_KW, IF_KW, WHILE_KW, LOOP_KW, MATCH_KW, R_PAREN, COMMA];

fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> {
    let m = match p.nth(0) {
        T![box] => box_pat(p),
        T![ref] | T![mut] => bind_pat(p, true),
        IDENT => match p.nth(1) {
            // Checks the token after an IDENT to see if a pattern is a path (Struct { .. }) or macro
            // (T![x]).
            T!['('] | T!['{'] | T![!] => path_pat(p),
            T![:] if p.nth_at(1, T![::]) => path_pat(p),
            _ => bind_pat(p, true),
        },

        _ if paths::is_use_path_start(p) => path_pat(p),
        _ if is_literal_pat_start(p) => literal_pat(p),

        T![_] => placeholder_pat(p),
        T![&] => ref_pat(p),
        T!['('] => tuple_pat(p),
        T!['['] => slice_pat(p),

        _ => {
            p.err_recover("expected pattern", recovery_set);
            return None;
        }
    };

    Some(m)
}

fn is_literal_pat_start(p: &Parser) -> bool {
    p.at(T![-]) && (p.nth(1) == INT_NUMBER || p.nth(1) == FLOAT_NUMBER)
        || p.at_ts(expressions::LITERAL_FIRST)
}

// test literal_pattern
// fn main() {
//     match () {
//         -1 => (),
//         92 => (),
//         'c' => (),
//         "hello" => (),
//     }
// }
fn literal_pat(p: &mut Parser) -> CompletedMarker {
    assert!(is_literal_pat_start(p));
    let m = p.start();
    if p.at(T![-]) {
        p.bump_any();
    }
    expressions::literal(p);
    m.complete(p, LITERAL_PAT)
}

// test path_part
// fn foo() {
//     let foo::Bar = ();
//     let ::Bar = ();
//     let Bar { .. } = ();
//     let Bar(..) = ();
// }
fn path_pat(p: &mut Parser) -> CompletedMarker {
    assert!(paths::is_use_path_start(p));
    let m = p.start();
    paths::expr_path(p);
    let kind = match p.current() {
        T!['('] => {
            tuple_pat_fields(p);
            TUPLE_STRUCT_PAT
        }
        T!['{'] => {
            record_field_pat_list(p);
            RECORD_PAT
        }
        _ => PATH_PAT,
    };
    m.complete(p, kind)
}

// test tuple_pat_fields
// fn foo() {
//     let S() = ();
//     let S(_) = ();
//     let S(_,) = ();
//     let S(_, .. , x) = ();
// }
fn tuple_pat_fields(p: &mut Parser) {
    assert!(p.at(T!['(']));
    p.bump_any();
    pat_list(p, T![')']);
    p.expect(T![')']);
}

// test record_field_pat_list
// fn foo() {
//     let S {} = ();
//     let S { f, ref mut g } = ();
//     let S { h: _, ..} = ();
//     let S { h: _, } = ();
// }
fn record_field_pat_list(p: &mut Parser) {
    assert!(p.at(T!['{']));
    let m = p.start();
    p.bump_any();
    while !p.at(EOF) && !p.at(T!['}']) {
        match p.current() {
            T![.] if p.at(T![..]) => p.bump(T![..]),
            IDENT if p.nth(1) == T![:] => record_field_pat(p),
            T!['{'] => error_block(p, "expected ident"),
            T![box] => {
                box_pat(p);
            }
            _ => {
                bind_pat(p, false);
            }
        }
        if !p.at(T!['}']) {
            p.expect(T![,]);
        }
    }
    p.expect(T!['}']);
    m.complete(p, RECORD_FIELD_PAT_LIST);
}

fn record_field_pat(p: &mut Parser) {
    assert!(p.at(IDENT));
    assert!(p.nth(1) == T![:]);

    let m = p.start();
    name(p);
    p.bump_any();
    pattern(p);
    m.complete(p, RECORD_FIELD_PAT);
}

// test placeholder_pat
// fn main() { let _ = (); }
fn placeholder_pat(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(T![_]));
    let m = p.start();
    p.bump_any();
    m.complete(p, PLACEHOLDER_PAT)
}

// test ref_pat
// fn main() {
//     let &a = ();
//     let &mut b = ();
// }
fn ref_pat(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(T![&]));
    let m = p.start();
    p.bump_any();
    p.eat(T![mut]);
    pattern(p);
    m.complete(p, REF_PAT)
}

// test tuple_pat
// fn main() {
//     let (a, b, ..) = ();
// }
fn tuple_pat(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(T!['(']));
    let m = p.start();
    tuple_pat_fields(p);
    m.complete(p, TUPLE_PAT)
}

// test slice_pat
// fn main() {
//     let [a, b, ..] = [];
// }
fn slice_pat(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(T!['[']));
    let m = p.start();
    p.bump_any();
    pat_list(p, T![']']);
    p.expect(T![']']);
    m.complete(p, SLICE_PAT)
}

fn pat_list(p: &mut Parser, ket: SyntaxKind) {
    while !p.at(EOF) && !p.at(ket) {
        match p.current() {
            T![.] if p.at(T![..]) => p.bump(T![..]),
            _ => {
                if !p.at_ts(PATTERN_FIRST) {
                    p.error("expected a pattern");
                    break;
                }
                pattern(p)
            }
        }
        if !p.at(ket) {
            p.expect(T![,]);
        }
    }
}

// test bind_pat
// fn main() {
//     let a = ();
//     let mut b = ();
//     let ref c = ();
//     let ref mut d = ();
//     let e @ _ = ();
//     let ref mut f @ g @ _ = ();
// }
fn bind_pat(p: &mut Parser, with_at: bool) -> CompletedMarker {
    let m = p.start();
    p.eat(T![ref]);
    p.eat(T![mut]);
    name(p);
    if with_at && p.eat(T![@]) {
        pattern(p);
    }
    m.complete(p, BIND_PAT)
}

// test box_pat
// fn main() {
//     let box i = ();
//     let box Outer { box i, j: box Inner(box &x) } = ();
//     let box ref mut i = ();
// }
fn box_pat(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(T![box]));
    let m = p.start();
    p.bump_any();
    pattern(p);
    m.complete(p, BOX_PAT)
}
<commit_msg>Parse `..` as a proper pattern<commit_after>use super::*;

pub(super) const PATTERN_FIRST: TokenSet = expressions::LITERAL_FIRST
    .union(paths::PATH_FIRST)
    .union(token_set![BOX_KW, REF_KW, MUT_KW, L_PAREN, L_BRACK, AMP, UNDERSCORE, MINUS, DOT]);

pub(crate) fn pattern(p: &mut Parser) {
    pattern_r(p, PAT_RECOVERY_SET);
}

/// Parses a pattern list separated by pipes `|`
pub(super) fn pattern_list(p: &mut Parser) {
    pattern_list_r(p, PAT_RECOVERY_SET)
}

/// Parses a pattern list separated by pipes `|`
/// using the given `recovery_set`
pub(super) fn pattern_list_r(p: &mut Parser, recovery_set: TokenSet) {
    p.eat(T![|]);
    pattern_r(p, recovery_set);

    while p.eat(T![|]) {
        pattern_r(p, recovery_set);
    }
}

pub(super) fn pattern_r(p: &mut Parser, recovery_set: TokenSet) {
    if let Some(lhs) = atom_pat(p, recovery_set) {
        // test range_pat
        // fn main() {
        //     match 92 {
        //         0 ... 100 => (),
        //         101 ..= 200 => (),
        //         200 .. 301=> (),
        //     }
        // }
        for &range_op in [T![...], T![..=], T![..]].iter() {
            if p.at(range_op) {
                let m = lhs.precede(p);
                p.bump(range_op);
                atom_pat(p, recovery_set);
                m.complete(p, RANGE_PAT);
                return;
            }
        }
        // test marco_pat
        // fn main() {
        //     let m!(x) = 0;
        // }
        if lhs.kind() == PATH_PAT && p.at(T![!]) {
            let m = lhs.precede(p);
            items::macro_call_after_excl(p);
            m.complete(p, MACRO_CALL);
        }
    }
}

const PAT_RECOVERY_SET: TokenSet =
    token_set![LET_KW, IF_KW, WHILE_KW, LOOP_KW, MATCH_KW, R_PAREN, COMMA];

fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> {
    let m = match p.nth(0) {
        T![box] => box_pat(p),
        T![ref] | T![mut] => bind_pat(p, true),
        IDENT => match p.nth(1) {
            // Checks the token after an IDENT to see if a pattern is a path (Struct { .. }) or macro
            // (T![x]).
            T!['('] | T!['{'] | T![!] => path_pat(p),
            T![:] if p.nth_at(1, T![::]) => path_pat(p),
            _ => bind_pat(p, true),
        },

        _ if paths::is_use_path_start(p) => path_pat(p),
        _ if is_literal_pat_start(p) => literal_pat(p),

        T![.] if p.at(T![..]) => dot_dot_pat(p),
        T![_] => placeholder_pat(p),
        T![&] => ref_pat(p),
        T!['('] => tuple_pat(p),
        T!['['] => slice_pat(p),

        _ => {
            p.err_recover("expected pattern", recovery_set);
            return None;
        }
    };

    Some(m)
}

fn is_literal_pat_start(p: &Parser) -> bool {
    p.at(T![-]) && (p.nth(1) == INT_NUMBER || p.nth(1) == FLOAT_NUMBER)
        || p.at_ts(expressions::LITERAL_FIRST)
}

// test literal_pattern
// fn main() {
//     match () {
//         -1 => (),
//         92 => (),
//         'c' => (),
//         "hello" => (),
//     }
// }
fn literal_pat(p: &mut Parser) -> CompletedMarker {
    assert!(is_literal_pat_start(p));
    let m = p.start();
    if p.at(T![-]) {
        p.bump_any();
    }
    expressions::literal(p);
    m.complete(p, LITERAL_PAT)
}

// test path_part
// fn foo() {
//     let foo::Bar = ();
//     let ::Bar = ();
//     let Bar { .. } = ();
//     let Bar(..) = ();
// }
fn path_pat(p: &mut Parser) -> CompletedMarker {
    assert!(paths::is_use_path_start(p));
    let m = p.start();
    paths::expr_path(p);
    let kind = match p.current() {
        T!['('] => {
            tuple_pat_fields(p);
            TUPLE_STRUCT_PAT
        }
        T!['{'] => {
            record_field_pat_list(p);
            RECORD_PAT
        }
        _ => PATH_PAT,
    };
    m.complete(p, kind)
}

// test tuple_pat_fields
// fn foo() {
//     let S() = ();
//     let S(_) = ();
//     let S(_,) = ();
//     let S(_, .. , x) = ();
// }
fn tuple_pat_fields(p: &mut Parser) {
    assert!(p.at(T!['(']));
    p.bump_any();
    pat_list(p, T![')']);
    p.expect(T![')']);
}

// test record_field_pat_list
// fn foo() {
//     let S {} = ();
//     let S { f, ref mut g } = ();
//     let S { h: _, ..} = ();
//     let S { h: _, } = ();
// }
fn record_field_pat_list(p: &mut Parser) {
    assert!(p.at(T!['{']));
    let m = p.start();
    p.bump_any();
    while !p.at(EOF) && !p.at(T!['}']) {
        match p.current() {
            // A trailing `..` is *not* treated as a DOT_DOT_PAT.
            T![.] if p.at(T![..]) => p.bump(T![..]),

            IDENT if p.nth(1) == T![:] => record_field_pat(p),
            T!['{'] => error_block(p, "expected ident"),
            T![box] => {
                box_pat(p);
            }
            _ => {
                bind_pat(p, false);
            }
        }
        if !p.at(T!['}']) {
            p.expect(T![,]);
        }
    }
    p.expect(T!['}']);
    m.complete(p, RECORD_FIELD_PAT_LIST);
}

fn record_field_pat(p: &mut Parser) {
    assert!(p.at(IDENT));
    assert!(p.nth(1) == T![:]);

    let m = p.start();
    name(p);
    p.bump_any();
    pattern(p);
    m.complete(p, RECORD_FIELD_PAT);
}

// test placeholder_pat
// fn main() { let _ = (); }
fn placeholder_pat(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(T![_]));
    let m = p.start();
    p.bump_any();
    m.complete(p, PLACEHOLDER_PAT)
}

// test dot_dot_pat
// fn main() {
//     let .. = ();
//     //
//     // Tuples
//     //
//     let (a, ..) = ();
//     let (a, ..,) = ();
//     let Tuple(a, ..) = ();
//     let Tuple(a, ..,) = ();
//     let (.., ..) = ();
//     let Tuple(.., ..) = ();
//     let (.., a, ..) = ();
//     let Tuple(.., a, ..) = ();
//     //
//     // Slices
//     //
//     let [..] = ();
//     let [head, ..] = ();
//     let [head, tail @ ..] = ();
//     let [head, .., cons] = ();
//     let [head, mid @ .., cons] = ();
//     let [head, .., .., cons] = ();
//     let [head, .., mid, tail @ ..] = ();
//     let [head, .., mid, .., cons] = ();
// }
fn dot_dot_pat(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(T![..]));
    let m = p.start();
    p.bump(T![..]);
    m.complete(p, DOT_DOT_PAT)
}

// test ref_pat
// fn main() {
//     let &a = ();
//     let &mut b = ();
// }
fn ref_pat(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(T![&]));
    let m = p.start();
    p.bump_any();
    p.eat(T![mut]);
    pattern(p);
    m.complete(p, REF_PAT)
}

// test tuple_pat
// fn main() {
//     let (a, b, ..) = ();
// }
fn tuple_pat(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(T!['(']));
    let m = p.start();
    tuple_pat_fields(p);
    m.complete(p, TUPLE_PAT)
}

// test slice_pat
// fn main() {
//     let [a, b, ..] = [];
// }
fn slice_pat(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(T!['[']));
    let m = p.start();
    p.bump_any();
    pat_list(p, T![']']);
    p.expect(T![']']);
    m.complete(p, SLICE_PAT)
}

fn pat_list(p: &mut Parser, ket: SyntaxKind) {
    while !p.at(EOF) && !p.at(ket) {
        if !p.at_ts(PATTERN_FIRST) {
            p.error("expected a pattern");
            break;
        }

        pattern(p);
        if !p.at(ket) {
            p.expect(T![,]);
        }
    }
}

// test bind_pat
// fn main() {
//     let a = ();
//     let mut b = ();
//     let ref c = ();
//     let ref mut d = ();
//     let e @ _ = ();
//     let ref mut f @ g @ _ = ();
// }
fn bind_pat(p: &mut Parser, with_at: bool) -> CompletedMarker {
    let m = p.start();
    p.eat(T![ref]);
    p.eat(T![mut]);
    name(p);
    if with_at && p.eat(T![@]) {
        pattern(p);
    }
    m.complete(p, BIND_PAT)
}

// test box_pat
// fn main() {
//     let box i = ();
//     let box Outer { box i, j: box Inner(box &x) } = ();
//     let box ref mut i = ();
// }
fn box_pat(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(T![box]));
    let m = p.start();
    p.bump_any();
    pattern(p);
    m.complete(p, BOX_PAT)
}
<|endoftext|>


<commit_before>//! CSS font properties.

use cssparser::{BasicParseError, Parser};

use crate::drawing_ctx::ViewParams;
use crate::error::*;
use crate::length::*;
use crate::parsers::Parse;
use crate::properties::ComputedValues;

// https://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#propdef-font-size
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum FontSizeSpec {
    Smaller,
    Larger,
    XXSmall,
    XSmall,
    Small,
    Medium,
    Large,
    XLarge,
    XXLarge,
    Value(Length<Both>),
}

impl FontSizeSpec {
    pub fn value(&self) -> Length<Both> {
        match self {
            FontSizeSpec::Value(s) => *s,
            _ => unreachable!(),
        }
    }

    pub fn compute(&self, v: &ComputedValues) -> Self {
        let compute_points = |p| 12.0 * 1.2f64.powf(p) / POINTS_PER_INCH;

        let size = v.font_size.0.value();

        let new_size = match self {
            FontSizeSpec::Smaller => Length::<Both>::new(size.length / 1.2, size.unit),
            FontSizeSpec::Larger => Length::<Both>::new(size.length * 1.2, size.unit),
            FontSizeSpec::XXSmall => Length::<Both>::new(compute_points(-3.0), LengthUnit::In),
            FontSizeSpec::XSmall => Length::<Both>::new(compute_points(-2.0), LengthUnit::In),
            FontSizeSpec::Small => Length::<Both>::new(compute_points(-1.0), LengthUnit::In),
            FontSizeSpec::Medium => Length::<Both>::new(compute_points(0.0), LengthUnit::In),
            FontSizeSpec::Large => Length::<Both>::new(compute_points(1.0), LengthUnit::In),
            FontSizeSpec::XLarge => Length::<Both>::new(compute_points(2.0), LengthUnit::In),
            FontSizeSpec::XXLarge => Length::<Both>::new(compute_points(3.0), LengthUnit::In),
            FontSizeSpec::Value(s) if s.unit == LengthUnit::Percent => {
                Length::<Both>::new(size.length * s.length, size.unit)
            }
            FontSizeSpec::Value(s) => *s,
        };

        FontSizeSpec::Value(new_size)
    }

    pub fn normalize(&self, values: &ComputedValues, params: &ViewParams) -> f64 {
        self.value().normalize(values, params)
    }
}

impl Parse for FontSizeSpec {
    fn parse(parser: &mut Parser<'_, '_>) -> Result<FontSizeSpec, crate::error::ValueErrorKind> {
        parser.try_parse(|p| Length::<Both>::parse(p))
            .and_then(|l| Ok(FontSizeSpec::Value(l)))
            .or_else(|_| {
                parse_identifiers!(
                    parser,
                    "smaller" => FontSizeSpec::Smaller,
                    "larger" => FontSizeSpec::Larger,
                    "xx-small" => FontSizeSpec::XXSmall,
                    "x-small" => FontSizeSpec::XSmall,
                    "small" => FontSizeSpec::Small,
                    "medium" => FontSizeSpec::Medium,
                    "large" => FontSizeSpec::Large,
                    "x-large" => FontSizeSpec::XLarge,
                    "xx-large" => FontSizeSpec::XXLarge,
                )
            }).map_err(|_| ValueErrorKind::parse_error("parse error"))
    }
}

// https://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#propdef-font-weight
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum FontWeightSpec {
    Normal,
    Bold,
    Bolder,
    Lighter,
    W100,
    W200,
    W300,
    W400,
    W500,
    W600,
    W700,
    W800,
    W900,
}

impl Parse for FontWeightSpec {
    fn parse(parser: &mut Parser<'_, '_>) -> Result<FontWeightSpec, crate::error::ValueErrorKind> {
        if let Ok(r) = parser.try_parse(|p| {
            p.expect_ident()
                .map_err(|_| ())
                .and_then(|cow| match cow.as_ref() {
                    "normal" => Ok(FontWeightSpec::Normal),
                    "bold" => Ok(FontWeightSpec::Bold),
                    "bolder" => Ok(FontWeightSpec::Bolder),
                    "lighter" => Ok(FontWeightSpec::Lighter),
                    _ => Err(()),
                })
        }) {
            return Ok(r);
        }

        if let Ok(r) = parser
            .expect_integer()
            .map_err(|_| ())
            .and_then(|i| match i {
                100 => Ok(FontWeightSpec::W100),
                200 => Ok(FontWeightSpec::W200),
                300 => Ok(FontWeightSpec::W300),
                400 => Ok(FontWeightSpec::W400),
                500 => Ok(FontWeightSpec::W500),
                600 => Ok(FontWeightSpec::W600),
                700 => Ok(FontWeightSpec::W700),
                800 => Ok(FontWeightSpec::W800),
                900 => Ok(FontWeightSpec::W900),
                _ => Err(()),
            })
        {
            Ok(r)
        } else {
            Err(ValueErrorKind::parse_error(
                "invalid font-weight specification",
            ))
        }
    }
}

// https://www.w3.org/TR/css-text-3/#letter-spacing-property
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum LetterSpacingSpec {
    Normal,
    Value(Length<Horizontal>),
}

impl LetterSpacingSpec {
    pub fn value(&self) -> Length<Horizontal> {
        match self {
            LetterSpacingSpec::Value(s) => *s,
            _ => unreachable!(),
        }
    }

    pub fn compute(&self) -> Self {
        let spacing = match self {
            LetterSpacingSpec::Normal => Length::<Horizontal>::new(0.0, LengthUnit::Px),
            LetterSpacingSpec::Value(s) => *s,
        };

        LetterSpacingSpec::Value(spacing)
    }

    pub fn normalize(&self, values: &ComputedValues, params: &ViewParams) -> f64 {
        self.value().normalize(values, params)
    }
}

impl Parse for LetterSpacingSpec {
    fn parse(
        parser: &mut Parser<'_, '_>,
    ) -> Result<LetterSpacingSpec, crate::error::ValueErrorKind> {
        parser.try_parse(|p| Length::<Horizontal>::parse(p))
            .and_then(|l| Ok(LetterSpacingSpec::Value(l)))
            .or_else(|_| {
                parse_identifiers!(
                    parser,
                    "normal" => LetterSpacingSpec::Normal,
                )
            }).map_err(|_| ValueErrorKind::parse_error("parse error"))
    }
}

/// https://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#propdef-font-family
#[derive(Debug, Clone, PartialEq)]
pub struct SingleFontFamily(pub String);

impl Parse for SingleFontFamily {
    fn parse(parser: &mut Parser<'_, '_>) -> Result<SingleFontFamily, ValueErrorKind> {
        parse_single_font_family(parser)
            .map_err(|_| ValueErrorKind::parse_error("expected font family"))
    }
}

fn parse_single_font_family<'i>(
    parser: &'i mut Parser<'_, '_>,
) -> Result<SingleFontFamily, BasicParseError<'i>> {
    if let Ok(cow) = parser.try_parse(|p| p.expect_string_cloned()) {
        return Ok(SingleFontFamily((*cow).to_owned()));
    }

    let first_ident = parser.expect_ident()?.clone();

    let mut value = first_ident.as_ref().to_owned();

    while let Ok(cow) = parser.try_parse(|p| p.expect_ident_cloned()) {
        value.push(' ');
        value.push_str(&cow);
    }

    Ok(SingleFontFamily(value))
}

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

    #[test]
    fn detects_invalid_invalid_font_size() {
        assert!(is_parse_error(&FontSizeSpec::parse_str("furlong")));
    }

    #[test]
    fn parses_font_weight() {
        assert_eq!(
            <FontWeightSpec as Parse>::parse_str("normal"),
            Ok(FontWeightSpec::Normal)
        );
        assert_eq!(
            <FontWeightSpec as Parse>::parse_str("bold"),
            Ok(FontWeightSpec::Bold)
        );
        assert_eq!(
            <FontWeightSpec as Parse>::parse_str("100"),
            Ok(FontWeightSpec::W100)
        );
    }

    #[test]
    fn detects_invalid_font_weight() {
        assert!(<FontWeightSpec as Parse>::parse_str("").is_err());
        assert!(<FontWeightSpec as Parse>::parse_str("strange").is_err());
        assert!(<FontWeightSpec as Parse>::parse_str("314").is_err());
        assert!(<FontWeightSpec as Parse>::parse_str("3.14").is_err());
    }

    #[test]
    fn parses_letter_spacing() {
        assert_eq!(
            <LetterSpacingSpec as Parse>::parse_str("normal"),
            Ok(LetterSpacingSpec::Normal)
        );
        assert_eq!(
            <LetterSpacingSpec as Parse>::parse_str("10em"),
            Ok(LetterSpacingSpec::Value(Length::<Horizontal>::new(
                10.0,
                LengthUnit::Em,
            )))
        );
    }

    #[test]
    fn computes_letter_spacing() {
        assert_eq!(
            <LetterSpacingSpec as Parse>::parse_str("normal").map(|s| s.compute()),
            Ok(LetterSpacingSpec::Value(Length::<Horizontal>::new(
                0.0,
                LengthUnit::Px,
            )))
        );
        assert_eq!(
            <LetterSpacingSpec as Parse>::parse_str("10em").map(|s| s.compute()),
            Ok(LetterSpacingSpec::Value(Length::<Horizontal>::new(
                10.0,
                LengthUnit::Em,
            )))
        );
    }

    #[test]
    fn detects_invalid_invalid_letter_spacing() {
        assert!(is_parse_error(&LetterSpacingSpec::parse_str("furlong")));
    }

    #[test]
    fn parses_font_family() {
        assert_eq!(
            <SingleFontFamily as Parse>::parse_str("'Hello world'"),
            Ok(SingleFontFamily("Hello world".to_owned()))
        );

        assert_eq!(
            <SingleFontFamily as Parse>::parse_str("\"Hello world\""),
            Ok(SingleFontFamily("Hello world".to_owned()))
        );

        assert_eq!(
            <SingleFontFamily as Parse>::parse_str("  Hello  world  "),
            Ok(SingleFontFamily("Hello world".to_owned()))
        );

        assert_eq!(
            <SingleFontFamily as Parse>::parse_str("Plonk"),
            Ok(SingleFontFamily("Plonk".to_owned()))
        );
    }

    #[test]
    fn detects_invalid_font_family() {
        assert!(<SingleFontFamily as Parse>::parse_str("").is_err());

        // assert!(<SingleFontFamily as Parse>::parse_str("''").is_err());

        assert!(<SingleFontFamily as Parse>::parse_str("42").is_err());
    }
}
<commit_msg>FontSizeSpec: simplify parser<commit_after>//! CSS font properties.

use cssparser::{BasicParseError, Parser};

use crate::drawing_ctx::ViewParams;
use crate::error::*;
use crate::length::*;
use crate::parsers::Parse;
use crate::properties::ComputedValues;

// https://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#propdef-font-size
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum FontSizeSpec {
    Smaller,
    Larger,
    XXSmall,
    XSmall,
    Small,
    Medium,
    Large,
    XLarge,
    XXLarge,
    Value(Length<Both>),
}

impl FontSizeSpec {
    pub fn value(&self) -> Length<Both> {
        match self {
            FontSizeSpec::Value(s) => *s,
            _ => unreachable!(),
        }
    }

    pub fn compute(&self, v: &ComputedValues) -> Self {
        let compute_points = |p| 12.0 * 1.2f64.powf(p) / POINTS_PER_INCH;

        let size = v.font_size.0.value();

        let new_size = match self {
            FontSizeSpec::Smaller => Length::<Both>::new(size.length / 1.2, size.unit),
            FontSizeSpec::Larger => Length::<Both>::new(size.length * 1.2, size.unit),
            FontSizeSpec::XXSmall => Length::<Both>::new(compute_points(-3.0), LengthUnit::In),
            FontSizeSpec::XSmall => Length::<Both>::new(compute_points(-2.0), LengthUnit::In),
            FontSizeSpec::Small => Length::<Both>::new(compute_points(-1.0), LengthUnit::In),
            FontSizeSpec::Medium => Length::<Both>::new(compute_points(0.0), LengthUnit::In),
            FontSizeSpec::Large => Length::<Both>::new(compute_points(1.0), LengthUnit::In),
            FontSizeSpec::XLarge => Length::<Both>::new(compute_points(2.0), LengthUnit::In),
            FontSizeSpec::XXLarge => Length::<Both>::new(compute_points(3.0), LengthUnit::In),
            FontSizeSpec::Value(s) if s.unit == LengthUnit::Percent => {
                Length::<Both>::new(size.length * s.length, size.unit)
            }
            FontSizeSpec::Value(s) => *s,
        };

        FontSizeSpec::Value(new_size)
    }

    pub fn normalize(&self, values: &ComputedValues, params: &ViewParams) -> f64 {
        self.value().normalize(values, params)
    }
}

impl Parse for FontSizeSpec {
    fn parse(parser: &mut Parser<'_, '_>) -> Result<FontSizeSpec, crate::error::ValueErrorKind> {
        parser
            .try_parse(|p| Length::<Both>::parse(p))
            .and_then(|l| Ok(FontSizeSpec::Value(l)))
            .or_else(|_| {
                parse_identifiers!(
                    parser,
                    "smaller" => FontSizeSpec::Smaller,
                    "larger" => FontSizeSpec::Larger,
                    "xx-small" => FontSizeSpec::XXSmall,
                    "x-small" => FontSizeSpec::XSmall,
                    "small" => FontSizeSpec::Small,
                    "medium" => FontSizeSpec::Medium,
                    "large" => FontSizeSpec::Large,
                    "x-large" => FontSizeSpec::XLarge,
                    "xx-large" => FontSizeSpec::XXLarge,
                )
            })
            .map_err(|_| ValueErrorKind::parse_error("parse error"))
    }
}

// https://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#propdef-font-weight
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum FontWeightSpec {
    Normal,
    Bold,
    Bolder,
    Lighter,
    W100,
    W200,
    W300,
    W400,
    W500,
    W600,
    W700,
    W800,
    W900,
}

impl Parse for FontWeightSpec {
    fn parse(parser: &mut Parser<'_, '_>) -> Result<FontWeightSpec, crate::error::ValueErrorKind> {
        parser
            .try_parse(|p| {
                parse_identifiers!(
                    p,
                    "normal" => FontWeightSpec::Normal,
                    "bold" => FontWeightSpec::Bold,
                    "bolder" => FontWeightSpec::Bolder,
                    "lighter" => FontWeightSpec::Lighter,
                )
                .map_err(|_| ValueErrorKind::parse_error("parse error"))
            })
            .or_else(|_| {
                parser
                    .expect_integer()
                    .map_err(|_| ValueErrorKind::parse_error("parse error"))
                    .and_then(|i| match i {
                        100 => Ok(FontWeightSpec::W100),
                        200 => Ok(FontWeightSpec::W200),
                        300 => Ok(FontWeightSpec::W300),
                        400 => Ok(FontWeightSpec::W400),
                        500 => Ok(FontWeightSpec::W500),
                        600 => Ok(FontWeightSpec::W600),
                        700 => Ok(FontWeightSpec::W700),
                        800 => Ok(FontWeightSpec::W800),
                        900 => Ok(FontWeightSpec::W900),
                        _ => Err(ValueErrorKind::parse_error("parse error")),
                    })
            })
    }
}

// https://www.w3.org/TR/css-text-3/#letter-spacing-property
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum LetterSpacingSpec {
    Normal,
    Value(Length<Horizontal>),
}

impl LetterSpacingSpec {
    pub fn value(&self) -> Length<Horizontal> {
        match self {
            LetterSpacingSpec::Value(s) => *s,
            _ => unreachable!(),
        }
    }

    pub fn compute(&self) -> Self {
        let spacing = match self {
            LetterSpacingSpec::Normal => Length::<Horizontal>::new(0.0, LengthUnit::Px),
            LetterSpacingSpec::Value(s) => *s,
        };

        LetterSpacingSpec::Value(spacing)
    }

    pub fn normalize(&self, values: &ComputedValues, params: &ViewParams) -> f64 {
        self.value().normalize(values, params)
    }
}

impl Parse for LetterSpacingSpec {
    fn parse(
        parser: &mut Parser<'_, '_>,
    ) -> Result<LetterSpacingSpec, crate::error::ValueErrorKind> {
        parser
            .try_parse(|p| Length::<Horizontal>::parse(p))
            .and_then(|l| Ok(LetterSpacingSpec::Value(l)))
            .or_else(|_| {
                parse_identifiers!(
                    parser,
                    "normal" => LetterSpacingSpec::Normal,
                )
            })
            .map_err(|_| ValueErrorKind::parse_error("parse error"))
    }
}

/// https://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#propdef-font-family
#[derive(Debug, Clone, PartialEq)]
pub struct SingleFontFamily(pub String);

impl Parse for SingleFontFamily {
    fn parse(parser: &mut Parser<'_, '_>) -> Result<SingleFontFamily, ValueErrorKind> {
        parse_single_font_family(parser)
            .map_err(|_| ValueErrorKind::parse_error("expected font family"))
    }
}

fn parse_single_font_family<'i>(
    parser: &'i mut Parser<'_, '_>,
) -> Result<SingleFontFamily, BasicParseError<'i>> {
    if let Ok(cow) = parser.try_parse(|p| p.expect_string_cloned()) {
        return Ok(SingleFontFamily((*cow).to_owned()));
    }

    let first_ident = parser.expect_ident()?.clone();

    let mut value = first_ident.as_ref().to_owned();

    while let Ok(cow) = parser.try_parse(|p| p.expect_ident_cloned()) {
        value.push(' ');
        value.push_str(&cow);
    }

    Ok(SingleFontFamily(value))
}

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

    #[test]
    fn detects_invalid_invalid_font_size() {
        assert!(is_parse_error(&FontSizeSpec::parse_str("furlong")));
    }

    #[test]
    fn parses_font_weight() {
        assert_eq!(
            <FontWeightSpec as Parse>::parse_str("normal"),
            Ok(FontWeightSpec::Normal)
        );
        assert_eq!(
            <FontWeightSpec as Parse>::parse_str("bold"),
            Ok(FontWeightSpec::Bold)
        );
        assert_eq!(
            <FontWeightSpec as Parse>::parse_str("100"),
            Ok(FontWeightSpec::W100)
        );
    }

    #[test]
    fn detects_invalid_font_weight() {
        assert!(<FontWeightSpec as Parse>::parse_str("").is_err());
        assert!(<FontWeightSpec as Parse>::parse_str("strange").is_err());
        assert!(<FontWeightSpec as Parse>::parse_str("314").is_err());
        assert!(<FontWeightSpec as Parse>::parse_str("3.14").is_err());
    }

    #[test]
    fn parses_letter_spacing() {
        assert_eq!(
            <LetterSpacingSpec as Parse>::parse_str("normal"),
            Ok(LetterSpacingSpec::Normal)
        );
        assert_eq!(
            <LetterSpacingSpec as Parse>::parse_str("10em"),
            Ok(LetterSpacingSpec::Value(Length::<Horizontal>::new(
                10.0,
                LengthUnit::Em,
            )))
        );
    }

    #[test]
    fn computes_letter_spacing() {
        assert_eq!(
            <LetterSpacingSpec as Parse>::parse_str("normal").map(|s| s.compute()),
            Ok(LetterSpacingSpec::Value(Length::<Horizontal>::new(
                0.0,
                LengthUnit::Px,
            )))
        );
        assert_eq!(
            <LetterSpacingSpec as Parse>::parse_str("10em").map(|s| s.compute()),
            Ok(LetterSpacingSpec::Value(Length::<Horizontal>::new(
                10.0,
                LengthUnit::Em,
            )))
        );
    }

    #[test]
    fn detects_invalid_invalid_letter_spacing() {
        assert!(is_parse_error(&LetterSpacingSpec::parse_str("furlong")));
    }

    #[test]
    fn parses_font_family() {
        assert_eq!(
            <SingleFontFamily as Parse>::parse_str("'Hello world'"),
            Ok(SingleFontFamily("Hello world".to_owned()))
        );

        assert_eq!(
            <SingleFontFamily as Parse>::parse_str("\"Hello world\""),
            Ok(SingleFontFamily("Hello world".to_owned()))
        );

        assert_eq!(
            <SingleFontFamily as Parse>::parse_str("  Hello  world  "),
            Ok(SingleFontFamily("Hello world".to_owned()))
        );

        assert_eq!(
            <SingleFontFamily as Parse>::parse_str("Plonk"),
            Ok(SingleFontFamily("Plonk".to_owned()))
        );
    }

    #[test]
    fn detects_invalid_font_family() {
        assert!(<SingleFontFamily as Parse>::parse_str("").is_err());

        // assert!(<SingleFontFamily as Parse>::parse_str("''").is_err());

        assert!(<SingleFontFamily as Parse>::parse_str("42").is_err());
    }
}
<|endoftext|>