<commit_before>///! Utility functions for snapshot testing
use std::path::Path;

// Re-exports for use by other internal crates
pub use insta;
pub use test_utils::fixtures;

/// Generate snapshots from the paths of fixtures matching a glob pattern.
///
/// # Arguments
///
/// - `pattern`: glob pattern _within_ the fixtures folder
/// - `func`: the test function to run on the path of each file matching the `pattern`.
///
/// `insta`'s `glob` macro seems to have difficulties with our Rust module
/// layout (workspaces and nested modules). This function deals with that
/// by making the pattern relative to the fixtures and adding some other
/// conveniences.
pub fn snapshot_fixtures<F: FnMut(&Path)>(pattern: &str, func: F) {
    let mut settings = insta::Settings::clone_current();
    settings.set_prepend_module_to_snapshot(false);
    settings.bind(|| {
        insta::_macro_support::glob_exec(&fixtures(), pattern, func);
    });
}

/// Generate snapshots from the contents of fixtures matching a glob pattern.
///
/// # Arguments
///
/// - `pattern`: glob pattern _within_ the fixtures folder
/// - `func`: the test function to run on the content of each file matching the `pattern`.
pub fn snapshot_fixtures_content<F: FnMut(&str)>(pattern: &str, mut func: F) {
    snapshot_fixtures(pattern, |path| {
        let content = std::fs::read_to_string(path).expect("Unable to read file");
        func(&content)
    })
}

/// Generate snapshots from the path and contents of fixtures matching a glob pattern.
pub fn snapshot_fixtures_path_content<F: FnMut(&Path, &str)>(pattern: &str, mut func: F) {
    snapshot_fixtures(pattern, |path| {
        let content = std::fs::read_to_string(path).expect("Unable to read file");
        func(path, &content)
    })
}

/// Generate snapshots from JSON node fixtures matching a glob pattern.
///
/// # Arguments
///
/// - `pattern`: glob pattern _within_ the fixtures folder
/// - `func`: the test function to run on the content of each file matching the `pattern`.
pub fn snapshot_fixtures_nodes<F: FnMut(stencila_schema::Node)>(pattern: &str, mut func: F) {
    snapshot_fixtures(pattern, |path| {
        let json = std::fs::read_to_string(path).expect("Unable to read file");
        let node = serde_json::from_str(&json).expect("Unable to deserialize from JSON");
        func(node)
    })
}

/// Set the suffix for snapshots
pub fn snapshot_set_suffix<F: FnMut()>(suffix: &str, func: F) {
    let mut settings = insta::Settings::clone_current();
    settings.set_snapshot_suffix(suffix);
    settings.bind(func);
}

/// Add a suffix to snapshots
pub fn snapshot_add_suffix<F: FnMut()>(suffix: &str, func: F) {
    let mut settings = insta::Settings::clone_current();
    settings.set_snapshot_suffix([settings.snapshot_suffix().unwrap_or_default(), suffix].concat());
    settings.bind(func);
}
<commit_msg>test(Snapshots): Funtion for standard settings<commit_after>///! Utility functions for snapshot testing
use std::path::Path;

// Re-exports for use by other internal crates
pub use insta;
pub use test_utils::fixtures;

/// Use our default settings for snapshots.
pub fn snapshot_settings<F: FnMut()>(func: F) {
    let mut settings = insta::Settings::clone_current();
    settings.set_prepend_module_to_snapshot(false);
    settings.bind(func);
}

/// Generate snapshots from the paths of fixtures matching a glob pattern.
///
/// # Arguments
///
/// - `pattern`: glob pattern _within_ the fixtures folder
/// - `func`: the test function to run on the path of each file matching the `pattern`.
///
/// `insta`'s `glob` macro seems to have difficulties with our Rust module
/// layout (workspaces and nested modules). This function deals with that
/// by making the pattern relative to the fixtures and adding some other
/// conveniences.
pub fn snapshot_fixtures<F: FnMut(&Path)>(pattern: &str, func: F) {
    let mut settings = insta::Settings::clone_current();
    settings.set_prepend_module_to_snapshot(false);
    settings.bind(|| {
        insta::_macro_support::glob_exec(&fixtures(), pattern, func);
    });
}

/// Generate snapshots from the contents of fixtures matching a glob pattern.
///
/// # Arguments
///
/// - `pattern`: glob pattern _within_ the fixtures folder
/// - `func`: the test function to run on the content of each file matching the `pattern`.
pub fn snapshot_fixtures_content<F: FnMut(&str)>(pattern: &str, mut func: F) {
    snapshot_fixtures(pattern, |path| {
        let content = std::fs::read_to_string(path).expect("Unable to read file");
        func(&content)
    })
}

/// Generate snapshots from the path and contents of fixtures matching a glob pattern.
pub fn snapshot_fixtures_path_content<F: FnMut(&Path, &str)>(pattern: &str, mut func: F) {
    snapshot_fixtures(pattern, |path| {
        let content = std::fs::read_to_string(path).expect("Unable to read file");
        func(path, &content)
    })
}

/// Generate snapshots from JSON node fixtures matching a glob pattern.
///
/// # Arguments
///
/// - `pattern`: glob pattern _within_ the fixtures folder
/// - `func`: the test function to run on the content of each file matching the `pattern`.
pub fn snapshot_fixtures_nodes<F: FnMut(stencila_schema::Node)>(pattern: &str, mut func: F) {
    snapshot_fixtures(pattern, |path| {
        let json = std::fs::read_to_string(path).expect("Unable to read file");
        let node = serde_json::from_str(&json).expect("Unable to deserialize from JSON");
        func(node)
    })
}

/// Set the suffix for snapshots
pub fn snapshot_set_suffix<F: FnMut()>(suffix: &str, func: F) {
    let mut settings = insta::Settings::clone_current();
    settings.set_snapshot_suffix(suffix);
    settings.bind(func);
}

/// Add a suffix to snapshots
pub fn snapshot_add_suffix<F: FnMut()>(suffix: &str, func: F) {
    let mut settings = insta::Settings::clone_current();
    settings.set_snapshot_suffix([settings.snapshot_suffix().unwrap_or_default(), suffix].concat());
    settings.bind(func);
}
<|endoftext|>


<commit_before>use kay::{World, ActorSystem, TypedID};
use compact::COption;
use land_use::buildings::{UnitType, BuildingID, UnitIdx};
use simulation::{Sleeper, SleeperID, Instant, SimulationID, Duration};
use util::random::{seed, Rng};

use economy::households::household_kinds;
use self::household_kinds::family::FamilyID;
use self::household_kinds::grocery_shop::GroceryShopID;
use self::household_kinds::cow_farm::CowFarmID;
use self::household_kinds::grain_farm::GrainFarmID;
use self::household_kinds::vegetable_farm::VegetableFarmID;
use self::household_kinds::mill::MillID;
use self::household_kinds::bakery::BakeryID;
use self::household_kinds::neighboring_town_trade::NeighboringTownTradeID;
use land_use::buildings::BuildingStyle;
use land_use::vacant_lots::VacantLotID;
use land_use::zone_planning::BuildingIntent;
use planning::{PlanManagerID, Proposal, PrototypeID, Plan, GestureID, Gesture, GestureIntent};

// TODO: somehow get rid of this horrible duplication by having something like
// a pointer to an abstract Household trait...

#[derive(Copy, Clone, Debug)]
pub enum HouseholdTypeToSpawn {
    Family,
    GroceryShop,
    GrainFarm,
    CowFarm,
    VegetableFarm,
    Mill,
    Bakery,
    NeighboringTownTrade,
}

pub fn unit_type_for(household_type: HouseholdTypeToSpawn) -> UnitType {
    match household_type {
        HouseholdTypeToSpawn::Family => UnitType::Dwelling,
        HouseholdTypeToSpawn::GroceryShop => UnitType::Retail,
        HouseholdTypeToSpawn::GrainFarm
        | HouseholdTypeToSpawn::CowFarm
        | HouseholdTypeToSpawn::VegetableFarm => UnitType::Agriculture,
        HouseholdTypeToSpawn::Mill => UnitType::Mill,
        HouseholdTypeToSpawn::Bakery => UnitType::Bakery,
        HouseholdTypeToSpawn::NeighboringTownTrade => UnitType::NeighboringTownTrade,
    }
}

pub fn building_style_for(household_type: HouseholdTypeToSpawn) -> BuildingStyle {
    match household_type {
        HouseholdTypeToSpawn::Family => BuildingStyle::FamilyHouse,
        HouseholdTypeToSpawn::GroceryShop => BuildingStyle::GroceryShop,
        HouseholdTypeToSpawn::GrainFarm
        | HouseholdTypeToSpawn::CowFarm
        | HouseholdTypeToSpawn::VegetableFarm => BuildingStyle::Field,
        HouseholdTypeToSpawn::Mill => BuildingStyle::Mill,
        HouseholdTypeToSpawn::Bakery => BuildingStyle::Bakery,
        HouseholdTypeToSpawn::NeighboringTownTrade => BuildingStyle::NeighboringTownConnection,
    }
}

#[derive(Compact, Clone)]
pub struct ImmigrationManager {
    id: ImmigrationManagerID,
    simulation: SimulationID,
    development_manager: DevelopmentManagerID,
    state: ImmigrationManagerState,
}

impl ImmigrationManager {
    pub fn spawn(
        id: ImmigrationManagerID,
        simulation: SimulationID,
        development_manager: DevelopmentManagerID,
        world: &mut World,
    ) -> ImmigrationManager {
        simulation.wake_up_in(Duration::from_minutes(10).into(), id.into(), world);

        ImmigrationManager {
            id,
            simulation,
            development_manager,
            state: ImmigrationManagerState::Idle,
        }
    }
}

#[derive(Copy, Clone)]
pub enum ImmigrationManagerState {
    Idle,
    FindingBuilding(HouseholdTypeToSpawn),
}

impl Sleeper for ImmigrationManager {
    fn wake(&mut self, current_instant: Instant, world: &mut World) {
        self.state = match self.state {
            ImmigrationManagerState::Idle => {
                let family_share = 1.0;
                let grocery_share = 0.2;
                let cow_farm_share = 0.9;
                let veg_farm_share = 0.26;
                let grain_farm_share = 0.2; //0.0016;
                let mill_share = 0.2; //0.001;
                let bakery_share = 0.2; //0.01;

                let total_share = family_share
                    + grocery_share
                    + cow_farm_share
                    + veg_farm_share
                    + grain_farm_share
                    + mill_share
                    + bakery_share;

                let dot = seed(current_instant).gen_range(0.0, total_share);

                let household_type_to_spawn = if dot < family_share {
                    HouseholdTypeToSpawn::Family
                } else if dot < family_share + grocery_share {
                    HouseholdTypeToSpawn::GroceryShop
                } else if dot < family_share + grocery_share + cow_farm_share {
                    HouseholdTypeToSpawn::CowFarm
                } else if dot < family_share + grocery_share + cow_farm_share + veg_farm_share {
                    HouseholdTypeToSpawn::VegetableFarm
                } else if dot
                    < family_share
                        + grocery_share
                        + cow_farm_share
                        + veg_farm_share
                        + grain_farm_share
                {
                    HouseholdTypeToSpawn::GrainFarm
                } else if dot
                    < family_share
                        + grocery_share
                        + cow_farm_share
                        + veg_farm_share
                        + grain_farm_share
                        + mill_share
                {
                    HouseholdTypeToSpawn::Mill
                } else {
                    HouseholdTypeToSpawn::Bakery
                };

                println!("Trying to spawn {:?}", household_type_to_spawn);

                let required_unit_type = unit_type_for(household_type_to_spawn);

                BuildingID::global_broadcast(world).try_offer_unit(
                    required_unit_type,
                    self.id,
                    world,
                );

                ImmigrationManagerState::FindingBuilding(household_type_to_spawn)
            }
            ImmigrationManagerState::FindingBuilding(household_type_to_spawn) => {
                // didn't find a building in time
                self.development_manager
                    .try_develop(building_style_for(household_type_to_spawn), world);

                ImmigrationManagerState::Idle
            }
        };

        self.simulation
            .wake_up_in(Duration::from_minutes(10).into(), self.id.into(), world);
    }
}

impl ImmigrationManager {
    pub fn on_unit_offer(&mut self, building_id: BuildingID, unit_idx: UnitIdx, world: &mut World) {
        println!("Got offer");
        self.state = match self.state {
            ImmigrationManagerState::FindingBuilding(household_type_to_spawn) => {
                println!("Moving in");

                let household_id = match household_type_to_spawn {
                    HouseholdTypeToSpawn::Family => {
                        FamilyID::move_into(3, building_id, self.simulation, world).into()
                    }
                    HouseholdTypeToSpawn::GroceryShop => {
                        GroceryShopID::move_into(building_id, self.simulation, world).into()
                    }
                    HouseholdTypeToSpawn::GrainFarm => {
                        GrainFarmID::move_into(building_id, self.simulation, world).into()
                    }
                    HouseholdTypeToSpawn::CowFarm => {
                        CowFarmID::move_into(building_id, self.simulation, world).into()
                    }
                    HouseholdTypeToSpawn::VegetableFarm => {
                        VegetableFarmID::move_into(building_id, self.simulation, world).into()
                    }
                    HouseholdTypeToSpawn::Mill => {
                        MillID::move_into(building_id, self.simulation, world).into()
                    }
                    HouseholdTypeToSpawn::Bakery => {
                        BakeryID::move_into(building_id, self.simulation, world).into()
                    }
                    HouseholdTypeToSpawn::NeighboringTownTrade => {
                        NeighboringTownTradeID::move_into(building_id, self.simulation, world)
                            .into()
                    }
                };

                building_id.add_household(household_id, unit_idx, world);

                ImmigrationManagerState::Idle
            }
            ImmigrationManagerState::Idle => ImmigrationManagerState::Idle,
        }
    }
}

#[derive(Compact, Clone)]
pub struct DevelopmentManager {
    id: DevelopmentManagerID,
    simulation: SimulationID,
    plan_manager: PlanManagerID,
    building_to_develop: COption<BuildingStyle>,
}

impl DevelopmentManager {
    pub fn spawn(
        id: DevelopmentManagerID,
        simulation: SimulationID,
        plan_manager: PlanManagerID,
        _world: &mut World,
    ) -> DevelopmentManager {
        DevelopmentManager {
            id,
            simulation,
            plan_manager,
            building_to_develop: COption(None),
        }
    }

    pub fn try_develop(&mut self, building_style: BuildingStyle, world: &mut World) {
        if self.building_to_develop.is_none() {
            println!("Trying to develop {:?}", building_style);
            self.building_to_develop = COption(Some(building_style));
            VacantLotID::global_broadcast(world).suggest_lot(building_style, self.id, world);
            self.simulation
                .wake_up_in(Duration::from_minutes(10).into(), self.id.into(), world);
        }
    }

    pub fn on_suggested_lot(
        &mut self,
        building_intent: &BuildingIntent,
        based_on: PrototypeID,
        world: &mut World,
    ) {
        if let Some(building_to_develop) = *self.building_to_develop {
            if building_to_develop == building_intent.building_style {
                println!("Adding to plan {:?}", building_intent.building_style);
                self.plan_manager.implement_artificial_proposal(
                    Proposal::from_plan(Plan::from_gestures(Some((
                        GestureID::new(),
                        Gesture::new(
                            vec![building_intent.lot.center_point()].into(),
                            GestureIntent::Building(building_intent.clone()),
                        ),
                    )))),
                    vec![based_on].into(),
                    world,
                );
                self.building_to_develop = COption(None);
            }
        }
    }
}

impl Sleeper for DevelopmentManager {
    fn wake(&mut self, _: Instant, _world: &mut World) {
        self.building_to_develop = COption(None);
    }
}

pub fn setup(system: &mut ActorSystem) {
    system.register::<ImmigrationManager>();
    system.register::<DevelopmentManager>();
    auto_setup(system);
}

pub fn spawn(world: &mut World, simulation: SimulationID, plan_manager: PlanManagerID) {
    let development_manager = DevelopmentManagerID::spawn(simulation, plan_manager, world);
    ImmigrationManagerID::spawn(simulation, development_manager, world);
}

mod kay_auto;
pub use self::kay_auto::*;
<commit_msg>Increase building spawning rate<commit_after>use kay::{World, ActorSystem, TypedID};
use compact::COption;
use land_use::buildings::{UnitType, BuildingID, UnitIdx};
use simulation::{Sleeper, SleeperID, Instant, SimulationID, Duration};
use util::random::{seed, Rng};

use economy::households::household_kinds;
use self::household_kinds::family::FamilyID;
use self::household_kinds::grocery_shop::GroceryShopID;
use self::household_kinds::cow_farm::CowFarmID;
use self::household_kinds::grain_farm::GrainFarmID;
use self::household_kinds::vegetable_farm::VegetableFarmID;
use self::household_kinds::mill::MillID;
use self::household_kinds::bakery::BakeryID;
use self::household_kinds::neighboring_town_trade::NeighboringTownTradeID;
use land_use::buildings::BuildingStyle;
use land_use::vacant_lots::VacantLotID;
use land_use::zone_planning::BuildingIntent;
use planning::{PlanManagerID, Proposal, PrototypeID, Plan, GestureID, Gesture, GestureIntent};

// TODO: somehow get rid of this horrible duplication by having something like
// a pointer to an abstract Household trait...

#[derive(Copy, Clone, Debug)]
pub enum HouseholdTypeToSpawn {
    Family,
    GroceryShop,
    GrainFarm,
    CowFarm,
    VegetableFarm,
    Mill,
    Bakery,
    NeighboringTownTrade,
}

pub fn unit_type_for(household_type: HouseholdTypeToSpawn) -> UnitType {
    match household_type {
        HouseholdTypeToSpawn::Family => UnitType::Dwelling,
        HouseholdTypeToSpawn::GroceryShop => UnitType::Retail,
        HouseholdTypeToSpawn::GrainFarm
        | HouseholdTypeToSpawn::CowFarm
        | HouseholdTypeToSpawn::VegetableFarm => UnitType::Agriculture,
        HouseholdTypeToSpawn::Mill => UnitType::Mill,
        HouseholdTypeToSpawn::Bakery => UnitType::Bakery,
        HouseholdTypeToSpawn::NeighboringTownTrade => UnitType::NeighboringTownTrade,
    }
}

pub fn building_style_for(household_type: HouseholdTypeToSpawn) -> BuildingStyle {
    match household_type {
        HouseholdTypeToSpawn::Family => BuildingStyle::FamilyHouse,
        HouseholdTypeToSpawn::GroceryShop => BuildingStyle::GroceryShop,
        HouseholdTypeToSpawn::GrainFarm
        | HouseholdTypeToSpawn::CowFarm
        | HouseholdTypeToSpawn::VegetableFarm => BuildingStyle::Field,
        HouseholdTypeToSpawn::Mill => BuildingStyle::Mill,
        HouseholdTypeToSpawn::Bakery => BuildingStyle::Bakery,
        HouseholdTypeToSpawn::NeighboringTownTrade => BuildingStyle::NeighboringTownConnection,
    }
}

#[derive(Compact, Clone)]
pub struct ImmigrationManager {
    id: ImmigrationManagerID,
    simulation: SimulationID,
    development_manager: DevelopmentManagerID,
    state: ImmigrationManagerState,
}

impl ImmigrationManager {
    pub fn spawn(
        id: ImmigrationManagerID,
        simulation: SimulationID,
        development_manager: DevelopmentManagerID,
        world: &mut World,
    ) -> ImmigrationManager {
        simulation.wake_up_in(IMMIGRATION_PACE.into(), id.into(), world);

        ImmigrationManager {
            id,
            simulation,
            development_manager,
            state: ImmigrationManagerState::Idle,
        }
    }
}

#[derive(Copy, Clone)]
pub enum ImmigrationManagerState {
    Idle,
    FindingBuilding(HouseholdTypeToSpawn),
}

const IMMIGRATION_PACE: Duration = Duration(10);

impl Sleeper for ImmigrationManager {
    fn wake(&mut self, current_instant: Instant, world: &mut World) {
        self.state = match self.state {
            ImmigrationManagerState::Idle => {
                let family_share = 1.0;
                let grocery_share = 0.2;
                let cow_farm_share = 0.9;
                let veg_farm_share = 0.26;
                let grain_farm_share = 0.2; //0.0016;
                let mill_share = 0.2; //0.001;
                let bakery_share = 0.2; //0.01;

                let total_share = family_share
                    + grocery_share
                    + cow_farm_share
                    + veg_farm_share
                    + grain_farm_share
                    + mill_share
                    + bakery_share;

                let dot = seed(current_instant).gen_range(0.0, total_share);

                let household_type_to_spawn = if dot < family_share {
                    HouseholdTypeToSpawn::Family
                } else if dot < family_share + grocery_share {
                    HouseholdTypeToSpawn::GroceryShop
                } else if dot < family_share + grocery_share + cow_farm_share {
                    HouseholdTypeToSpawn::CowFarm
                } else if dot < family_share + grocery_share + cow_farm_share + veg_farm_share {
                    HouseholdTypeToSpawn::VegetableFarm
                } else if dot
                    < family_share
                        + grocery_share
                        + cow_farm_share
                        + veg_farm_share
                        + grain_farm_share
                {
                    HouseholdTypeToSpawn::GrainFarm
                } else if dot
                    < family_share
                        + grocery_share
                        + cow_farm_share
                        + veg_farm_share
                        + grain_farm_share
                        + mill_share
                {
                    HouseholdTypeToSpawn::Mill
                } else {
                    HouseholdTypeToSpawn::Bakery
                };

                println!("Trying to spawn {:?}", household_type_to_spawn);

                let required_unit_type = unit_type_for(household_type_to_spawn);

                BuildingID::global_broadcast(world).try_offer_unit(
                    required_unit_type,
                    self.id,
                    world,
                );

                ImmigrationManagerState::FindingBuilding(household_type_to_spawn)
            }
            ImmigrationManagerState::FindingBuilding(household_type_to_spawn) => {
                // didn't find a building in time
                self.development_manager
                    .try_develop(building_style_for(household_type_to_spawn), world);

                ImmigrationManagerState::Idle
            }
        };

        self.simulation
            .wake_up_in(IMMIGRATION_PACE.into(), self.id.into(), world);
    }
}

impl ImmigrationManager {
    pub fn on_unit_offer(&mut self, building_id: BuildingID, unit_idx: UnitIdx, world: &mut World) {
        println!("Got offer");
        self.state = match self.state {
            ImmigrationManagerState::FindingBuilding(household_type_to_spawn) => {
                println!("Moving in");

                let household_id = match household_type_to_spawn {
                    HouseholdTypeToSpawn::Family => {
                        FamilyID::move_into(3, building_id, self.simulation, world).into()
                    }
                    HouseholdTypeToSpawn::GroceryShop => {
                        GroceryShopID::move_into(building_id, self.simulation, world).into()
                    }
                    HouseholdTypeToSpawn::GrainFarm => {
                        GrainFarmID::move_into(building_id, self.simulation, world).into()
                    }
                    HouseholdTypeToSpawn::CowFarm => {
                        CowFarmID::move_into(building_id, self.simulation, world).into()
                    }
                    HouseholdTypeToSpawn::VegetableFarm => {
                        VegetableFarmID::move_into(building_id, self.simulation, world).into()
                    }
                    HouseholdTypeToSpawn::Mill => {
                        MillID::move_into(building_id, self.simulation, world).into()
                    }
                    HouseholdTypeToSpawn::Bakery => {
                        BakeryID::move_into(building_id, self.simulation, world).into()
                    }
                    HouseholdTypeToSpawn::NeighboringTownTrade => {
                        NeighboringTownTradeID::move_into(building_id, self.simulation, world)
                            .into()
                    }
                };

                building_id.add_household(household_id, unit_idx, world);

                ImmigrationManagerState::Idle
            }
            ImmigrationManagerState::Idle => ImmigrationManagerState::Idle,
        }
    }
}

#[derive(Compact, Clone)]
pub struct DevelopmentManager {
    id: DevelopmentManagerID,
    simulation: SimulationID,
    plan_manager: PlanManagerID,
    building_to_develop: COption<BuildingStyle>,
}

impl DevelopmentManager {
    pub fn spawn(
        id: DevelopmentManagerID,
        simulation: SimulationID,
        plan_manager: PlanManagerID,
        _world: &mut World,
    ) -> DevelopmentManager {
        DevelopmentManager {
            id,
            simulation,
            plan_manager,
            building_to_develop: COption(None),
        }
    }

    pub fn try_develop(&mut self, building_style: BuildingStyle, world: &mut World) {
        if self.building_to_develop.is_none() {
            println!("Trying to develop {:?}", building_style);
            self.building_to_develop = COption(Some(building_style));
            VacantLotID::global_broadcast(world).suggest_lot(building_style, self.id, world);
            self.simulation
                .wake_up_in(IMMIGRATION_PACE.into(), self.id.into(), world);
        }
    }

    pub fn on_suggested_lot(
        &mut self,
        building_intent: &BuildingIntent,
        based_on: PrototypeID,
        world: &mut World,
    ) {
        if let Some(building_to_develop) = *self.building_to_develop {
            if building_to_develop == building_intent.building_style {
                println!("Adding to plan {:?}", building_intent.building_style);
                self.plan_manager.implement_artificial_proposal(
                    Proposal::from_plan(Plan::from_gestures(Some((
                        GestureID::new(),
                        Gesture::new(
                            vec![building_intent.lot.center_point()].into(),
                            GestureIntent::Building(building_intent.clone()),
                        ),
                    )))),
                    vec![based_on].into(),
                    world,
                );
                self.building_to_develop = COption(None);
            }
        }
    }
}

impl Sleeper for DevelopmentManager {
    fn wake(&mut self, _: Instant, _world: &mut World) {
        self.building_to_develop = COption(None);
    }
}

pub fn setup(system: &mut ActorSystem) {
    system.register::<ImmigrationManager>();
    system.register::<DevelopmentManager>();
    auto_setup(system);
}

pub fn spawn(world: &mut World, simulation: SimulationID, plan_manager: PlanManagerID) {
    let development_manager = DevelopmentManagerID::spawn(simulation, plan_manager, world);
    ImmigrationManagerID::spawn(simulation, development_manager, world);
}

mod kay_auto;
pub use self::kay_auto::*;
<|endoftext|>


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

//! # gl_generator
//!
//! `gl_generator` is an OpenGL bindings generator plugin. It defines a macro
//!  named `generate_gl_bindings!` which can be used to generate all constants
//!  and functions of a given OpenGL version.
//!
//! ## Example
//!
//! ~~~rust
//! #[phase(plugin)]
//! extern crate gl_generator;
//!
//! use self::types::*;
//!
//! generate_gl_bindings! {
//!     api: "gl",
//!     profile: "core",
//!     version: "4.5",
//!     generator: "global",
//!     extensions: [
//!         "GL_EXT_texture_filter_anisotropic",
//!     ],
//! }
//! ~~~
//!
//! ## Arguments
//!
//! Each field can be specified at most once, or not at all. If the field is not
//! specified, then a default value will be used.
//!
//! - `api`: The API to generate. Can be either `"gl"`, `"gles1"`, `"gles2"`,
//!   `"wgl"`, `"glx"`, `"egl"`. Defaults to `"gl"`.
//! - `profile`: Can be either `"core"` or `"compatibility"`. Defaults to
//!   `"core"`. `"core"` will only include all functions supported by the
//!   requested version it self, while `"compatibility"` will include all the
//!   functions from previous versions as well.
//! - `version`: The requested API version. This is usually in the form
//!   `"major.minor"`. Defaults to `"1.0"`
//! - `generator`: The type of loader to generate. Can be either `"static"`,
//!   `"global"`, or `"struct"`. Defaults to `"static"`.
//! - `extensions`: Extra extensions to include in the bindings. These are
//!   specified as a list of strings. Defaults to `[]`.
//!
//! ## About EGL
//!
//! When you generate bindings for EGL, the following platform-specific types must be declared
//!  *at the same level where you call `generate_gl_bindings`*:
//!
//! - `khronos_utime_nanoseconds_t`
//! - `khronos_uint64_t`
//! - `khronos_ssize_t`
//! - `EGLNativeDisplayType`
//! - `EGLNativePixmapType`
//! - `EGLNativeWindowType`
//! - `EGLint`
//! - `NativeDisplayType`
//! - `NativePixmapType`
//! - `NativeWindowType`
//!

#![crate_name = "gl_generator"]
#![crate_type = "dylib"]

#![feature(advanced_slice_patterns)]
#![feature(macro_rules)]
#![feature(phase)]
#![feature(plugin_registrar)]
#![feature(quote)]

#[phase(plugin, link)]
extern crate log;

#[phase(plugin)]
extern crate regex_macros;

extern crate khronos_api;
extern crate regex;
extern crate rustc;
extern crate syntax;

use generators::Generator;
use registry::{Registry, Filter, Ns};
use syntax::ast::{TokenTree, TtDelimited, TtToken};
use syntax::codemap::Span;
use syntax::ext::base::{DummyResult, ExtCtxt, MacResult, MacItems};
use syntax::parse::token;

pub mod generators;

#[allow(dead_code)]
pub mod registry;

#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(reg: &mut ::rustc::plugin::Registry) {
    reg.register_macro("generate_gl_bindings", macro_handler);
}

/// A predicate that is useful for splitting a comma separated list of tokens
fn is_comma(tt: &TokenTree) -> bool {
    match *tt {
        TtToken(_, token::Comma) => true,
        _ => false,
    }
}

/// Drops a trailing comma if it exists
fn drop_trailing_comma(tts: &[TokenTree]) -> &[TokenTree] {
    match tts {
        [tts.., TtToken(_, token::Comma)] => tts,
        tts => tts,
    }
}

/// handler for generate_gl_bindings!
fn macro_handler(ecx: &mut ExtCtxt, span: Span, tts: &[TokenTree]) -> Box<MacResult+'static> {
    return generate_bindings(ecx, span, tts, vec![
        ("static", box generators::static_gen::StaticGenerator as Box<Generator>),
        ("global", box generators::global_gen::GlobalGenerator as Box<Generator>),
        ("struct", box generators::struct_gen::StructGenerator as Box<Generator>),
        ("static_struct", box generators::static_struct_gen::StaticStructGenerator as Box<Generator>),
    ]);
}

/// Entry point for generating bindings based on a syntax extension invocation.
pub fn generate_bindings(ecx: &mut ExtCtxt, span: Span, tts: &[TokenTree],
                     generators: Vec<(&str, Box<Generator>)>) -> Box<MacResult+'static> {
    // Generator options
    let mut api = None::<(Ns, &'static [u8])>;
    let mut profile = None::<String>;
    let mut version = None::<String>;
    let mut generator = None::<Box<Generator>>;
    let mut extensions = None::<Vec<String>>;
    let mut generators = Some(generators);

    let tts = drop_trailing_comma(tts);

    // Iterate through the comma separated
    for tts in tts.split(is_comma) {
        let mut it = tts.iter();
        let field = match it.next() {
            Some(&TtToken(_, token::Ident(ref field, _))) => field.as_str(),
            tt => {
                let span = tt.map(|tt| tt.get_span()).unwrap_or(span);
                ecx.span_err(span, "Expected a generator argument name, \
                                    either: `api`, `profile`, `version`, \
                                    `generator`, or `extensions`.");
                return DummyResult::any(span);
            },
        };
        match it.next() {
            Some(&TtToken(_, token::Colon)) => {},
            tt => {
                let span = tt.map(|tt| tt.get_span()).unwrap_or(span);
                ecx.span_err(span, "Expected `:`");
                return DummyResult::any(span);
            },
        }
        match (field, it.collect::<Vec<_>>().as_slice()) {
            ("api", tts) => {
                if api.is_some() {
                    let span = tts.head().map_or(span, |tt| tt.get_span());
                    ecx.span_err(span, "An API was already specified.");
                    return DummyResult::any(span);
                }
                api = Some(match tts {
                    [&TtToken(_, token::Literal(token::Str_(api), None))] if api.as_str() == "gl"
                        => (registry::Ns::Gl, khronos_api::GL_XML),
                    [&TtToken(_, token::Literal(token::Str_(api), None))] if api.as_str() == "glx"
                        => (registry::Ns::Glx, khronos_api::GLX_XML),
                    [&TtToken(_, token::Literal(token::Str_(api), None))] if api.as_str() == "wgl"
                        => (registry::Ns::Wgl, khronos_api::WGL_XML),
                    [&TtToken(_, token::Literal(token::Str_(api), None))] if api.as_str() == "egl"
                        => (registry::Ns::Egl, khronos_api::EGL_XML),
                    [&TtToken(_, token::Literal(token::Str_(api), None))] if api.as_str() == "gles1"
                        => (registry::Ns::Gles1, khronos_api::GL_XML),
                    [&TtToken(_, token::Literal(token::Str_(api), None))] if api.as_str() == "gles2"
                        => (registry::Ns::Gles2, khronos_api::GL_XML),
                    [&TtToken(span, token::Literal(token::Str_(api), None))] => {
                        ecx.span_err(span, format!("Unknown API \"{}\"", api.as_str()).as_slice());
                        return DummyResult::any(span);
                    },
                    _ => {
                        let span = tts.head().map_or(span, |tt| tt.get_span());
                        ecx.span_err(span, "Invalid API format, expected \
                                            string.");
                        return DummyResult::any(span);
                    }
                })
            }
            ("profile", tts) => {
                if profile.is_some() {
                    ecx.span_err(tts[0].get_span(), "A profile was already specified.");
                    return DummyResult::any(span);
                }
                profile = Some(match tts {
                    [&TtToken(_, token::Literal(token::Str_(profile), None))] if profile.as_str() == "core"
                        => "core".to_string(),
                    [&TtToken(_, token::Literal(token::Str_(profile), None))] if profile.as_str() == "compatibility"
                        => "compatibility".to_string(),
                    [&TtToken(_, token::Literal(token::Str_(profile), None))] => {
                        let span = tts.head().map_or(span, |tt| tt.get_span());
                        ecx.span_err(span, format!("Unknown profile \"{}\"",
                                                   profile.as_str()).as_slice());
                        return DummyResult::any(span);
                    },
                    _ => {
                        let span = tts.head().map_or(span, |tt| tt.get_span());
                        ecx.span_err(span, "Invalid profile format, expected \
                                            string.");
                        return DummyResult::any(span);
                    },
                })
            }
            ("version", tts) => {
                if version.is_some() {
                    let span = tts.head().map_or(span, |tt| tt.get_span());
                    ecx.span_err(span, "A version was already specified.");
                    return DummyResult::any(span);
                }
                version = Some(match tts {
                    [&TtToken(_, token::Literal(token::Str_(version), None))] => {
                        version.as_str().to_string()
                    },
                    _ => {
                        let span = tts.head().map_or(span, |tt| tt.get_span());
                        ecx.span_err(span, "Invalid version format, expected \
                                            string.");
                        return DummyResult::any(span);
                    },
                });
            }
            ("generator", tts) => {
                if generator.is_some() {
                    let span = tts.head().map_or(span, |tt| tt.get_span());
                    ecx.span_err(span, "A generator was already specified.");
                    return DummyResult::any(span);
                }
                match tts {
                    [&TtToken(span, token::Literal(token::Str_(gen), None))] => {
                        if generators.is_none() { continue; }
                        for (name, generator_) in generators.take().unwrap().into_iter() {
                            if name == gen.as_str() {
                                generator = Some(generator_);
                                break;
                            }
                        }
                        if generator.is_none() {
                            ecx.span_err(span, format!("Unknown generator \"{}\"",
                                                       gen.as_str()).as_slice());
                            return DummyResult::any(span);
                        }
                    },
                    _ => {
                        let span = tts.head().map_or(span, |tt| tt.get_span());
                        ecx.span_err(span, "Invalid generator format, expected \
                                            string.");
                        return DummyResult::any(span);
                    },
                };
            }
            ("extensions", tts) => {
                if extensions.is_some() {
                    let span = tts.head().map_or(span, |tt| tt.get_span());
                    ecx.span_err(span, "The list of extensions were already \
                                        specified.");
                    return DummyResult::any(span);
                }
                extensions = Some(match tts {
                    [&TtDelimited(span, ref delimited)]
                    if delimited.delim == token::Bracket => {
                        // Drop the trailing comma if it exists
                        let tts = drop_trailing_comma(delimited.tts.as_slice());

                        // Collect the extensions, breaking early if a parse
                        // error occurs.
                        let mut failed = false;
                        let exts = tts.split(is_comma).scan((), |_, tts| {
                            match tts {
                                [TtToken(_, token::Literal(token::Str_(ext), None))] => {
                                    Some(ext.as_str().to_string())
                                },
                                _ => {
                                    failed = true;
                                    None
                                },
                            }
                        }).collect();

                        // Cause an error if there is still some leftover
                        // tokens.
                        if failed {
                            ecx.span_err(span, "Invalid extension format, \
                                                expected string.");
                            return DummyResult::any(span);
                        } else {
                            exts
                        }
                    },
                    _ => {
                        ecx.span_err(span, "Expected a list of extension strings.");
                        return DummyResult::any(span);
                    }
                });
            }
            (field, _) => {
                ecx.span_err(span, format!("Unknown field `{}`", field).as_slice());
                return DummyResult::any(span);
            }
        }
    }

    // Use default values if the parameters have not been set
    let (ns, source) = api.unwrap_or((registry::Ns::Gl, khronos_api::GL_XML));
    let extensions = extensions.unwrap_or(vec![]);
    let version = version.unwrap_or("1.0".to_string());
    let generator = generator.unwrap_or(box generators::static_gen::StaticGenerator);
    let profile = profile.unwrap_or("core".to_string());

    // Get generator field values, using default values if they have not been
    // specified
    let filter = Some(Filter {
        api: ns.to_string(),
        extensions: extensions,
        version: version,
        profile: profile,
    });

    // Generate the registry of all bindings
    let registry = {
        use std::io::BufReader;
        use std::task;

        let result = task::try(proc() {
            let reader = BufReader::new(source);
            Registry::from_xml(reader, ns, filter)
        });

        match result {
            Ok(reg) => reg,
            Err(err) => {
                use std::any::{Any, AnyRefExt};
                let err: &Any = &*err;

                match err {
                    err if err.is::<String>() => {
                        ecx.span_err(span, "error while parsing the registry");
                        ecx.span_err(span, err.downcast_ref::<String>().unwrap().as_slice());
                    },
                    err if err.is::<&'static str>() => {
                        ecx.span_err(span, "error while parsing the registry");
                        ecx.span_err(span, err.downcast_ref::<&'static str>().unwrap().as_slice());
                    },
                    _ => {
                        ecx.span_err(span, "unknown error while parsing the registry");
                    }
                }

                return DummyResult::any(span);
            }
        }
    };

    // generating the Rust bindings as a source code into "buffer"
    let items = generator.write(ecx, &registry, ns);

    MacItems::new(items.into_iter())
}
<commit_msg>Update for Rustc<commit_after>// Copyright 2013-2014 The gl-rs developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! # gl_generator
//!
//! `gl_generator` is an OpenGL bindings generator plugin. It defines a macro
//!  named `generate_gl_bindings!` which can be used to generate all constants
//!  and functions of a given OpenGL version.
//!
//! ## Example
//!
//! ~~~rust
//! #[phase(plugin)]
//! extern crate gl_generator;
//!
//! use self::types::*;
//!
//! generate_gl_bindings! {
//!     api: "gl",
//!     profile: "core",
//!     version: "4.5",
//!     generator: "global",
//!     extensions: [
//!         "GL_EXT_texture_filter_anisotropic",
//!     ],
//! }
//! ~~~
//!
//! ## Arguments
//!
//! Each field can be specified at most once, or not at all. If the field is not
//! specified, then a default value will be used.
//!
//! - `api`: The API to generate. Can be either `"gl"`, `"gles1"`, `"gles2"`,
//!   `"wgl"`, `"glx"`, `"egl"`. Defaults to `"gl"`.
//! - `profile`: Can be either `"core"` or `"compatibility"`. Defaults to
//!   `"core"`. `"core"` will only include all functions supported by the
//!   requested version it self, while `"compatibility"` will include all the
//!   functions from previous versions as well.
//! - `version`: The requested API version. This is usually in the form
//!   `"major.minor"`. Defaults to `"1.0"`
//! - `generator`: The type of loader to generate. Can be either `"static"`,
//!   `"global"`, or `"struct"`. Defaults to `"static"`.
//! - `extensions`: Extra extensions to include in the bindings. These are
//!   specified as a list of strings. Defaults to `[]`.
//!
//! ## About EGL
//!
//! When you generate bindings for EGL, the following platform-specific types must be declared
//!  *at the same level where you call `generate_gl_bindings`*:
//!
//! - `khronos_utime_nanoseconds_t`
//! - `khronos_uint64_t`
//! - `khronos_ssize_t`
//! - `EGLNativeDisplayType`
//! - `EGLNativePixmapType`
//! - `EGLNativeWindowType`
//! - `EGLint`
//! - `NativeDisplayType`
//! - `NativePixmapType`
//! - `NativeWindowType`
//!

#![crate_name = "gl_generator"]
#![crate_type = "dylib"]

#![feature(advanced_slice_patterns)]
#![feature(macro_rules)]
#![feature(phase)]
#![feature(plugin_registrar)]
#![feature(quote)]

#[phase(plugin, link)]
extern crate log;

#[phase(plugin)]
extern crate regex_macros;

extern crate khronos_api;
extern crate regex;
extern crate rustc;
extern crate syntax;

use generators::Generator;
use registry::{Registry, Filter, Ns};
use syntax::ast::{TokenTree, TtDelimited, TtToken};
use syntax::codemap::Span;
use syntax::ext::base::{DummyResult, ExtCtxt, MacResult, MacItems};
use syntax::parse::token;

pub mod generators;

#[allow(dead_code)]
pub mod registry;

#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(reg: &mut ::rustc::plugin::Registry) {
    reg.register_macro("generate_gl_bindings", macro_handler);
}

/// A predicate that is useful for splitting a comma separated list of tokens
fn is_comma(tt: &TokenTree) -> bool {
    match *tt {
        TtToken(_, token::Comma) => true,
        _ => false,
    }
}

/// Drops a trailing comma if it exists
fn drop_trailing_comma(tts: &[TokenTree]) -> &[TokenTree] {
    match tts {
        [tts.., TtToken(_, token::Comma)] => tts,
        tts => tts,
    }
}

/// handler for generate_gl_bindings!
fn macro_handler(ecx: &mut ExtCtxt, span: Span, tts: &[TokenTree]) -> Box<MacResult+'static> {
    return generate_bindings(ecx, span, tts, vec![
        ("static", box generators::static_gen::StaticGenerator as Box<Generator>),
        ("global", box generators::global_gen::GlobalGenerator as Box<Generator>),
        ("struct", box generators::struct_gen::StructGenerator as Box<Generator>),
        ("static_struct", box generators::static_struct_gen::StaticStructGenerator as Box<Generator>),
    ]);
}

/// Entry point for generating bindings based on a syntax extension invocation.
pub fn generate_bindings(ecx: &mut ExtCtxt, span: Span, tts: &[TokenTree],
                     generators: Vec<(&str, Box<Generator>)>) -> Box<MacResult+'static> {
    // Generator options
    let mut api = None::<(Ns, &'static [u8])>;
    let mut profile = None::<String>;
    let mut version = None::<String>;
    let mut generator = None::<Box<Generator>>;
    let mut extensions = None::<Vec<String>>;
    let mut generators = Some(generators);

    let tts = drop_trailing_comma(tts);

    // Iterate through the comma separated
    for tts in tts.split(is_comma) {
        let mut it = tts.iter();
        let field = match it.next() {
            Some(&TtToken(_, token::Ident(ref field, _))) => field.as_str(),
            tt => {
                let span = tt.map(|tt| tt.get_span()).unwrap_or(span);
                ecx.span_err(span, "Expected a generator argument name, \
                                    either: `api`, `profile`, `version`, \
                                    `generator`, or `extensions`.");
                return DummyResult::any(span);
            },
        };
        match it.next() {
            Some(&TtToken(_, token::Colon)) => {},
            tt => {
                let span = tt.map(|tt| tt.get_span()).unwrap_or(span);
                ecx.span_err(span, "Expected `:`");
                return DummyResult::any(span);
            },
        }
        match (field, it.collect::<Vec<_>>().as_slice()) {
            ("api", tts) => {
                if api.is_some() {
                    let span = tts.head().map_or(span, |tt| tt.get_span());
                    ecx.span_err(span, "An API was already specified.");
                    return DummyResult::any(span);
                }
                api = Some(match tts {
                    [&TtToken(_, token::Literal(token::Str_(api), None))] if api.as_str() == "gl"
                        => (registry::Ns::Gl, khronos_api::GL_XML),
                    [&TtToken(_, token::Literal(token::Str_(api), None))] if api.as_str() == "glx"
                        => (registry::Ns::Glx, khronos_api::GLX_XML),
                    [&TtToken(_, token::Literal(token::Str_(api), None))] if api.as_str() == "wgl"
                        => (registry::Ns::Wgl, khronos_api::WGL_XML),
                    [&TtToken(_, token::Literal(token::Str_(api), None))] if api.as_str() == "egl"
                        => (registry::Ns::Egl, khronos_api::EGL_XML),
                    [&TtToken(_, token::Literal(token::Str_(api), None))] if api.as_str() == "gles1"
                        => (registry::Ns::Gles1, khronos_api::GL_XML),
                    [&TtToken(_, token::Literal(token::Str_(api), None))] if api.as_str() == "gles2"
                        => (registry::Ns::Gles2, khronos_api::GL_XML),
                    [&TtToken(span, token::Literal(token::Str_(api), None))] => {
                        ecx.span_err(span, format!("Unknown API \"{}\"", api.as_str()).as_slice());
                        return DummyResult::any(span);
                    },
                    _ => {
                        let span = tts.head().map_or(span, |tt| tt.get_span());
                        ecx.span_err(span, "Invalid API format, expected \
                                            string.");
                        return DummyResult::any(span);
                    }
                })
            }
            ("profile", tts) => {
                if profile.is_some() {
                    ecx.span_err(tts[0].get_span(), "A profile was already specified.");
                    return DummyResult::any(span);
                }
                profile = Some(match tts {
                    [&TtToken(_, token::Literal(token::Str_(profile), None))] if profile.as_str() == "core"
                        => "core".to_string(),
                    [&TtToken(_, token::Literal(token::Str_(profile), None))] if profile.as_str() == "compatibility"
                        => "compatibility".to_string(),
                    [&TtToken(_, token::Literal(token::Str_(profile), None))] => {
                        let span = tts.head().map_or(span, |tt| tt.get_span());
                        ecx.span_err(span, format!("Unknown profile \"{}\"",
                                                   profile.as_str()).as_slice());
                        return DummyResult::any(span);
                    },
                    _ => {
                        let span = tts.head().map_or(span, |tt| tt.get_span());
                        ecx.span_err(span, "Invalid profile format, expected \
                                            string.");
                        return DummyResult::any(span);
                    },
                })
            }
            ("version", tts) => {
                if version.is_some() {
                    let span = tts.head().map_or(span, |tt| tt.get_span());
                    ecx.span_err(span, "A version was already specified.");
                    return DummyResult::any(span);
                }
                version = Some(match tts {
                    [&TtToken(_, token::Literal(token::Str_(version), None))] => {
                        version.as_str().to_string()
                    },
                    _ => {
                        let span = tts.head().map_or(span, |tt| tt.get_span());
                        ecx.span_err(span, "Invalid version format, expected \
                                            string.");
                        return DummyResult::any(span);
                    },
                });
            }
            ("generator", tts) => {
                if generator.is_some() {
                    let span = tts.head().map_or(span, |tt| tt.get_span());
                    ecx.span_err(span, "A generator was already specified.");
                    return DummyResult::any(span);
                }
                match tts {
                    [&TtToken(span, token::Literal(token::Str_(gen), None))] => {
                        if generators.is_none() { continue; }
                        for (name, generator_) in generators.take().unwrap().into_iter() {
                            if name == gen.as_str() {
                                generator = Some(generator_);
                                break;
                            }
                        }
                        if generator.is_none() {
                            ecx.span_err(span, format!("Unknown generator \"{}\"",
                                                       gen.as_str()).as_slice());
                            return DummyResult::any(span);
                        }
                    },
                    _ => {
                        let span = tts.head().map_or(span, |tt| tt.get_span());
                        ecx.span_err(span, "Invalid generator format, expected \
                                            string.");
                        return DummyResult::any(span);
                    },
                };
            }
            ("extensions", tts) => {
                if extensions.is_some() {
                    let span = tts.head().map_or(span, |tt| tt.get_span());
                    ecx.span_err(span, "The list of extensions were already \
                                        specified.");
                    return DummyResult::any(span);
                }
                extensions = Some(match tts {
                    [&TtDelimited(span, ref delimited)]
                    if delimited.delim == token::Bracket => {
                        // Drop the trailing comma if it exists
                        let tts = drop_trailing_comma(delimited.tts.as_slice());

                        // Collect the extensions, breaking early if a parse
                        // error occurs.
                        let mut failed = false;
                        let exts = tts.split(is_comma).scan((), |_, tts| {
                            match tts {
                                [TtToken(_, token::Literal(token::Str_(ext), None))] => {
                                    Some(ext.as_str().to_string())
                                },
                                _ => {
                                    failed = true;
                                    None
                                },
                            }
                        }).collect();

                        // Cause an error if there is still some leftover
                        // tokens.
                        if failed {
                            ecx.span_err(span, "Invalid extension format, \
                                                expected string.");
                            return DummyResult::any(span);
                        } else {
                            exts
                        }
                    },
                    _ => {
                        ecx.span_err(span, "Expected a list of extension strings.");
                        return DummyResult::any(span);
                    }
                });
            }
            (field, _) => {
                ecx.span_err(span, format!("Unknown field `{}`", field).as_slice());
                return DummyResult::any(span);
            }
        }
    }

    // Use default values if the parameters have not been set
    let (ns, source) = api.unwrap_or((registry::Ns::Gl, khronos_api::GL_XML));
    let extensions = extensions.unwrap_or(vec![]);
    let version = version.unwrap_or("1.0".to_string());
    let generator = generator.unwrap_or(box generators::static_gen::StaticGenerator);
    let profile = profile.unwrap_or("core".to_string());

    // Get generator field values, using default values if they have not been
    // specified
    let filter = Some(Filter {
        api: ns.to_string(),
        extensions: extensions,
        version: version,
        profile: profile,
    });

    // Generate the registry of all bindings
    let registry = {
        use std::io::BufReader;
        use std::task;

        let result = task::try(move || {
            let reader = BufReader::new(source);
            Registry::from_xml(reader, ns, filter)
        });

        match result {
            Ok(reg) => reg,
            Err(err) => {
                use std::any::{Any, AnyRefExt};
                let err: &Any = &*err;

                match err {
                    err if err.is::<String>() => {
                        ecx.span_err(span, "error while parsing the registry");
                        ecx.span_err(span, err.downcast_ref::<String>().unwrap().as_slice());
                    },
                    err if err.is::<&'static str>() => {
                        ecx.span_err(span, "error while parsing the registry");
                        ecx.span_err(span, err.downcast_ref::<&'static str>().unwrap().as_slice());
                    },
                    _ => {
                        ecx.span_err(span, "unknown error while parsing the registry");
                    }
                }

                return DummyResult::any(span);
            }
        }
    };

    // generating the Rust bindings as a source code into "buffer"
    let items = generator.write(ecx, &registry, ns);

    MacItems::new(items.into_iter())
}
<|endoftext|>


<commit_before>/**
 * Angle and Trigonometry Functions
 *
 * This module corresponds to Section 8.1 of the [GLSL 4.30.6 specification]
 * (http://www.opengl.org/registry/doc/GLSLangSpec.4.30.6.pdf).
 */
use num::cast::{NumCast, cast};
use angle::Radians;
use vec::{Vec3, Vec2, Vec4};

///
/// Triganomic functions
///
/// http://en.wikipedia.org/wiki/Trigonometric_functions
///
priv trait Trig<T> {
    pure fn sin() -> T;
    pure fn cos() -> T;
    pure fn tan() -> T;
}

#[inline(always)] pub pure fn sin<T:Trig<R>, R>(theta: &T) -> R { theta.sin() }
#[inline(always)] pub pure fn cos<T:Trig<R>, R>(theta: &T) -> R { theta.cos() }
#[inline(always)] pub pure fn tan<T:Trig<R>, R>(theta: &T) -> R { theta.tan() }

priv impl<T:Copy Num NumCast> Radians<T>: Trig<T> {
    #[inline(always)] pure fn sin() -> T { cast(f64::sin(cast(*self))) }
    #[inline(always)] pure fn cos() -> T { cast(f64::cos(cast(*self))) }
    #[inline(always)] pure fn tan() -> T { cast(f64::tan(cast(*self))) }
}

pub impl<T:Copy Num NumCast> Vec2<Radians<T>>: Trig<Vec2<T>>  {
    #[inline(always)]
    pure fn sin() -> Vec2<T> {
        Vec2::new(sin(&self[0]),
                  sin(&self[1]))
    }

    #[inline(always)]
    pure fn cos() -> Vec2<T> {
        Vec2::new(cos(&self[0]),
                  cos(&self[1]))
    }

    #[inline(always)]
    pure fn tan() -> Vec2<T> {
        Vec2::new(tan(&self[0]),
                  tan(&self[1]))
    }
}

pub impl<T:Copy Num NumCast> Vec3<Radians<T>>: Trig<Vec3<T>>  {
    #[inline(always)]
    pure fn sin() -> Vec3<T> {
        Vec3::new(sin(&self[0]),
                  sin(&self[1]),
                  sin(&self[2]))
    }

    #[inline(always)]
    pure fn cos() -> Vec3<T> {
        Vec3::new(cos(&self[0]),
                  cos(&self[1]),
                  cos(&self[2]))
    }

    #[inline(always)]
    pure fn tan() -> Vec3<T> {
        Vec3::new(tan(&self[0]),
                  tan(&self[1]),
                  tan(&self[2]))
    }
}

pub impl<T:Copy Num NumCast> Vec4<Radians<T>>: Trig<Vec4<T>>  {
    #[inline(always)]
    pure fn sin() -> Vec4<T> {
        Vec4::new(sin(&self[0]),
                  sin(&self[1]),
                  sin(&self[2]),
                  sin(&self[3]))
    }

    #[inline(always)]
    pure fn cos() -> Vec4<T> {
        Vec4::new(cos(&self[0]),
                  cos(&self[1]),
                  cos(&self[2]),
                  cos(&self[3]))
    }

    #[inline(always)]
    pure fn tan() -> Vec4<T> {
        Vec4::new(tan(&self[0]),
                  tan(&self[1]),
                  tan(&self[2]),
                  tan(&self[3]))
    }
}

///
/// Inverse triganomic functions
///
/// http://en.wikipedia.org/wiki/Inverse_trigonometric_functions
///
pub trait InvTrig {
    pure fn asin() -> Radians<self>;
    pure fn acos() -> Radians<self>;
    pure fn atan() -> Radians<self>;
}

#[inline(always)] pub pure fn asin<T:InvTrig>(x: &T) -> Radians<T> { x.asin() }
#[inline(always)] pub pure fn acos<T:InvTrig>(x: &T) -> Radians<T> { x.acos() }
#[inline(always)] pub pure fn atan<T:InvTrig>(x: &T) -> Radians<T> { x.atan() }

pub impl f32: InvTrig {
    #[inline(always)] pure fn asin() -> Radians<f32> { Radians(f32::asin(self)) }
    #[inline(always)] pure fn acos() -> Radians<f32> { Radians(f32::acos(self)) }
    #[inline(always)] pure fn atan() -> Radians<f32> { Radians(f32::atan(self)) }
}

pub impl f64: InvTrig {
    #[inline(always)] pure fn asin() -> Radians<f64> { Radians(f64::asin(self)) }
    #[inline(always)] pure fn acos() -> Radians<f64> { Radians(f64::acos(self)) }
    #[inline(always)] pure fn atan() -> Radians<f64> { Radians(f64::atan(self)) }
}

pub impl float: InvTrig {
    #[inline(always)] pure fn asin() -> Radians<float> { Radians(f64::asin(cast(self)).to_float()) }
    #[inline(always)] pure fn acos() -> Radians<float> { Radians(f64::acos(cast(self)).to_float()) }
    #[inline(always)] pure fn atan() -> Radians<float> { Radians(f64::atan(cast(self)).to_float()) }
}

///
/// Hyperbolic functions
///
/// http://en.wikipedia.org/wiki/Hyperbolic_function
///
pub trait Hyp {
    pure fn sinh() -> self;
    pure fn cosh() -> self;
    pure fn tanh() -> self;
    // pure fn asinh() -> self;
    // pure fn acosh() -> self;
    // pure fn atanh() -> self;
}

#[inline(always)] pub pure fn sinh<T:Hyp>(x: &T) -> T { x.sinh() }
#[inline(always)] pub pure fn cosh<T:Hyp>(x: &T) -> T { x.cosh() }
#[inline(always)] pub pure fn tanh<T:Hyp>(x: &T) -> T { x.tanh() }

pub impl f32: Hyp {
    #[inline(always)] pure fn sinh() -> f32 { f32::sinh(self) }
    #[inline(always)] pure fn cosh() -> f32 { f32::cosh(self) }
    #[inline(always)] pure fn tanh() -> f32 { f32::tanh(self) }
}

pub impl f64: Hyp {
    #[inline(always)] pure fn sinh() -> f64 { f64::sinh(self) }
    #[inline(always)] pure fn cosh() -> f64 { f64::cosh(self) }
    #[inline(always)] pure fn tanh() -> f64 { f64::tanh(self) }
}

pub impl float: Hyp {
    #[inline(always)] pure fn sinh() -> float { cast(f64::sinh(cast(self))) }
    #[inline(always)] pure fn cosh() -> float { cast(f64::cosh(cast(self))) }
    #[inline(always)] pure fn tanh() -> float { cast(f64::tanh(cast(self))) }
}

pub impl <T:Copy Hyp> Vec2<T>: Hyp {
    #[inline(always)]
    pure fn sinh() -> Vec2<T> {
        Vec2::new(sinh(&self[0]),
                  sinh(&self[1]))
    }

    #[inline(always)]
    pure fn cosh() -> Vec2<T> {
        Vec2::new(cosh(&self[0]),
                  cosh(&self[1]))
    }

    #[inline(always)]
    pure fn tanh() -> Vec2<T> {
        Vec2::new(tanh(&self[0]),
                  tanh(&self[1]))
    }
}

pub impl <T:Copy Hyp> Vec3<T>: Hyp {
    #[inline(always)]
    pure fn sinh() -> Vec3<T> {
        Vec3::new(sinh(&self[0]),
                  sinh(&self[1]),
                  sinh(&self[2]))
    }

    #[inline(always)]
    pure fn cosh() -> Vec3<T> {
        Vec3::new(cosh(&self[0]),
                  cosh(&self[1]),
                  cosh(&self[2]))
    }

    #[inline(always)]
    pure fn tanh() -> Vec3<T> {
        Vec3::new(tanh(&self[0]),
                  tanh(&self[1]),
                  tanh(&self[2]))
    }
}

pub impl <T:Copy Hyp> Vec4<T>: Hyp  {
    #[inline(always)]
    pure fn sinh() -> Vec4<T> {
        Vec4::new(sinh(&self[0]),
                  sinh(&self[1]),
                  sinh(&self[2]),
                  sinh(&self[3]))
    }

    #[inline(always)]
    pure fn cosh() -> Vec4<T> {
        Vec4::new(cosh(&self[0]),
                  cosh(&self[1]),
                  cosh(&self[2]),
                  cosh(&self[3]))
    }

    #[inline(always)]
    pure fn tanh() -> Vec4<T> {
        Vec4::new(tanh(&self[0]),
                  tanh(&self[1]),
                  tanh(&self[2]),
                  tanh(&self[3]))
    }
}<commit_msg>Implement inverse trigonometry functions for vector types<commit_after>/**
 * Angle and Trigonometry Functions
 *
 * This module corresponds to Section 8.1 of the [GLSL 4.30.6 specification]
 * (http://www.opengl.org/registry/doc/GLSLangSpec.4.30.6.pdf).
 */
use num::cast::{NumCast, cast};
use angle::Radians;
use vec::{Vec3, Vec2, Vec4};

///
/// Triganomic functions
///
/// http://en.wikipedia.org/wiki/Trigonometric_functions
///
priv trait Trig<T> {
    pure fn sin() -> T;
    pure fn cos() -> T;
    pure fn tan() -> T;
}

#[inline(always)] pub pure fn sin<T:Trig<R>, R>(theta: &T) -> R { theta.sin() }
#[inline(always)] pub pure fn cos<T:Trig<R>, R>(theta: &T) -> R { theta.cos() }
#[inline(always)] pub pure fn tan<T:Trig<R>, R>(theta: &T) -> R { theta.tan() }

priv impl<T:Copy Num NumCast> Radians<T>: Trig<T> {
    #[inline(always)] pure fn sin() -> T { cast(f64::sin(cast(*self))) }
    #[inline(always)] pure fn cos() -> T { cast(f64::cos(cast(*self))) }
    #[inline(always)] pure fn tan() -> T { cast(f64::tan(cast(*self))) }
}

pub impl<T:Copy Num NumCast> Vec2<Radians<T>>: Trig<Vec2<T>>  {
    #[inline(always)]
    pure fn sin() -> Vec2<T> {
        Vec2::new(sin(&self[0]),
                  sin(&self[1]))
    }

    #[inline(always)]
    pure fn cos() -> Vec2<T> {
        Vec2::new(cos(&self[0]),
                  cos(&self[1]))
    }

    #[inline(always)]
    pure fn tan() -> Vec2<T> {
        Vec2::new(tan(&self[0]),
                  tan(&self[1]))
    }
}

pub impl<T:Copy Num NumCast> Vec3<Radians<T>>: Trig<Vec3<T>>  {
    #[inline(always)]
    pure fn sin() -> Vec3<T> {
        Vec3::new(sin(&self[0]),
                  sin(&self[1]),
                  sin(&self[2]))
    }

    #[inline(always)]
    pure fn cos() -> Vec3<T> {
        Vec3::new(cos(&self[0]),
                  cos(&self[1]),
                  cos(&self[2]))
    }

    #[inline(always)]
    pure fn tan() -> Vec3<T> {
        Vec3::new(tan(&self[0]),
                  tan(&self[1]),
                  tan(&self[2]))
    }
}

pub impl<T:Copy Num NumCast> Vec4<Radians<T>>: Trig<Vec4<T>>  {
    #[inline(always)]
    pure fn sin() -> Vec4<T> {
        Vec4::new(sin(&self[0]),
                  sin(&self[1]),
                  sin(&self[2]),
                  sin(&self[3]))
    }

    #[inline(always)]
    pure fn cos() -> Vec4<T> {
        Vec4::new(cos(&self[0]),
                  cos(&self[1]),
                  cos(&self[2]),
                  cos(&self[3]))
    }

    #[inline(always)]
    pure fn tan() -> Vec4<T> {
        Vec4::new(tan(&self[0]),
                  tan(&self[1]),
                  tan(&self[2]),
                  tan(&self[3]))
    }
}

///
/// Inverse triganomic functions
///
/// http://en.wikipedia.org/wiki/Inverse_trigonometric_functions
///
pub trait InvTrig {
    pure fn asin() -> Radians<self>;
    pure fn acos() -> Radians<self>;
    pure fn atan() -> Radians<self>;
}

#[inline(always)] pub pure fn asin<T:InvTrig>(x: &T) -> Radians<T> { x.asin() }
#[inline(always)] pub pure fn acos<T:InvTrig>(x: &T) -> Radians<T> { x.acos() }
#[inline(always)] pub pure fn atan<T:InvTrig>(x: &T) -> Radians<T> { x.atan() }

pub impl f32: InvTrig {
    #[inline(always)] pure fn asin() -> Radians<f32> { Radians(f32::asin(self)) }
    #[inline(always)] pure fn acos() -> Radians<f32> { Radians(f32::acos(self)) }
    #[inline(always)] pure fn atan() -> Radians<f32> { Radians(f32::atan(self)) }
}

pub impl f64: InvTrig {
    #[inline(always)] pure fn asin() -> Radians<f64> { Radians(f64::asin(self)) }
    #[inline(always)] pure fn acos() -> Radians<f64> { Radians(f64::acos(self)) }
    #[inline(always)] pure fn atan() -> Radians<f64> { Radians(f64::atan(self)) }
}

pub impl float: InvTrig {
    #[inline(always)] pure fn asin() -> Radians<float> { Radians(f64::asin(cast(self)).to_float()) }
    #[inline(always)] pure fn acos() -> Radians<float> { Radians(f64::acos(cast(self)).to_float()) }
    #[inline(always)] pure fn atan() -> Radians<float> { Radians(f64::atan(cast(self)).to_float()) }
}

// TODO: figure out how to merge with InvTrig
pub trait InvTrigV<T> {
    pure fn asin() -> T;
    pure fn acos() -> T;
    pure fn atan() -> T;
}

pub impl<T:Copy Num NumCast InvTrig> Vec2<T>: InvTrigV<Vec2<Radians<T>>>  {
    #[inline(always)]
    pure fn asin() -> Vec2<Radians<T>> {
        Vec2::new(asin(&self[0]),
                  asin(&self[1]))
    }

    #[inline(always)]
    pure fn acos() -> Vec2<Radians<T>> {
        Vec2::new(acos(&self[0]),
                  acos(&self[1]))
    }

    #[inline(always)]
    pure fn atan() -> Vec2<Radians<T>> {
        Vec2::new(atan(&self[0]),
                  atan(&self[1]))
    }
}

pub impl<T:Copy Num NumCast InvTrig> Vec3<T>: InvTrigV<Vec3<Radians<T>>>  {
    #[inline(always)]
    pure fn asin() -> Vec3<Radians<T>> {
        Vec3::new(asin(&self[0]),
                  asin(&self[1]),
                  asin(&self[2]))
    }

    #[inline(always)]
    pure fn acos() -> Vec3<Radians<T>> {
        Vec3::new(acos(&self[0]),
                  acos(&self[1]),
                  acos(&self[2]))
    }

    #[inline(always)]
    pure fn atan() -> Vec3<Radians<T>> {
        Vec3::new(atan(&self[0]),
                  atan(&self[1]),
                  atan(&self[2]))
    }
}

pub impl<T:Copy Num NumCast InvTrig> Vec4<T>: InvTrigV<Vec4<Radians<T>>>  {
    #[inline(always)]
    pure fn asin() -> Vec4<Radians<T>> {
        Vec4::new(asin(&self[0]),
                  asin(&self[1]),
                  asin(&self[2]),
                  asin(&self[3]))
    }

    #[inline(always)]
    pure fn acos() -> Vec4<Radians<T>> {
        Vec4::new(acos(&self[0]),
                  acos(&self[1]),
                  acos(&self[2]),
                  acos(&self[3]))
    }

    #[inline(always)]
    pure fn atan() -> Vec4<Radians<T>> {
        Vec4::new(atan(&self[0]),
                  atan(&self[1]),
                  atan(&self[2]),
                  atan(&self[3]))
    }
}

///
/// Hyperbolic functions
///
/// http://en.wikipedia.org/wiki/Hyperbolic_function
///
pub trait Hyp {
    pure fn sinh() -> self;
    pure fn cosh() -> self;
    pure fn tanh() -> self;
    // pure fn asinh() -> self;
    // pure fn acosh() -> self;
    // pure fn atanh() -> self;
}

#[inline(always)] pub pure fn sinh<T:Hyp>(x: &T) -> T { x.sinh() }
#[inline(always)] pub pure fn cosh<T:Hyp>(x: &T) -> T { x.cosh() }
#[inline(always)] pub pure fn tanh<T:Hyp>(x: &T) -> T { x.tanh() }

pub impl f32: Hyp {
    #[inline(always)] pure fn sinh() -> f32 { f32::sinh(self) }
    #[inline(always)] pure fn cosh() -> f32 { f32::cosh(self) }
    #[inline(always)] pure fn tanh() -> f32 { f32::tanh(self) }
}

pub impl f64: Hyp {
    #[inline(always)] pure fn sinh() -> f64 { f64::sinh(self) }
    #[inline(always)] pure fn cosh() -> f64 { f64::cosh(self) }
    #[inline(always)] pure fn tanh() -> f64 { f64::tanh(self) }
}

pub impl float: Hyp {
    #[inline(always)] pure fn sinh() -> float { cast(f64::sinh(cast(self))) }
    #[inline(always)] pure fn cosh() -> float { cast(f64::cosh(cast(self))) }
    #[inline(always)] pure fn tanh() -> float { cast(f64::tanh(cast(self))) }
}

pub impl <T:Copy Hyp> Vec2<T>: Hyp {
    #[inline(always)]
    pure fn sinh() -> Vec2<T> {
        Vec2::new(sinh(&self[0]),
                  sinh(&self[1]))
    }

    #[inline(always)]
    pure fn cosh() -> Vec2<T> {
        Vec2::new(cosh(&self[0]),
                  cosh(&self[1]))
    }

    #[inline(always)]
    pure fn tanh() -> Vec2<T> {
        Vec2::new(tanh(&self[0]),
                  tanh(&self[1]))
    }
}

pub impl <T:Copy Hyp> Vec3<T>: Hyp {
    #[inline(always)]
    pure fn sinh() -> Vec3<T> {
        Vec3::new(sinh(&self[0]),
                  sinh(&self[1]),
                  sinh(&self[2]))
    }

    #[inline(always)]
    pure fn cosh() -> Vec3<T> {
        Vec3::new(cosh(&self[0]),
                  cosh(&self[1]),
                  cosh(&self[2]))
    }

    #[inline(always)]
    pure fn tanh() -> Vec3<T> {
        Vec3::new(tanh(&self[0]),
                  tanh(&self[1]),
                  tanh(&self[2]))
    }
}

pub impl <T:Copy Hyp> Vec4<T>: Hyp  {
    #[inline(always)]
    pure fn sinh() -> Vec4<T> {
        Vec4::new(sinh(&self[0]),
                  sinh(&self[1]),
                  sinh(&self[2]),
                  sinh(&self[3]))
    }

    #[inline(always)]
    pure fn cosh() -> Vec4<T> {
        Vec4::new(cosh(&self[0]),
                  cosh(&self[1]),
                  cosh(&self[2]),
                  cosh(&self[3]))
    }

    #[inline(always)]
    pure fn tanh() -> Vec4<T> {
        Vec4::new(tanh(&self[0]),
                  tanh(&self[1]),
                  tanh(&self[2]),
                  tanh(&self[3]))
    }
}<|endoftext|>


<commit_before>// Copyright 2018 Developers of the Rand project.
// Copyright 2016-2017 The Rust Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The binomial distribution.

use Rng;
use distributions::{Distribution, Cauchy};
use distributions::utils::log_gamma;

/// The binomial distribution `Binomial(n, p)`.
///
/// This distribution has density function:
/// `f(k) = n!/(k! (n-k)!) p^k (1-p)^(n-k)` for `k >= 0`.
///
/// # Example
///
/// ```
/// use rand::distributions::{Binomial, Distribution};
///
/// let bin = Binomial::new(20, 0.3);
/// let v = bin.sample(&mut rand::thread_rng());
/// println!("{} is from a binomial distribution", v);
/// ```
#[derive(Clone, Copy, Debug)]
pub struct Binomial {
    /// Number of trials.
    n: u64,
    /// Probability of success.
    p: f64,
}

impl Binomial {
    /// Construct a new `Binomial` with the given shape parameters `n` (number
    /// of trials) and `p` (probability of success).
    ///
    /// Panics if `p < 0` or `p > 1`.
    pub fn new(n: u64, p: f64) -> Binomial {
        assert!(p >= 0.0, "Binomial::new called with p < 0");
        assert!(p <= 1.0, "Binomial::new called with p > 1");
        Binomial { n, p }
    }
}

impl Distribution<u64> for Binomial {
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u64 {
        // Handle these values directly.
        if self.p == 0.0 {
            return 0;
        } else if self.p == 1.0 {
            return self.n;
        }

        // binomial distribution is symmetrical with respect to p -> 1-p, k -> n-k
        // switch p so that it is less than 0.5 - this allows for lower expected values
        // we will just invert the result at the end
        let p = if self.p <= 0.5 {
            self.p
        } else {
            1.0 - self.p
        };

        let result;

        // For small n * min(p, 1 - p), the BINV algorithm based on the inverse
        // transformation of the binomial distribution is more efficient:
        //
        // Voratas Kachitvichyanukul and Bruce W. Schmeiser. 1988. Binomial
        // random variate generation. Commun. ACM 31, 2 (February 1988),
        // 216-222. http://dx.doi.org/10.1145/42372.42381
        if (self.n as f64) * p < 10. && self.n <= (::std::i32::MAX as u64) {
            let q = 1. - p;
            let s = p / q;
            let a = ((self.n + 1) as f64) * s;
            let mut r = q.powi(self.n as i32);
            let mut u: f64 = rng.gen();
            let mut x = 0;
            while u > r as f64 {
                u -= r;
                x += 1;
                r *= a / (x as f64) - s;
            }
            result = x;
        } else {
            // FIXME: Using the BTPE algorithm is probably faster.

            // prepare some cached values
            let float_n = self.n as f64;
            let ln_fact_n = log_gamma(float_n + 1.0);
            let pc = 1.0 - p;
            let log_p = p.ln();
            let log_pc = pc.ln();
            let expected = self.n as f64 * p;
            let sq = (expected * (2.0 * pc)).sqrt();
            let mut lresult;

            // we use the Cauchy distribution as the comparison distribution
            // f(x) ~ 1/(1+x^2)
            let cauchy = Cauchy::new(0.0, 1.0);
            loop {
                let mut comp_dev: f64;
                loop {
                    // draw from the Cauchy distribution
                    comp_dev = rng.sample(cauchy);
                    // shift the peak of the comparison ditribution
                    lresult = expected + sq * comp_dev;
                    // repeat the drawing until we are in the range of possible values
                    if lresult >= 0.0 && lresult < float_n + 1.0 {
                        break;
                    }
                }

                // the result should be discrete
                lresult = lresult.floor();

                let log_binomial_dist = ln_fact_n - log_gamma(lresult+1.0) -
                    log_gamma(float_n - lresult + 1.0) + lresult*log_p + (float_n - lresult)*log_pc;
                // this is the binomial probability divided by the comparison probability
                // we will generate a uniform random value and if it is larger than this,
                // we interpret it as a value falling out of the distribution and repeat
                let comparison_coeff = (log_binomial_dist.exp() * sq) * (1.2 * (1.0 + comp_dev*comp_dev));

                if comparison_coeff >= rng.gen() {
                    break;
                }
            }
            result = lresult as u64;
        }

        // invert the result for p < 0.5
        if p != self.p {
            self.n - result
        } else {
            result
        }
    }
}

#[cfg(test)]
mod test {
    use Rng;
    use distributions::Distribution;
    use super::Binomial;

    fn test_binomial_mean_and_variance<R: Rng>(n: u64, p: f64, rng: &mut R) {
        let binomial = Binomial::new(n, p);

        let expected_mean = n as f64 * p;
        let expected_variance = n as f64 * p * (1.0 - p);

        let mut results = [0.0; 1000];
        for i in results.iter_mut() { *i = binomial.sample(rng) as f64; }

        let mean = results.iter().sum::<f64>() / results.len() as f64;
        assert!((mean as f64 - expected_mean).abs() < expected_mean / 50.0);

        let variance =
            results.iter().map(|x| (x - mean) * (x - mean)).sum::<f64>()
            / results.len() as f64;
        assert!((variance - expected_variance).abs() < expected_variance / 10.0);
    }

    #[test]
    fn test_binomial() {
        let mut rng = ::test::rng(351);
        test_binomial_mean_and_variance(150, 0.1, &mut rng);
        test_binomial_mean_and_variance(70, 0.6, &mut rng);
        test_binomial_mean_and_variance(40, 0.5, &mut rng);
        test_binomial_mean_and_variance(20, 0.7, &mut rng);
        test_binomial_mean_and_variance(20, 0.5, &mut rng);
    }

    #[test]
    fn test_binomial_end_points() {
        let mut rng = ::test::rng(352);
        assert_eq!(rng.sample(Binomial::new(20, 0.0)), 0);
        assert_eq!(rng.sample(Binomial::new(20, 1.0)), 20);
    }

    #[test]
    #[should_panic]
    fn test_binomial_invalid_lambda_neg() {
        Binomial::new(20, -10.0);
    }
}
<commit_msg>Implement the BTPE for binomial sampling<commit_after>// Copyright 2018 Developers of the Rand project.
// Copyright 2016-2017 The Rust Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The binomial distribution.

use Rng;
use distributions::Distribution;

/// The binomial distribution `Binomial(n, p)`.
///
/// This distribution has density function:
/// `f(k) = n!/(k! (n-k)!) p^k (1-p)^(n-k)` for `k >= 0`.
///
/// # Example
///
/// ```
/// use rand::distributions::{Binomial, Distribution};
///
/// let bin = Binomial::new(20, 0.3);
/// let v = bin.sample(&mut rand::thread_rng());
/// println!("{} is from a binomial distribution", v);
/// ```
#[derive(Clone, Copy, Debug)]
pub struct Binomial {
    /// Number of trials.
    n: u64,
    /// Probability of success.
    p: f64,
}

impl Binomial {
    /// Construct a new `Binomial` with the given shape parameters `n` (number
    /// of trials) and `p` (probability of success).
    ///
    /// Panics if `p < 0` or `p > 1`.
    pub fn new(n: u64, p: f64) -> Binomial {
        assert!(p >= 0.0, "Binomial::new called with p < 0");
        assert!(p <= 1.0, "Binomial::new called with p > 1");
        Binomial { n, p }
    }
}

impl Distribution<u64> for Binomial {
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u64 {
        // Handle these values directly.
        if self.p == 0.0 {
            return 0;
        } else if self.p == 1.0 {
            return self.n;
        }

        // The binomial distribution is symmetrical with respect to p -> 1-p,
        // k -> n-k switch p so that it is less than 0.5 - this allows for lower
        // expected values we will just invert the result at the end
        let p = if self.p <= 0.5 {
            self.p
        } else {
            1.0 - self.p
        };

        let result;

        // For small n * min(p, 1 - p), the BINV algorithm based on the inverse
        // transformation of the binomial distribution is efficient. Otherwise,
        // the BTPE algorithm is used.
        //
        // Voratas Kachitvichyanukul and Bruce W. Schmeiser. 1988. Binomial
        // random variate generation. Commun. ACM 31, 2 (February 1988),
        // 216-222. http://dx.doi.org/10.1145/42372.42381

        // Threshold for prefering the BINV algorithm. The paper suggests 10,
        // Ranlib uses 30, and GSL uses 14.
        const BINV_THRESHOLD: f64 = 10.;

        if (self.n as f64) * p < BINV_THRESHOLD &&
           self.n <= (::std::i32::MAX as u64) {
            // Use the BINV algorithm.
            let q = 1. - p;
            let s = p / q;
            let a = ((self.n + 1) as f64) * s;
            let mut r = q.powi(self.n as i32);
            let mut u: f64 = rng.gen();
            let mut x = 0;
            while u > r as f64 {
                u -= r;
                x += 1;
                r *= a / (x as f64) - s;
            }
            result = x;
        } else {
            // Use the BTPE algorithm.

            // Threshold for using the squeeze algorithm. This can be freely
            // chosen based on performance. Ranlib and GSL use 20.
            const SQUEEZE_THRESHOLD: i64 = 20;

            // Step 0: Calculate constants as functions of `n` and `p`.
            let n = self.n as f64;
            let r = p;
            let q = 1. - r;
            let f_m = n*r + r;
            let m = f_m as i64;
            // radius of triangle region, since height=1 also area of region
            let p1 = (2.195 * (n*r*q).sqrt() - 4.6 * q).floor() + 0.5;
            // tip of triangle
            let x_m = (m as f64) + 0.5;
            // left edge of triangle
            let x_l = x_m - p1;
            // right edge of triangle
            let x_r = x_m + p1;
            let c = 0.134 + 20.5 / (15.3 + (m as f64));
            // p1 + area of parallelogram region
            let p2 = p1 * (1. + 2. * c);

            fn lambda(a: f64) -> f64 {
                a * (1. + 0.5 * a)
            }

            let lambda_l = lambda((f_m - x_l) / (f_m - x_l * r));
            let lambda_r = lambda((x_r - f_m) / (x_r * q));
            // p1 + area of left tail
            let p3 = p2 + c / lambda_l;
            // p1 + area of right tail
            let p4 = p3 + c / lambda_r;

            // return value
            let mut y: i64;

            'outer: loop {
                // Step 1: Generate `u` for selecting the region. If region 1 is
                // selected, generate a triangularly distributed variate.
                let u = rng.gen_range(0., p4);
                let mut v = rng.gen_range(0., 1.);
                if !(u > p1) {
                    y = (x_m - p1 * v + u) as i64;
                    break;
                }

                loop {
                    // Step 2: Region 2, parallelograms. Check if region 2 is used. If
                    // so, generate `y`.
                    if !(u > p2) {
                        let x = x_l + (u - p1) / c;
                        v = v * c + 1.0 - (x - x_m).abs() / p1;
                        if v > 1. {
                            continue 'outer;
                        } else {
                            y = x as i64;
                            break;
                        }
                    }

                    // Step 3: Region 3, left exponential tail.
                    if !(u > p3) {
                        y = (x_l + v.ln() / lambda_l) as i64;
                        if y < 0 {
                            continue 'outer;
                        } else {
                            v *= (u - p2) * lambda_l;
                            break;
                        }
                    }

                    // Step 4: Region 4, right exponential tail.
                    y = (x_r - v.ln() / lambda_r) as i64;
                    if y > 0 && (y as u64) > self.n {
                        continue 'outer;
                    } else {
                        v *= (u - p3) * lambda_r;
                    }

                    break;
                }

                // Step 5: Acceptance/rejection comparison.

                // Step 5.0: Test for appropriate method of evaluating f(y).
                let k = (y - m).abs();
                if !(k > SQUEEZE_THRESHOLD && (k as f64) < 0.5 * n*r*q - 1.) {
                    // Step 5.1: Evaluate f(y) via the recursive relationship. Start the
                    // search from the mode.
                    let s = r / q;
                    let a = s * (n + 1.);
                    let mut f = 1.0;
                    if m < y {
                        let mut i = m;
                        loop {
                            i += 1;
                            f *= a / (i as f64) - s;
                            if i == y {
                                break;
                            }
                        }
                    } else if m > y {
                        let mut i = y;
                        loop {
                            i += 1;
                            f /= a / (i as f64) - s;
                            if i == m {
                                break;
                            }
                        }
                    }
                    if v > f {
                        continue;
                    } else {
                        break;
                    }
                }

                // Step 5.2: Squeezing. Check the value of ln(v) againts upper and
                // lower bound of ln(f(y)).
                let k = k as f64;
                let rho = (k / (n*r*q)) * ((k * (k / 3. + 0.625) + 1./6.) / (n*r*q) + 0.5);
                let t = -0.5 * k*k / (n*r*q);
                let alpha = v.ln();
                if alpha < t - rho {
                    break;
                }
                if alpha > t + rho {
                    continue;
                }

                // Step 5.3: Final acceptance/rejection test.
                let x1 = (y + 1) as f64;
                let f1 = (m + 1) as f64;
                let z = ((n as i64) + 1 - m) as f64;
                let w = ((n as i64) - y + 1) as f64;

                fn stirling(a: f64) -> f64 {
                    let a2 = a * a;
                    (13860. - (462. - (132. - (99. - 140. / a2) / a2) / a2) / a2) / a / 166320.
                }

                if alpha > x_m * (f1 / x1).ln()
                    + (n - (m as f64) + 0.5) * (z / w).ln()
                    + ((y - m) as f64) * (w * r / (x1 * q)).ln()
                    + stirling(f1) + stirling(z) + stirling(x1) + stirling(w)
                {
                    continue;
                }

                break;
            }
            assert!(y >= 0);
            result = y as u64;
        }

        // Invert the result for p < 0.5.
        if p != self.p {
            self.n - result
        } else {
            result
        }
    }
}

#[cfg(test)]
mod test {
    use Rng;
    use distributions::Distribution;
    use super::Binomial;

    fn test_binomial_mean_and_variance<R: Rng>(n: u64, p: f64, rng: &mut R) {
        let binomial = Binomial::new(n, p);

        let expected_mean = n as f64 * p;
        let expected_variance = n as f64 * p * (1.0 - p);

        let mut results = [0.0; 1000];
        for i in results.iter_mut() { *i = binomial.sample(rng) as f64; }

        let mean = results.iter().sum::<f64>() / results.len() as f64;
        assert!((mean as f64 - expected_mean).abs() < expected_mean / 50.0);

        let variance =
            results.iter().map(|x| (x - mean) * (x - mean)).sum::<f64>()
            / results.len() as f64;
        assert!((variance - expected_variance).abs() < expected_variance / 10.0);
    }

    #[test]
    fn test_binomial() {
        let mut rng = ::test::rng(351);
        test_binomial_mean_and_variance(150, 0.1, &mut rng);
        test_binomial_mean_and_variance(70, 0.6, &mut rng);
        test_binomial_mean_and_variance(40, 0.5, &mut rng);
        test_binomial_mean_and_variance(20, 0.7, &mut rng);
        test_binomial_mean_and_variance(20, 0.5, &mut rng);
    }

    #[test]
    fn test_binomial_end_points() {
        let mut rng = ::test::rng(352);
        assert_eq!(rng.sample(Binomial::new(20, 0.0)), 0);
        assert_eq!(rng.sample(Binomial::new(20, 1.0)), 20);
    }

    #[test]
    #[should_panic]
    fn test_binomial_invalid_lambda_neg() {
        Binomial::new(20, -10.0);
    }
}
<|endoftext|>