<commit_before>//! `Creep` data description.
use super::super::resources::ResourceType;
use super::super::resources::Store;
use super::ActionLogTarget;
use crate::data::RoomName;

with_update_struct! {
    /// A struct describing a creep part.
    ///
    /// TODO: parse creep part boosts.
    #[derive(serde_derive::Deserialize, Clone, Debug, PartialEq)]
    #[serde(rename_all = "camelCase")]
    pub struct CreepPart {
        /// Part health, out of 100.
        pub hits: i32,
        /// Part type.
        #[serde(rename = "type")]
        pub part_type: CreepPartType,
        /// Part boost, if any.
        pub boost: Option<ResourceType>,
    }

    /// The update structure for a `CreepPart`.
    #[derive(serde_derive::Deserialize, Clone, Debug)]
    #[serde(rename_all = "camelCase")]
    pub struct CreepPartUpdate { ... }
}

#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[serde(rename_all = "snake_case")]
/// A type of creep part.
pub enum CreepPartType {
    /// A move part - allows creeps to move, or move faster (max speed at 1 move part per other part).
    Move,
    /// A work part - allows creeps to spend energy doing things, mine sources and minerals, and damage
    /// structures.
    Work,
    /// A carry part - allows creeps to carry energy and other resources.
    Carry,
    /// An attack part - allows creeps to damage both other creeps, and structures.
    Attack,
    /// A heal part - allows creeps to heal creeps (other and self).
    Heal,
    /// A ranged attack part - allows creeps to attack other creeps and structures from a small distance.
    RangedAttack,
    /// A tough part - a cheap part which has no additional functionality.
    Tough,
    /// A claim part - a part which allows a creep to reserve or claim a room controller.
    Claim,
}

basic_updatable!(CreepPartType);

with_update_struct! {
    /// A struct describing a creep's message conveyed with `say`.
    #[derive(serde_derive::Deserialize, Default, Clone, Debug, PartialEq)]
    #[serde(rename_all = "camelCase")]
    pub struct CreepMessage {
        /// If true, the message is visible to all players.
        pub is_public: bool,
        /// The message.
        pub message: String,
    }

    /// The update structure for a `CreepMessage`.
    #[derive(serde_derive::Deserialize, Clone, Debug)]
    #[serde(rename_all = "camelCase")]
    pub struct CreepMessageUpdate { ... }
}

with_update_struct! {
    /// A struct describing a creep's actions.
    #[derive(serde_derive::Deserialize, Default, Clone, Debug, PartialEq)]
    #[serde(rename_all = "camelCase")]
    pub struct CreepActions {
        /// The location this creep harvested last tick.
        pub harvest: Option<ActionLogTarget>,
        /// The location this creep built to last tick.
        pub build: Option<ActionLogTarget>,
        /// The location this creep repaired last tick.
        pub repair: Option<ActionLogTarget>,
        /// The location this creep attacked last tick.
        pub attack: Option<ActionLogTarget>,
        /// The location this creep healed last tick.
        pub heal: Option<ActionLogTarget>,
        /// The location this creep range-attacked last tick.
        pub ranged_attack: Option<ActionLogTarget>,
        /// The location this creep range-healed last tick.
        pub ranged_heal: Option<ActionLogTarget>,
        /// If present, this creep made a ranged mass attack last tick.
        pub ranged_mass_attack: Option<ActionLogTarget>,
        /// The location of the controller this creep reserved last tick.
        pub reserve_controller: Option<ActionLogTarget>,
        /// The location of the controller this creep upgraded last tick.
        pub upgrade_controller: Option<ActionLogTarget>,
        /// The location this creep was attacked from last tick.
        pub attacked: Option<ActionLogTarget>,
        /// The location this creep was healed from last tick.
        pub healed: Option<ActionLogTarget>,
        /// The message this creep said last tick. TODO: confirm this is correct.
        pub say: Option<CreepMessage>,
    }

    /// The update structure for a `CreepActions`.
    #[derive(serde_derive::Deserialize, Clone, Debug)]
    #[serde(rename_all = "camelCase")]
    pub struct CreepActionsUpdate { ... }
}

with_base_fields_and_update_struct! {
    /// A creep object.
    #[derive(Clone, Debug, PartialEq)]
    #[serde(rename_all = "camelCase")]
    pub struct Creep {
        /// The current number of hit-points this structure has.
        #[serde(default)]
        pub hits: i32,
        /// The maximum number of hit-points this structure has.
        #[serde(default)]
        pub hits_max: i32,
        /// The user ID of the owner of this creep.
        pub user: String,
        /// Whether or not this creep is currently being constructed 'inside' a spawner. If this is the case,
        /// it cannot perform any actions.
        #[serde(default)]
        pub spawning: bool,
        /// The total amount of resources this creep can carry.
        #[serde(rename = "storeCapacity")]
        pub capacity: i32,
        /// Whether or not an attack on this creep will send an email to the owner automatically..
        #[serde(default)]
        pub notify_when_attacked: bool,
        /// The name of this creep, unique per player.
        pub name: String,
        /// The current 'fatigue' of this creep. If higher than 0, this creep cannot execute a move action this tick.
        pub fatigue: i32,
        /// The game time at which this creep will die if not renewed further before then.
        ///
        /// None if the creep is still spawning.
        pub age_time: Option<u32>,
        /// A list of parts on this creep, and their current states.
        pub body: Vec<CreepPart>,
        /// A record of all actions this creep performed and some actions performed onto this creep last tick.
        #[serde(default)] // won't exist for spawning creeps, but we can just do this.
        pub action_log: CreepActions,
        /// The resources and amounts of each resource some game object holds.
        pub store: Store,
    }

    /// The update structure for a `Creep`.
    #[derive(Clone, Debug)]
    #[serde(rename_all = "camelCase")]
    pub struct CreepUpdate {
        - hits: i32,
        - hits_max: i32,
        - user: String,
        - spawning: bool,
        #[serde(rename = "energyCapacity")]
        - capacity: i32,
        - notify_when_attacked: bool,
        - name: String,
        - fatigue: i32,
        - age_time: Option<u32>,
        - body: Vec<CreepPart>,
        - action_log: CreepActions,
        - store: Store,
    }
}

impl Creep {
    /// Iterates over this creep's carried resources.
    pub fn carry_contents(&self) -> impl Iterator<Item = (ResourceType, i32)> + '_ {
        self.store.iter()
    }
}

#[cfg(test)]
mod test {
    use serde::Deserialize;

    use crate::data::RoomName;

    use super::{ActionLogTarget, Creep, CreepActions, CreepPartType};

    #[test]
    fn parse_creep() {
        let json = json!({
            "_id": "5e117142fadd09a383ffdc99",
            "actionLog": {
                "attack": null,
                "attacked": null,
                "build": null,
                "harvest": null,
                "heal": null,
                "healed": null,
                "rangedAttack": null,
                "rangedHeal": null,
                "rangedMassAttack": null,
                "repair": null,
                "reserveController": null,
                "say": null,
                "upgradeController": {
                    "x": 27,
                    "y": 8,
                }
            },
            "ageTime": 23469491,
            "body": [
                {
                    "hits": 100,
                    "type": "move"
                },
                {
                    "hits": 100,
                    "type": "move"
                },
                {
                    "hits": 100,
                    "type": "carry"
                },
                {
                    "hits": 100,
                    "type": "work"
                }
            ],
            "fatigue": 0,
            "hits": 400,
            "hitsMax": 400,
            "name": "w9g1gpnN",
            "notifyWhenAttacked": true,
            "room": "E44S19",
            "spawning": false,
            "store": {
                "energy": 13
            },
            "storeCapacity": 50,
            "type": "creep",
            "user": "57874d42d0ae911e3bd15bbc",
            "x": 26,
            "y": 7
        });

        let obj = Creep::deserialize(json).unwrap();

        match obj {
            Creep {
                ref id,
                ref room,
                x: 26,
                y: 7,
                capacity: 50,
                hits: 400,
                hits_max: 400,
                age_time: Some(23469491),
                ref name,
                notify_when_attacked: true,
                spawning: false,
                action_log:
                    CreepActions {
                        attack: None,
                        attacked: None,
                        build: None,
                        harvest: None,
                        heal: None,
                        healed: None,
                        ranged_attack: None,
                        ranged_heal: None,
                        ranged_mass_attack: None,
                        repair: None,
                        reserve_controller: None,
                        say: None,
                        upgrade_controller: Some(ActionLogTarget { x: 27, y: 8 }),
                    },
                ref body,
                ref user,
                ..
            } => {
                if user != "57874d42d0ae911e3bd15bbc"
                    || id != "5e117142fadd09a383ffdc99"
                    || *room != RoomName::new("E33S19").unwrap()
                    || name != "w9g1gpnN"
                    || body
                        .iter()
                        .map(|part| {
                            if part.part_type == CreepPartType::Carry {
                                1
                            } else {
                                0
                            }
                        })
                        .sum::<i32>()
                        != 1
                    || body
                        .iter()
                        .map(|part| {
                            if part.part_type == CreepPartType::Work {
                                1
                            } else {
                                0
                            }
                        })
                        .sum::<i32>()
                        != 1
                    || body
                        .iter()
                        .map(|part| {
                            if part.part_type == CreepPartType::Move {
                                1
                            } else {
                                0
                            }
                        })
                        .sum::<i32>()
                        != 2
                    || !body.iter().all(|part| {
                        part.part_type == CreepPartType::Move
                            || part.part_type == CreepPartType::Work
                            || part.part_type == CreepPartType::Carry
                    })
                {
                    panic!("some fields wrong from pre-set Creep: {:#?}", obj);
                }
            }
            other => panic!("expected pre-set Creep to match, found {:#?}", other),
        }

        assert_eq!(obj.carry_contents().collect::<Vec<_>>(), vec![]);
    }
}
<commit_msg>Fix Creep tests<commit_after>//! `Creep` data description.
use super::super::resources::ResourceType;
use super::super::resources::Store;
use super::ActionLogTarget;
use crate::data::RoomName;

with_update_struct! {
    /// A struct describing a creep part.
    ///
    /// TODO: parse creep part boosts.
    #[derive(serde_derive::Deserialize, Clone, Debug, PartialEq)]
    #[serde(rename_all = "camelCase")]
    pub struct CreepPart {
        /// Part health, out of 100.
        pub hits: i32,
        /// Part type.
        #[serde(rename = "type")]
        pub part_type: CreepPartType,
        /// Part boost, if any.
        pub boost: Option<ResourceType>,
    }

    /// The update structure for a `CreepPart`.
    #[derive(serde_derive::Deserialize, Clone, Debug)]
    #[serde(rename_all = "camelCase")]
    pub struct CreepPartUpdate { ... }
}

#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[serde(rename_all = "snake_case")]
/// A type of creep part.
pub enum CreepPartType {
    /// A move part - allows creeps to move, or move faster (max speed at 1 move part per other part).
    Move,
    /// A work part - allows creeps to spend energy doing things, mine sources and minerals, and damage
    /// structures.
    Work,
    /// A carry part - allows creeps to carry energy and other resources.
    Carry,
    /// An attack part - allows creeps to damage both other creeps, and structures.
    Attack,
    /// A heal part - allows creeps to heal creeps (other and self).
    Heal,
    /// A ranged attack part - allows creeps to attack other creeps and structures from a small distance.
    RangedAttack,
    /// A tough part - a cheap part which has no additional functionality.
    Tough,
    /// A claim part - a part which allows a creep to reserve or claim a room controller.
    Claim,
}

basic_updatable!(CreepPartType);

with_update_struct! {
    /// A struct describing a creep's message conveyed with `say`.
    #[derive(serde_derive::Deserialize, Default, Clone, Debug, PartialEq)]
    #[serde(rename_all = "camelCase")]
    pub struct CreepMessage {
        /// If true, the message is visible to all players.
        pub is_public: bool,
        /// The message.
        pub message: String,
    }

    /// The update structure for a `CreepMessage`.
    #[derive(serde_derive::Deserialize, Clone, Debug)]
    #[serde(rename_all = "camelCase")]
    pub struct CreepMessageUpdate { ... }
}

with_update_struct! {
    /// A struct describing a creep's actions.
    #[derive(serde_derive::Deserialize, Default, Clone, Debug, PartialEq)]
    #[serde(rename_all = "camelCase")]
    pub struct CreepActions {
        /// The location this creep harvested last tick.
        pub harvest: Option<ActionLogTarget>,
        /// The location this creep built to last tick.
        pub build: Option<ActionLogTarget>,
        /// The location this creep repaired last tick.
        pub repair: Option<ActionLogTarget>,
        /// The location this creep attacked last tick.
        pub attack: Option<ActionLogTarget>,
        /// The location this creep healed last tick.
        pub heal: Option<ActionLogTarget>,
        /// The location this creep range-attacked last tick.
        pub ranged_attack: Option<ActionLogTarget>,
        /// The location this creep range-healed last tick.
        pub ranged_heal: Option<ActionLogTarget>,
        /// If present, this creep made a ranged mass attack last tick.
        pub ranged_mass_attack: Option<ActionLogTarget>,
        /// The location of the controller this creep reserved last tick.
        pub reserve_controller: Option<ActionLogTarget>,
        /// The location of the controller this creep upgraded last tick.
        pub upgrade_controller: Option<ActionLogTarget>,
        /// The location this creep was attacked from last tick.
        pub attacked: Option<ActionLogTarget>,
        /// The location this creep was healed from last tick.
        pub healed: Option<ActionLogTarget>,
        /// The message this creep said last tick. TODO: confirm this is correct.
        pub say: Option<CreepMessage>,
    }

    /// The update structure for a `CreepActions`.
    #[derive(serde_derive::Deserialize, Clone, Debug)]
    #[serde(rename_all = "camelCase")]
    pub struct CreepActionsUpdate { ... }
}

with_base_fields_and_update_struct! {
    /// A creep object.
    #[derive(Clone, Debug, PartialEq)]
    #[serde(rename_all = "camelCase")]
    pub struct Creep {
        /// The current number of hit-points this structure has.
        #[serde(default)]
        pub hits: i32,
        /// The maximum number of hit-points this structure has.
        #[serde(default)]
        pub hits_max: i32,
        /// The user ID of the owner of this creep.
        pub user: String,
        /// Whether or not this creep is currently being constructed 'inside' a spawner. If this is the case,
        /// it cannot perform any actions.
        #[serde(default)]
        pub spawning: bool,
        /// The total amount of resources this creep can carry.
        #[serde(rename = "storeCapacity")]
        pub capacity: i32,
        /// Whether or not an attack on this creep will send an email to the owner automatically..
        #[serde(default)]
        pub notify_when_attacked: bool,
        /// The name of this creep, unique per player.
        pub name: String,
        /// The current 'fatigue' of this creep. If higher than 0, this creep cannot execute a move action this tick.
        pub fatigue: i32,
        /// The game time at which this creep will die if not renewed further before then.
        ///
        /// None if the creep is still spawning.
        pub age_time: Option<u32>,
        /// A list of parts on this creep, and their current states.
        pub body: Vec<CreepPart>,
        /// A record of all actions this creep performed and some actions performed onto this creep last tick.
        #[serde(default)] // won't exist for spawning creeps, but we can just do this.
        pub action_log: CreepActions,
        /// The resources and amounts of each resource some game object holds.
        pub store: Store,
    }

    /// The update structure for a `Creep`.
    #[derive(Clone, Debug)]
    #[serde(rename_all = "camelCase")]
    pub struct CreepUpdate {
        - hits: i32,
        - hits_max: i32,
        - user: String,
        - spawning: bool,
        #[serde(rename = "energyCapacity")]
        - capacity: i32,
        - notify_when_attacked: bool,
        - name: String,
        - fatigue: i32,
        - age_time: Option<u32>,
        - body: Vec<CreepPart>,
        - action_log: CreepActions,
        - store: Store,
    }
}

impl Creep {
    /// Iterates over this creep's carried resources.
    pub fn carry_contents(&self) -> impl Iterator<Item = (ResourceType, i32)> + '_ {
        self.store.iter()
    }
}

#[cfg(test)]
mod test {
    use serde::Deserialize;

    use crate::data::RoomName;

    use super::{ActionLogTarget, Creep, CreepActions, CreepPartType};

    #[test]
    fn parse_creep() {
        let json = json!({
            "_id": "5e117142fadd09a383ffdc99",
            "actionLog": {
                "attack": null,
                "attacked": null,
                "build": null,
                "harvest": null,
                "heal": null,
                "healed": null,
                "rangedAttack": null,
                "rangedHeal": null,
                "rangedMassAttack": null,
                "repair": null,
                "reserveController": null,
                "say": null,
                "upgradeController": {
                    "x": 27,
                    "y": 8,
                }
            },
            "ageTime": 23469491,
            "body": [
                {
                    "hits": 100,
                    "type": "move"
                },
                {
                    "hits": 100,
                    "type": "move"
                },
                {
                    "hits": 100,
                    "type": "carry"
                },
                {
                    "hits": 100,
                    "type": "work"
                }
            ],
            "fatigue": 0,
            "hits": 400,
            "hitsMax": 400,
            "name": "w9g1gpnN",
            "notifyWhenAttacked": true,
            "room": "E44S19",
            "spawning": false,
            "store": {
                "energy": 13
            },
            "storeCapacity": 50,
            "type": "creep",
            "user": "57874d42d0ae911e3bd15bbc",
            "x": 26,
            "y": 7
        });

        let obj = Creep::deserialize(json).unwrap();

        match obj {
            Creep {
                ref id,
                ref room,
                x: 26,
                y: 7,
                capacity: 50,
                hits: 400,
                hits_max: 400,
                age_time: Some(23469491),
                ref name,
                notify_when_attacked: true,
                spawning: false,
                action_log:
                    CreepActions {
                        attack: None,
                        attacked: None,
                        build: None,
                        harvest: None,
                        heal: None,
                        healed: None,
                        ranged_attack: None,
                        ranged_heal: None,
                        ranged_mass_attack: None,
                        repair: None,
                        reserve_controller: None,
                        say: None,
                        upgrade_controller: Some(ActionLogTarget { x: 27, y: 8 }),
                    },
                ref body,
                ref user,
                ..
            } => {
                if user != "57874d42d0ae911e3bd15bbc"
                    || id != "5e117142fadd09a383ffdc99"
                    || *room != RoomName::new("E44S19").unwrap()
                    || name != "w9g1gpnN"
                    || body
                        .iter()
                        .map(|part| {
                            if part.part_type == CreepPartType::Carry {
                                1
                            } else {
                                0
                            }
                        })
                        .sum::<i32>()
                        != 1
                    || body
                        .iter()
                        .map(|part| {
                            if part.part_type == CreepPartType::Work {
                                1
                            } else {
                                0
                            }
                        })
                        .sum::<i32>()
                        != 1
                    || body
                        .iter()
                        .map(|part| {
                            if part.part_type == CreepPartType::Move {
                                1
                            } else {
                                0
                            }
                        })
                        .sum::<i32>()
                        != 2
                    || !body.iter().all(|part| {
                        part.part_type == CreepPartType::Move
                            || part.part_type == CreepPartType::Work
                            || part.part_type == CreepPartType::Carry
                    })
                {
                    panic!("some fields wrong from pre-set Creep: {:#?}", obj);
                }
            }
            other => panic!("expected pre-set Creep to match, found {:#?}", other),
        }

        assert_eq!(obj.store, store! { Energy: 13 });
    }
}
<|endoftext|>


<commit_before>use url::Url;

use crate::http::client::Http;
use crate::internal::prelude::*;
use crate::model::prelude::*;

/// A builder for constructing an invite link with custom OAuth2 scopes.
#[derive(Debug, Clone, Default)]
pub struct CreateBotAuthParameters {
    client_id: UserId,
    scopes: Vec<OAuth2Scope>,
    permissions: Permissions,
    guild_id: GuildId,
    disable_guild_select: bool,
}

impl CreateBotAuthParameters {
    /// Builds the url with the provided data.
    pub fn build(self) -> String {
        let mut valid_data = vec![];
        let bits = self.permissions.bits();

        if self.client_id.0 != 0 {
            valid_data.push(("cliend_id", self.client_id.0.to_string()));
        }

        if !self.scopes.is_empty() {
            valid_data.push((
                "scope",
                self.scopes.iter().map(|i| i.to_string()).collect::<Vec<_>>().join(" "),
            ));
        }

        if bits != 0 {
            valid_data.push(("permissions", bits.to_string()));
        }

        if self.guild_id.0 != 0 {
            valid_data.push(("guild", self.guild_id.0.to_string()));
        }

        if self.disable_guild_select {
            valid_data.push(("disable_guild_select", self.disable_guild_select.to_string()));
        }

        let url = Url::parse_with_params("https://discord.com/api/oauth2/authorize", &valid_data)
            .expect("failed to construct URL");

        url.to_string()
    }

    /// Specify the client Id of your application.
    pub fn client_id<U: Into<UserId>>(&mut self, client_id: U) -> &mut Self {
        self.client_id = client_id.into();
        self
    }

    /// Automatically fetch and set the client Id of your application by inquiring Discord's API.
    ///
    /// # Errors
    ///
    /// Returns an
    /// [`HttpError::UnsuccessfulRequest(Unauthorized)`][`HttpError::UnsuccessfulRequest`]
    /// If the user is not authorized for this endpoint.
    ///
    /// [`HttpError::UnsuccessfulRequest`]: crate::http::HttpError::UnsuccessfulRequest
    pub async fn auto_client_id(&mut self, http: impl AsRef<Http>) -> Result<&mut Self> {
        self.client_id = http.as_ref().get_current_application_info().await.map(|v| v.id)?;
        Ok(self)
    }

    /// Specify the scopes for your application.
    ///
    /// **Note**: This needs to include the [`Bot`] scope.
    ///
    /// [`Bot`]: crate::model::oauth2::OAuth2Scope::Bot
    pub fn scopes(&mut self, scopes: &[OAuth2Scope]) -> &mut Self {
        self.scopes = scopes.to_vec();
        self
    }

    /// Specify the permissions your application requires.
    pub fn permissions(&mut self, permissions: Permissions) -> &mut Self {
        self.permissions = permissions;
        self
    }

    /// Specify the Id of the guild to prefill the dropdown picker for the user.
    pub fn guild_id<G: Into<GuildId>>(&mut self, guild_id: G) -> &mut Self {
        self.guild_id = guild_id.into();
        self
    }

    /// Specify whether the user cannot change the guild in the dropdown picker.
    pub fn disable_guild_select(&mut self, disable: bool) -> &mut Self {
        self.disable_guild_select = disable;
        self
    }
}
<commit_msg>Fix `cliend_id` typo<commit_after>use url::Url;

use crate::http::client::Http;
use crate::internal::prelude::*;
use crate::model::prelude::*;

/// A builder for constructing an invite link with custom OAuth2 scopes.
#[derive(Debug, Clone, Default)]
pub struct CreateBotAuthParameters {
    client_id: UserId,
    scopes: Vec<OAuth2Scope>,
    permissions: Permissions,
    guild_id: GuildId,
    disable_guild_select: bool,
}

impl CreateBotAuthParameters {
    /// Builds the url with the provided data.
    pub fn build(self) -> String {
        let mut valid_data = vec![];
        let bits = self.permissions.bits();

        if self.client_id.0 != 0 {
            valid_data.push(("client_id", self.client_id.0.to_string()));
        }

        if !self.scopes.is_empty() {
            valid_data.push((
                "scope",
                self.scopes.iter().map(|i| i.to_string()).collect::<Vec<_>>().join(" "),
            ));
        }

        if bits != 0 {
            valid_data.push(("permissions", bits.to_string()));
        }

        if self.guild_id.0 != 0 {
            valid_data.push(("guild", self.guild_id.0.to_string()));
        }

        if self.disable_guild_select {
            valid_data.push(("disable_guild_select", self.disable_guild_select.to_string()));
        }

        let url = Url::parse_with_params("https://discord.com/api/oauth2/authorize", &valid_data)
            .expect("failed to construct URL");

        url.to_string()
    }

    /// Specify the client Id of your application.
    pub fn client_id<U: Into<UserId>>(&mut self, client_id: U) -> &mut Self {
        self.client_id = client_id.into();
        self
    }

    /// Automatically fetch and set the client Id of your application by inquiring Discord's API.
    ///
    /// # Errors
    ///
    /// Returns an
    /// [`HttpError::UnsuccessfulRequest(Unauthorized)`][`HttpError::UnsuccessfulRequest`]
    /// If the user is not authorized for this endpoint.
    ///
    /// [`HttpError::UnsuccessfulRequest`]: crate::http::HttpError::UnsuccessfulRequest
    pub async fn auto_client_id(&mut self, http: impl AsRef<Http>) -> Result<&mut Self> {
        self.client_id = http.as_ref().get_current_application_info().await.map(|v| v.id)?;
        Ok(self)
    }

    /// Specify the scopes for your application.
    ///
    /// **Note**: This needs to include the [`Bot`] scope.
    ///
    /// [`Bot`]: crate::model::oauth2::OAuth2Scope::Bot
    pub fn scopes(&mut self, scopes: &[OAuth2Scope]) -> &mut Self {
        self.scopes = scopes.to_vec();
        self
    }

    /// Specify the permissions your application requires.
    pub fn permissions(&mut self, permissions: Permissions) -> &mut Self {
        self.permissions = permissions;
        self
    }

    /// Specify the Id of the guild to prefill the dropdown picker for the user.
    pub fn guild_id<G: Into<GuildId>>(&mut self, guild_id: G) -> &mut Self {
        self.guild_id = guild_id.into();
        self
    }

    /// Specify whether the user cannot change the guild in the dropdown picker.
    pub fn disable_guild_select(&mut self, disable: bool) -> &mut Self {
        self.disable_guild_select = disable;
        self
    }
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};
use std::rc::Rc;

use core::interning::InternedString;
use core::{Dependency, FeatureValue, PackageId, SourceId, Summary};
use util::CargoResult;
use util::Graph;

use super::types::RegistryQueryer;
use super::types::{ActivateResult, ConflictReason, DepInfo, GraphNode, Method, RcList};

pub use super::encode::{EncodableDependency, EncodablePackageId, EncodableResolve};
pub use super::encode::{Metadata, WorkspaceResolve};
pub use super::resolve::Resolve;

// A `Context` is basically a bunch of local resolution information which is
// kept around for all `BacktrackFrame` instances. As a result, this runs the
// risk of being cloned *a lot* so we want to make this as cheap to clone as
// possible.
#[derive(Clone)]
pub struct Context {
    // TODO: Both this and the two maps below are super expensive to clone. We should
    //       switch to persistent hash maps if we can at some point or otherwise
    //       make these much cheaper to clone in general.
    pub activations: Activations,
    pub resolve_features: HashMap<PackageId, HashSet<InternedString>>,
    pub links: HashMap<InternedString, PackageId>,

    // These are two cheaply-cloneable lists (O(1) clone) which are effectively
    // hash maps but are built up as "construction lists". We'll iterate these
    // at the very end and actually construct the map that we're making.
    pub resolve_graph: RcList<GraphNode>,
    pub resolve_replacements: RcList<(PackageId, PackageId)>,

    // These warnings are printed after resolution.
    pub warnings: RcList<String>,
}

impl Context {
    pub fn new() -> Context {
        Context {
            resolve_graph: RcList::new(),
            resolve_features: HashMap::new(),
            links: HashMap::new(),
            resolve_replacements: RcList::new(),
            activations: HashMap::new(),
            warnings: RcList::new(),
        }
    }

    /// Activate this summary by inserting it into our list of known activations.
    ///
    /// Returns true if this summary with the given method is already activated.
    pub fn flag_activated(&mut self, summary: &Summary, method: &Method) -> CargoResult<bool> {
        let id = summary.package_id();
        let prev = self.activations
            .entry((id.name(), id.source_id().clone()))
            .or_insert_with(|| Rc::new(Vec::new()));
        if !prev.iter().any(|c| c == summary) {
            self.resolve_graph.push(GraphNode::Add(id.clone()));
            if let Some(link) = summary.links() {
                ensure!(
                    self.links.insert(link, id.clone()).is_none(),
                    "Attempting to resolve a with more then one crate with the links={}. \n\
                     This will not build as is. Consider rebuilding the .lock file.",
                    &*link
                );
            }
            let mut inner: Vec<_> = (**prev).clone();
            inner.push(summary.clone());
            *prev = Rc::new(inner);
            return Ok(false);
        }
        debug!("checking if {} is already activated", summary.package_id());
        let (features, use_default) = match *method {
            Method::Everything
            | Method::Required {
                all_features: true, ..
            } => return Ok(false),
            Method::Required {
                features,
                uses_default_features,
                ..
            } => (features, uses_default_features),
        };

        let has_default_feature = summary.features().contains_key("default");
        Ok(match self.resolve_features.get(id) {
            Some(prev) => {
                features
                    .iter()
                    .all(|f| prev.contains(&InternedString::new(f)))
                    && (!use_default || prev.contains(&InternedString::new("default"))
                        || !has_default_feature)
            }
            None => features.is_empty() && (!use_default || !has_default_feature),
        })
    }

    pub fn build_deps(
        &mut self,
        registry: &mut RegistryQueryer,
        parent: Option<&Summary>,
        candidate: &Summary,
        method: &Method,
    ) -> ActivateResult<Vec<DepInfo>> {
        // First, figure out our set of dependencies based on the requested set
        // of features. This also calculates what features we're going to enable
        // for our own dependencies.
        let deps = self.resolve_features(parent, candidate, method)?;

        // Next, transform all dependencies into a list of possible candidates
        // which can satisfy that dependency.
        let mut deps = deps.into_iter()
            .map(|(dep, features)| {
                let candidates = registry.query(&dep)?;
                Ok((dep, candidates, Rc::new(features)))
            })
            .collect::<CargoResult<Vec<DepInfo>>>()?;

        // Attempt to resolve dependencies with fewer candidates before trying
        // dependencies with more candidates.  This way if the dependency with
        // only one candidate can't be resolved we don't have to do a bunch of
        // work before we figure that out.
        deps.sort_by_key(|&(_, ref a, _)| a.len());

        Ok(deps)
    }

    pub fn prev_active(&self, dep: &Dependency) -> &[Summary] {
        self.activations
            .get(&(dep.name(), dep.source_id().clone()))
            .map(|v| &v[..])
            .unwrap_or(&[])
    }

    fn is_active(&self, id: &PackageId) -> bool {
        self.activations
            .get(&(id.name(), id.source_id().clone()))
            .map(|v| v.iter().any(|s| s.package_id() == id))
            .unwrap_or(false)
    }

    /// checks whether all of `parent` and the keys of `conflicting activations`
    /// are still active
    pub fn is_conflicting(
        &self,
        parent: Option<&PackageId>,
        conflicting_activations: &HashMap<PackageId, ConflictReason>,
    ) -> bool {
        conflicting_activations
            .keys()
            .chain(parent)
            .all(|id| self.is_active(id))
    }

    /// Return all dependencies and the features we want from them.
    fn resolve_features<'b>(
        &mut self,
        parent: Option<&Summary>,
        s: &'b Summary,
        method: &'b Method,
    ) -> ActivateResult<Vec<(Dependency, Vec<InternedString>)>> {
        let dev_deps = match *method {
            Method::Everything => true,
            Method::Required { dev_deps, .. } => dev_deps,
        };

        // First, filter by dev-dependencies
        let deps = s.dependencies();
        let deps = deps.iter().filter(|d| d.is_transitive() || dev_deps);

        // Requested features stored in the Method are stored as string references, but we want to
        // transform them into FeatureValues here. In order to pass the borrow checker with
        // storage of the FeatureValues that outlives the Requirements object, we do the
        // transformation here, and pass the FeatureValues to build_requirements().
        let values = if let Method::Required {
            all_features: false,
            features: requested,
            ..
        } = *method
        {
            requested
                .iter()
                .map(|&f| FeatureValue::new(f, s))
                .collect::<Vec<FeatureValue>>()
        } else {
            vec![]
        };
        let mut reqs = build_requirements(s, method, &values)?;
        let mut ret = Vec::new();

        // Next, collect all actually enabled dependencies and their features.
        for dep in deps {
            // Skip optional dependencies, but not those enabled through a feature
            if dep.is_optional() && !reqs.deps.contains_key(&*dep.name()) {
                continue;
            }
            // So we want this dependency.  Move the features we want from `feature_deps`
            // to `ret`.
            let base = reqs.deps.remove(&*dep.name()).unwrap_or((false, vec![]));
            if !dep.is_optional() && base.0 {
                self.warnings.push(format!(
                    "Package `{}` does not have feature `{}`. It has a required dependency \
                     with that name, but only optional dependencies can be used as features. \
                     This is currently a warning to ease the transition, but it will become an \
                     error in the future.",
                    s.package_id(),
                    dep.name()
                ));
            }
            let mut base = base.1;
            base.extend(dep.features().iter());
            for feature in base.iter() {
                if feature.contains('/') {
                    return Err(
                        format_err!("feature names may not contain slashes: `{}`", feature).into(),
                    );
                }
            }
            ret.push((dep.clone(), base));
        }

        // Any remaining entries in feature_deps are bugs in that the package does not actually
        // have those dependencies.  We classified them as dependencies in the first place
        // because there is no such feature, either.
        if !reqs.deps.is_empty() {
            let unknown = reqs.deps.keys().map(|s| &s[..]).collect::<Vec<&str>>();
            let features = unknown.join(", ");
            return Err(match parent {
                None => format_err!(
                    "Package `{}` does not have these features: `{}`",
                    s.package_id(),
                    features
                ).into(),
                Some(p) => (
                    p.package_id().clone(),
                    ConflictReason::MissingFeatures(features),
                ).into(),
            });
        }

        // Record what list of features is active for this package.
        if !reqs.used.is_empty() {
            let pkgid = s.package_id();

            let set = self.resolve_features
                .entry(pkgid.clone())
                .or_insert_with(HashSet::new);
            for feature in reqs.used {
                set.insert(InternedString::new(feature));
            }
        }

        Ok(ret)
    }

    pub fn resolve_replacements(&self) -> HashMap<PackageId, PackageId> {
        let mut replacements = HashMap::new();
        let mut cur = &self.resolve_replacements;
        while let Some(ref node) = cur.head {
            let (k, v) = node.0.clone();
            replacements.insert(k, v);
            cur = &node.1;
        }
        replacements
    }

    pub fn graph(&self) -> Graph<PackageId> {
        let mut graph = Graph::new();
        let mut cur = &self.resolve_graph;
        while let Some(ref node) = cur.head {
            match node.0 {
                GraphNode::Add(ref p) => graph.add(p.clone(), &[]),
                GraphNode::Link(ref a, ref b) => graph.link(a.clone(), b.clone()),
            }
            cur = &node.1;
        }
        graph
    }
}

/// Takes requested features for a single package from the input Method and
/// recurses to find all requested features, dependencies and requested
/// dependency features in a Requirements object, returning it to the resolver.
fn build_requirements<'a, 'b: 'a>(
    s: &'a Summary,
    method: &'b Method,
    requested: &'a [FeatureValue],
) -> CargoResult<Requirements<'a>> {
    let mut reqs = Requirements::new(s);
    for fv in requested.iter() {
        reqs.require_value(fv)?;
    }
    match *method {
        Method::Everything
        | Method::Required {
            all_features: true, ..
        } => {
            for key in s.features().keys() {
                reqs.require_feature(key)?;
            }
            for dep in s.dependencies().iter().filter(|d| d.is_optional()) {
                reqs.require_dependency(dep.name().as_str());
            }
        }
        _ => {} // Explicitly requested features are handled through `requested`
    }
    match *method {
        Method::Everything
        | Method::Required {
            uses_default_features: true,
            ..
        } => {
            if s.features().get("default").is_some() {
                reqs.require_feature("default")?;
            }
        }
        Method::Required {
            uses_default_features: false,
            ..
        } => {}
    }
    Ok(reqs)
}

struct Requirements<'a> {
    summary: &'a Summary,
    // The deps map is a mapping of package name to list of features enabled.
    // Each package should be enabled, and each package should have the
    // specified set of features enabled. The boolean indicates whether this
    // package was specifically requested (rather than just requesting features
    // *within* this package).
    deps: HashMap<&'a str, (bool, Vec<InternedString>)>,
    // The used features set is the set of features which this local package had
    // enabled, which is later used when compiling to instruct the code what
    // features were enabled.
    used: HashSet<&'a str>,
    visited: HashSet<&'a str>,
}

impl<'r> Requirements<'r> {
    fn new(summary: &Summary) -> Requirements {
        Requirements {
            summary,
            deps: HashMap::new(),
            used: HashSet::new(),
            visited: HashSet::new(),
        }
    }

    fn require_crate_feature(&mut self, package: &'r str, feat: InternedString) {
        self.used.insert(package);
        self.deps
            .entry(package)
            .or_insert((false, Vec::new()))
            .1
            .push(feat);
    }

    fn seen(&mut self, feat: &'r str) -> bool {
        if self.visited.insert(feat) {
            self.used.insert(feat);
            false
        } else {
            true
        }
    }

    fn require_dependency(&mut self, pkg: &'r str) {
        if self.seen(pkg) {
            return;
        }
        self.deps.entry(pkg).or_insert((false, Vec::new())).0 = true;
    }

    fn require_feature(&mut self, feat: &'r str) -> CargoResult<()> {
        if feat.is_empty() || self.seen(feat) {
            return Ok(());
        }
        for fv in self.summary
            .features()
            .get(feat)
            .expect("must be a valid feature")
        {
            match *fv {
                FeatureValue::Feature(ref dep_feat) if **dep_feat == *feat => bail!(
                    "Cyclic feature dependency: feature `{}` depends on itself",
                    feat
                ),
                _ => {}
            }
            self.require_value(fv)?;
        }
        Ok(())
    }

    fn require_value(&mut self, fv: &'r FeatureValue) -> CargoResult<()> {
        match *fv {
            FeatureValue::Feature(ref feat) => self.require_feature(feat),
            FeatureValue::Crate(ref dep) => Ok(self.require_dependency(dep)),
            FeatureValue::CrateFeature(ref dep, dep_feat) => {
                Ok(self.require_crate_feature(dep, dep_feat))
            }
        }
    }
}

pub type Activations = HashMap<(InternedString, SourceId), Rc<Vec<Summary>>>;
<commit_msg>Auto merge of #5302 - Eh2406:MoreRc, r=alexcrichton<commit_after>use std::collections::{HashMap, HashSet};
use std::rc::Rc;

use core::interning::InternedString;
use core::{Dependency, FeatureValue, PackageId, SourceId, Summary};
use util::CargoResult;
use util::Graph;

use super::types::RegistryQueryer;
use super::types::{ActivateResult, ConflictReason, DepInfo, GraphNode, Method, RcList};

pub use super::encode::{EncodableDependency, EncodablePackageId, EncodableResolve};
pub use super::encode::{Metadata, WorkspaceResolve};
pub use super::resolve::Resolve;

// A `Context` is basically a bunch of local resolution information which is
// kept around for all `BacktrackFrame` instances. As a result, this runs the
// risk of being cloned *a lot* so we want to make this as cheap to clone as
// possible.
#[derive(Clone)]
pub struct Context {
    // TODO: Both this and the two maps below are super expensive to clone. We should
    //       switch to persistent hash maps if we can at some point or otherwise
    //       make these much cheaper to clone in general.
    pub activations: Activations,
    pub resolve_features: HashMap<PackageId, Rc<HashSet<InternedString>>>,
    pub links: HashMap<InternedString, PackageId>,

    // These are two cheaply-cloneable lists (O(1) clone) which are effectively
    // hash maps but are built up as "construction lists". We'll iterate these
    // at the very end and actually construct the map that we're making.
    pub resolve_graph: RcList<GraphNode>,
    pub resolve_replacements: RcList<(PackageId, PackageId)>,

    // These warnings are printed after resolution.
    pub warnings: RcList<String>,
}

pub type Activations = HashMap<(InternedString, SourceId), Rc<Vec<Summary>>>;

impl Context {
    pub fn new() -> Context {
        Context {
            resolve_graph: RcList::new(),
            resolve_features: HashMap::new(),
            links: HashMap::new(),
            resolve_replacements: RcList::new(),
            activations: HashMap::new(),
            warnings: RcList::new(),
        }
    }

    /// Activate this summary by inserting it into our list of known activations.
    ///
    /// Returns true if this summary with the given method is already activated.
    pub fn flag_activated(&mut self, summary: &Summary, method: &Method) -> CargoResult<bool> {
        let id = summary.package_id();
        let prev = self.activations
            .entry((id.name(), id.source_id().clone()))
            .or_insert_with(|| Rc::new(Vec::new()));
        if !prev.iter().any(|c| c == summary) {
            self.resolve_graph.push(GraphNode::Add(id.clone()));
            if let Some(link) = summary.links() {
                ensure!(
                    self.links.insert(link, id.clone()).is_none(),
                    "Attempting to resolve a with more then one crate with the links={}. \n\
                     This will not build as is. Consider rebuilding the .lock file.",
                    &*link
                );
            }
            Rc::make_mut(prev).push(summary.clone());
            return Ok(false);
        }
        debug!("checking if {} is already activated", summary.package_id());
        let (features, use_default) = match *method {
            Method::Everything
            | Method::Required {
                all_features: true, ..
            } => return Ok(false),
            Method::Required {
                features,
                uses_default_features,
                ..
            } => (features, uses_default_features),
        };

        let has_default_feature = summary.features().contains_key("default");
        Ok(match self.resolve_features.get(id) {
            Some(prev) => {
                features
                    .iter()
                    .all(|f| prev.contains(&InternedString::new(f)))
                    && (!use_default || prev.contains(&InternedString::new("default"))
                        || !has_default_feature)
            }
            None => features.is_empty() && (!use_default || !has_default_feature),
        })
    }

    pub fn build_deps(
        &mut self,
        registry: &mut RegistryQueryer,
        parent: Option<&Summary>,
        candidate: &Summary,
        method: &Method,
    ) -> ActivateResult<Vec<DepInfo>> {
        // First, figure out our set of dependencies based on the requested set
        // of features. This also calculates what features we're going to enable
        // for our own dependencies.
        let deps = self.resolve_features(parent, candidate, method)?;

        // Next, transform all dependencies into a list of possible candidates
        // which can satisfy that dependency.
        let mut deps = deps.into_iter()
            .map(|(dep, features)| {
                let candidates = registry.query(&dep)?;
                Ok((dep, candidates, Rc::new(features)))
            })
            .collect::<CargoResult<Vec<DepInfo>>>()?;

        // Attempt to resolve dependencies with fewer candidates before trying
        // dependencies with more candidates.  This way if the dependency with
        // only one candidate can't be resolved we don't have to do a bunch of
        // work before we figure that out.
        deps.sort_by_key(|&(_, ref a, _)| a.len());

        Ok(deps)
    }

    pub fn prev_active(&self, dep: &Dependency) -> &[Summary] {
        self.activations
            .get(&(dep.name(), dep.source_id().clone()))
            .map(|v| &v[..])
            .unwrap_or(&[])
    }

    fn is_active(&self, id: &PackageId) -> bool {
        self.activations
            .get(&(id.name(), id.source_id().clone()))
            .map(|v| v.iter().any(|s| s.package_id() == id))
            .unwrap_or(false)
    }

    /// checks whether all of `parent` and the keys of `conflicting activations`
    /// are still active
    pub fn is_conflicting(
        &self,
        parent: Option<&PackageId>,
        conflicting_activations: &HashMap<PackageId, ConflictReason>,
    ) -> bool {
        conflicting_activations
            .keys()
            .chain(parent)
            .all(|id| self.is_active(id))
    }

    /// Return all dependencies and the features we want from them.
    fn resolve_features<'b>(
        &mut self,
        parent: Option<&Summary>,
        s: &'b Summary,
        method: &'b Method,
    ) -> ActivateResult<Vec<(Dependency, Vec<InternedString>)>> {
        let dev_deps = match *method {
            Method::Everything => true,
            Method::Required { dev_deps, .. } => dev_deps,
        };

        // First, filter by dev-dependencies
        let deps = s.dependencies();
        let deps = deps.iter().filter(|d| d.is_transitive() || dev_deps);

        // Requested features stored in the Method are stored as string references, but we want to
        // transform them into FeatureValues here. In order to pass the borrow checker with
        // storage of the FeatureValues that outlives the Requirements object, we do the
        // transformation here, and pass the FeatureValues to build_requirements().
        let values = if let Method::Required {
            all_features: false,
            features: requested,
            ..
        } = *method
        {
            requested
                .iter()
                .map(|&f| FeatureValue::new(f, s))
                .collect::<Vec<FeatureValue>>()
        } else {
            vec![]
        };
        let mut reqs = build_requirements(s, method, &values)?;
        let mut ret = Vec::new();

        // Next, collect all actually enabled dependencies and their features.
        for dep in deps {
            // Skip optional dependencies, but not those enabled through a feature
            if dep.is_optional() && !reqs.deps.contains_key(&*dep.name()) {
                continue;
            }
            // So we want this dependency.  Move the features we want from `feature_deps`
            // to `ret`.
            let base = reqs.deps.remove(&*dep.name()).unwrap_or((false, vec![]));
            if !dep.is_optional() && base.0 {
                self.warnings.push(format!(
                    "Package `{}` does not have feature `{}`. It has a required dependency \
                     with that name, but only optional dependencies can be used as features. \
                     This is currently a warning to ease the transition, but it will become an \
                     error in the future.",
                    s.package_id(),
                    dep.name()
                ));
            }
            let mut base = base.1;
            base.extend(dep.features().iter());
            for feature in base.iter() {
                if feature.contains('/') {
                    return Err(
                        format_err!("feature names may not contain slashes: `{}`", feature).into(),
                    );
                }
            }
            ret.push((dep.clone(), base));
        }

        // Any remaining entries in feature_deps are bugs in that the package does not actually
        // have those dependencies.  We classified them as dependencies in the first place
        // because there is no such feature, either.
        if !reqs.deps.is_empty() {
            let unknown = reqs.deps.keys().map(|s| &s[..]).collect::<Vec<&str>>();
            let features = unknown.join(", ");
            return Err(match parent {
                None => format_err!(
                    "Package `{}` does not have these features: `{}`",
                    s.package_id(),
                    features
                ).into(),
                Some(p) => (
                    p.package_id().clone(),
                    ConflictReason::MissingFeatures(features),
                ).into(),
            });
        }

        // Record what list of features is active for this package.
        if !reqs.used.is_empty() {
            let pkgid = s.package_id();

            let set = Rc::make_mut(self.resolve_features
                .entry(pkgid.clone())
                .or_insert_with(|| Rc::new(HashSet::new())));

            for feature in reqs.used {
                set.insert(InternedString::new(feature));
            }
        }

        Ok(ret)
    }

    pub fn resolve_replacements(&self) -> HashMap<PackageId, PackageId> {
        let mut replacements = HashMap::new();
        let mut cur = &self.resolve_replacements;
        while let Some(ref node) = cur.head {
            let (k, v) = node.0.clone();
            replacements.insert(k, v);
            cur = &node.1;
        }
        replacements
    }

    pub fn graph(&self) -> Graph<PackageId> {
        let mut graph = Graph::new();
        let mut cur = &self.resolve_graph;
        while let Some(ref node) = cur.head {
            match node.0 {
                GraphNode::Add(ref p) => graph.add(p.clone(), &[]),
                GraphNode::Link(ref a, ref b) => graph.link(a.clone(), b.clone()),
            }
            cur = &node.1;
        }
        graph
    }
}

/// Takes requested features for a single package from the input Method and
/// recurses to find all requested features, dependencies and requested
/// dependency features in a Requirements object, returning it to the resolver.
fn build_requirements<'a, 'b: 'a>(
    s: &'a Summary,
    method: &'b Method,
    requested: &'a [FeatureValue],
) -> CargoResult<Requirements<'a>> {
    let mut reqs = Requirements::new(s);
    for fv in requested.iter() {
        reqs.require_value(fv)?;
    }
    match *method {
        Method::Everything
        | Method::Required {
            all_features: true, ..
        } => {
            for key in s.features().keys() {
                reqs.require_feature(key)?;
            }
            for dep in s.dependencies().iter().filter(|d| d.is_optional()) {
                reqs.require_dependency(dep.name().as_str());
            }
        }
        _ => {} // Explicitly requested features are handled through `requested`
    }
    match *method {
        Method::Everything
        | Method::Required {
            uses_default_features: true,
            ..
        } => {
            if s.features().get("default").is_some() {
                reqs.require_feature("default")?;
            }
        }
        Method::Required {
            uses_default_features: false,
            ..
        } => {}
    }
    Ok(reqs)
}

struct Requirements<'a> {
    summary: &'a Summary,
    // The deps map is a mapping of package name to list of features enabled.
    // Each package should be enabled, and each package should have the
    // specified set of features enabled. The boolean indicates whether this
    // package was specifically requested (rather than just requesting features
    // *within* this package).
    deps: HashMap<&'a str, (bool, Vec<InternedString>)>,
    // The used features set is the set of features which this local package had
    // enabled, which is later used when compiling to instruct the code what
    // features were enabled.
    used: HashSet<&'a str>,
    visited: HashSet<&'a str>,
}

impl<'r> Requirements<'r> {
    fn new(summary: &Summary) -> Requirements {
        Requirements {
            summary,
            deps: HashMap::new(),
            used: HashSet::new(),
            visited: HashSet::new(),
        }
    }

    fn require_crate_feature(&mut self, package: &'r str, feat: InternedString) {
        self.used.insert(package);
        self.deps
            .entry(package)
            .or_insert((false, Vec::new()))
            .1
            .push(feat);
    }

    fn seen(&mut self, feat: &'r str) -> bool {
        if self.visited.insert(feat) {
            self.used.insert(feat);
            false
        } else {
            true
        }
    }

    fn require_dependency(&mut self, pkg: &'r str) {
        if self.seen(pkg) {
            return;
        }
        self.deps.entry(pkg).or_insert((false, Vec::new())).0 = true;
    }

    fn require_feature(&mut self, feat: &'r str) -> CargoResult<()> {
        if feat.is_empty() || self.seen(feat) {
            return Ok(());
        }
        for fv in self.summary
            .features()
            .get(feat)
            .expect("must be a valid feature")
        {
            match *fv {
                FeatureValue::Feature(ref dep_feat) if **dep_feat == *feat => bail!(
                    "Cyclic feature dependency: feature `{}` depends on itself",
                    feat
                ),
                _ => {}
            }
            self.require_value(fv)?;
        }
        Ok(())
    }

    fn require_value(&mut self, fv: &'r FeatureValue) -> CargoResult<()> {
        match *fv {
            FeatureValue::Feature(ref feat) => self.require_feature(feat),
            FeatureValue::Crate(ref dep) => Ok(self.require_dependency(dep)),
            FeatureValue::CrateFeature(ref dep, dep_feat) => {
                Ok(self.require_crate_feature(dep, dep_feat))
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate rand;
extern crate timely;
extern crate differential_dataflow;

use rand::{Rng, SeedableRng, StdRng};

use timely::dataflow::*;
use timely::dataflow::operators::probe::Handle;

use differential_dataflow::input::Input;
use differential_dataflow::Collection;
use differential_dataflow::operators::*;
use differential_dataflow::lattice::Lattice;
use differential_dataflow::operators::iterate::Variable;

type Node = usize;
type Edge = (Node, Node);

fn main() {

    let nodes: usize = std::env::args().nth(1).unwrap().parse().unwrap();
    let edges: usize = std::env::args().nth(2).unwrap().parse().unwrap();
    let inspect: bool = std::env::args().any(|x| x == "inspect");

    // Our setting involves four read query types, and two updatable base relations.
    //
    //  Q1: Point lookup: reads "state" associated with a node.
    //  Q2: One-hop lookup: reads "state" associated with neighbors of a node.
    //  Q3: Two-hop lookup: reads "state" associated with n-of-n's of a node.
    //  Q4: Shortest path: reports hop count between two query nodes.
    //
    //  R1: "State": a pair of (node, T) for some type T that I don't currently know.
    //  R2: "Graph": pairs (node, node) indicating linkage between the two nodes.

    timely::execute_from_args(std::env::args().skip(3), move |worker| {

        let index = worker.index();
        let peers = worker.peers();
        let timer = ::std::time::Instant::now();

        // define BFS dataflow; return handles to roots and edges inputs
        let mut probe = Handle::new();

        let (mut q1, mut q2, mut q3, mut q4, mut state, mut graph) = worker.dataflow(|scope| {

            let (q1_input, q1) = scope.new_collection();
            let (q2_input, q2) = scope.new_collection();
            let (q3_input, q3) = scope.new_collection();
            let (q4_input, q4) = scope.new_collection();

            let (state_input, state) = scope.new_collection();
            let (graph_input, graph) = scope.new_collection();

            // Q1: Point lookups on `state`:
            state
                .semijoin(&q1)
                .filter(move |_| inspect)
                .inspect(|x| println!("Q1: {:?}", x))
                .probe_with(&mut probe);

            // Q2: One-hop lookups on `state`:
            graph
                .semijoin(&q2)
                .map(|(query, friend)| (friend, query))
                .join_map(&state, |_friend, &query, &state| (query, state))
                .filter(move |_| inspect)
                .inspect(|x| println!("Q2: {:?}", x))
                .probe_with(&mut probe);

            // Q3: Two-hop lookups on `state`:
            graph
                .semijoin(&q3)
                .map(|(query, friend)| (friend, query))
                .join_map(&graph, |_friend, &query, &friend2| (friend2, query))
                .join_map(&state, |_friend2, &query, &state| (query, state))
                .filter(move |_| inspect)
                .consolidate()
                .inspect(|x| println!("Q3: {:?}", x))
                .probe_with(&mut probe);

            // Q4: Shortest path queries:
            bidijkstra(&graph, &q4)
                .filter(move |_| inspect)
                .inspect(|x| println!("Q4: {:?}", x))
                .probe_with(&mut probe);

            (q1_input, q2_input, q3_input, q4_input, state_input, graph_input)
        });

        let seed: &[_] = &[1, 2, 3, index];
        let mut rng1: StdRng = SeedableRng::from_seed(seed);    // rng for edge additions
        // let mut rng2: StdRng = SeedableRng::from_seed(seed);    // rng for edge deletions
        let mut rng3: StdRng = SeedableRng::from_seed(seed);    // rng for queries

        println!("performing workload on random graph with {} nodes, {} edges:", nodes, edges);

        let worker_edges = edges/peers + if index < (edges % peers) { 1 } else { 0 };
        for _ in 0 .. worker_edges {
            graph.insert((rng1.gen_range(0, nodes), rng1.gen_range(0, nodes)));
        }
        for node in 0 .. nodes {
            if node % peers == index {
                state.insert((node, node));
            }
        }

        q1.advance_to(1);       q1.flush();     // q1 queries start now.
        q2.advance_to(1001);    q2.flush();     // q2 queries start here.
        q3.advance_to(2001);    q3.flush();     // q3 queries start here.
        q4.advance_to(3001);    q4.flush();     // q4 queries start here.
        state.close();                          // no changes to state.
        graph.close();                          // no changes to graph.

        // finish graph loading work.
        while probe.less_than(q1.time()) { worker.step(); }

        println!("{:?}\tgraph loaded", timer.elapsed());

        // Q1 testing:
        let timer_q1 = ::std::time::Instant::now();
        for round in 1 .. 1001 {
            q1.insert(rng3.gen_range(0, nodes));
            q1.advance_to(round);
            q1.flush();
            while probe.less_than(q1.time()) { worker.step(); }
        }
        println!("{:?}\tq1 eval complete; avg: {:?}", timer.elapsed(), timer_q1.elapsed()/1000);
        q1.close();

        // Q2 testing:
        let timer_q2 = ::std::time::Instant::now();
        for round in 1001 .. 2001 {
            q2.insert(rng3.gen_range(0, nodes));
            q2.advance_to(round);
            q2.flush();
            while probe.less_than(q2.time()) { worker.step(); }
        }
        println!("{:?}\tq2 eval complete; avg: {:?}", timer.elapsed(), timer_q2.elapsed()/1000);
        q2.close();

        // Q3 testing:
        let timer_q3 = ::std::time::Instant::now();
        for round in 2001 .. 3001 {
            q3.insert(rng3.gen_range(0, nodes));
            q3.advance_to(round);
            q3.flush();
            while probe.less_than(q3.time()) { worker.step(); }
        }
        println!("{:?}\tq3 eval complete; avg: {:?}", timer.elapsed(), timer_q3.elapsed()/1000);
        q3.close();

        // Q4 testing:
        let timer_q4 = ::std::time::Instant::now();
        for round in 3001 .. 4001 {
            q4.insert((rng3.gen_range(0, nodes), rng3.gen_range(0, nodes)));
            q4.advance_to(round);
            q4.flush();
            while probe.less_than(q4.time()) { worker.step(); }
        }
        println!("{:?}\tq4 eval complete; avg: {:?}", timer.elapsed(), timer_q4.elapsed()/1000);
        q4.close();

    }).unwrap();
}

// returns pairs (n, s) indicating node n can be reached from a root in s steps.
fn bidijkstra<G: Scope>(edges: &Collection<G, Edge>, goals: &Collection<G, (Node, Node)>) -> Collection<G, ((Node, Node), u32)>
where G::Timestamp: Lattice+Ord {

    edges.scope().scoped(|inner| {

        // Our plan is to start evolving distances from both sources and destinations.
        // The evolution from a source or destination should continue as long as there
        // is a corresponding destination or source that has not yet been reached.

        // forward and reverse (node, (root, dist))
        let forward = Variable::from(goals.map(|(x,_)| (x,(x,0))).enter(inner));
        let reverse = Variable::from(goals.map(|(_,y)| (y,(y,0))).enter(inner));

        let goals = goals.enter(inner);
        let edges = edges.enter(inner);

        // Let's determine which (src, dst) pairs are ready to return.
        //
        //   done(src, dst) := forward(src, med), reverse(dst, med), goal(src, dst).
        //
        // This is a cyclic join, which should scare us a bunch.
        let reached =
        forward
            .join_map(&reverse, |_, &(src,d1), &(dst,d2)| ((src, dst), d1 + d2))
            .group(|_key, s, t| t.push((*s[0].0, 1)))
            .semijoin(&goals);

        let active =
        reached
            .negate()
            .map(|(srcdst,_)| srcdst)
            .concat(&goals)
            .consolidate();

        // Let's expand out forward queries that are active.
        let forward_active = active.map(|(x,_y)| x).distinct();
        let forward_next =
        forward
            .map(|(med, (src, dist))| (src, (med, dist)))
            .semijoin(&forward_active)
            .map(|(src, (med, dist))| (med, (src, dist)))
            .join_map(&edges, |_med, &(src, dist), &next| (next, (src, dist+1)))
            .concat(&forward)
            .map(|(next, (src, dist))| ((next, src), dist))
            .group(|_key, s, t| t.push((*s[0].0, 1)))
            .map(|((next, src), dist)| (next, (src, dist)));

        forward.set(&forward_next);

        // Let's expand out reverse queries that are active.
        let reverse_active = active.map(|(_x,y)| y).distinct();
        let reverse_next =
        reverse
            .map(|(med, (rev, dist))| (rev, (med, dist)))
            .semijoin(&reverse_active)
            .map(|(rev, (med, dist))| (med, (rev, dist)))
            .join_map(&edges.map(|(x,y)| (y,x)), |_med, &(rev, dist), &next| (next, (rev, dist+1)))
            .concat(&reverse)
            .map(|(next, (rev, dist))| ((next, rev), dist))
            .group(|_key, s, t| t.push((*s[0].0, 1)))
            .map(|((next,rev), dist)| (next, (rev, dist)));

        reverse.set(&reverse_next);

        reached.leave()
    })
}<commit_msg>more featurez<commit_after>extern crate rand;
extern crate timely;
extern crate differential_dataflow;

use rand::{Rng, SeedableRng, StdRng};

use timely::dataflow::*;
use timely::dataflow::operators::probe::Handle;

use differential_dataflow::input::Input;
use differential_dataflow::Collection;
use differential_dataflow::operators::*;
use differential_dataflow::lattice::Lattice;
use differential_dataflow::operators::iterate::Variable;
use differential_dataflow::operators::arrange::ArrangeByKey;
use differential_dataflow::operators::arrange::ArrangeBySelf;

type Node = usize;
type Edge = (Node, Node);

fn main() {

    let nodes: usize = std::env::args().nth(1).unwrap().parse().unwrap();
    let edges: usize = std::env::args().nth(2).unwrap().parse().unwrap();
    let batch: usize = std::env::args().nth(3).unwrap().parse().unwrap();
    let inspect: bool = std::env::args().any(|x| x == "inspect");

    // Our setting involves four read query types, and two updatable base relations.
    //
    //  Q1: Point lookup: reads "state" associated with a node.
    //  Q2: One-hop lookup: reads "state" associated with neighbors of a node.
    //  Q3: Two-hop lookup: reads "state" associated with n-of-n's of a node.
    //  Q4: Shortest path: reports hop count between two query nodes.
    //
    //  R1: "State": a pair of (node, T) for some type T that I don't currently know.
    //  R2: "Graph": pairs (node, node) indicating linkage between the two nodes.

    timely::execute_from_args(std::env::args().skip(3), move |worker| {

        let index = worker.index();
        let peers = worker.peers();
        let timer = ::std::time::Instant::now();

        // define BFS dataflow; return handles to roots and edges inputs
        let mut probe = Handle::new();

        let (mut q1, mut q2, mut q3, mut q4, mut state, mut graph) = worker.dataflow(|scope| {

            let (q1_input, q1) = scope.new_collection();
            let (q2_input, q2) = scope.new_collection();
            let (q3_input, q3) = scope.new_collection();
            let (q4_input, q4) = scope.new_collection();

            let (state_input, state) = scope.new_collection();
            let (graph_input, graph) = scope.new_collection();

            let state_indexed = state.arrange_by_key();
            let graph_indexed = graph.map(|(src, dst)| (dst, src))
                                     .concat(&graph)
                                     .arrange_by_key();

            // Q1: Point lookups on `state`:
            q1  .arrange_by_self()
                .join_core(&state_indexed, |&query, &(), &state| Some((query, state)))
                .filter(move |_| inspect)
                .inspect(|x| println!("Q1: {:?}", x))
                .probe_with(&mut probe);

            // Q2: One-hop lookups on `state`:
            q2  .arrange_by_self()
                .join_core(&graph_indexed, |&query, &(), &friend| Some((friend, query)))
                .join_core(&state_indexed, |_friend, &query, &state| Some((query, state)))
                .filter(move |_| inspect)
                .inspect(|x| println!("Q2: {:?}", x))
                .probe_with(&mut probe);

            // Q3: Two-hop lookups on `state`:
            q3  .arrange_by_self()
                .join_core(&graph_indexed, |&query, &(), &friend| Some((friend, query)))
                .join_core(&graph_indexed, |_friend, &query, &friend2| Some((friend2, query)))
                .join_core(&state_indexed, |_friend2, &query, &state| Some((query, state)))
                .filter(move |_| inspect)
                .consolidate()
                .inspect(|x| println!("Q3: {:?}", x))
                .probe_with(&mut probe);

            // Q4: Shortest path queries:
            bidijkstra(&graph_indexed, &graph_indexed, &q4)
                .filter(move |_| inspect)
                .inspect(|x| println!("Q4: {:?}", x))
                .probe_with(&mut probe);

            (q1_input, q2_input, q3_input, q4_input, state_input, graph_input)
        });

        let seed: &[_] = &[1, 2, 3, index];
        let mut rng1: StdRng = SeedableRng::from_seed(seed);    // rng for edge additions
        // let mut rng2: StdRng = SeedableRng::from_seed(seed);    // rng for edge deletions
        let mut rng3: StdRng = SeedableRng::from_seed(seed);    // rng for queries

        if index == 0 { println!("performing workload on random graph with {} nodes, {} edges:", nodes, edges); }

        let worker_edges = edges/peers + if index < (edges % peers) { 1 } else { 0 };
        for _ in 0 .. worker_edges {
            graph.insert((rng1.gen_range(0, nodes), rng1.gen_range(0, nodes)));
        }
        for node in 0 .. nodes {
            if node % peers == index {
                state.insert((node, node));
            }
        }

        q1.advance_to(1);       q1.flush();     // q1 queries start now.
        q2.advance_to(1001);    q2.flush();     // q2 queries start here.
        q3.advance_to(2001);    q3.flush();     // q3 queries start here.
        q4.advance_to(3001);    q4.flush();     // q4 queries start here.
        state.close();                          // no changes to state.
        graph.close();                          // no changes to graph.

        // finish graph loading work.
        while probe.less_than(q1.time()) { worker.step(); }

        if index == 0 { println!("{:?}\tgraph loaded", timer.elapsed()); }

        let worker_batch = batch/peers + if index < batch % peers { 1 } else { 0 };

        // Q1 testing:
        let timer_q1 = ::std::time::Instant::now();
        for round in 1 .. 1001 {
            for _ in 0 .. worker_batch {
                q1.insert(rng3.gen_range(0, nodes));
            }
            q1.advance_to(round);
            q1.flush();
            while probe.less_than(q1.time()) { worker.step(); }
        }
        if index == 0 { println!("{:?}\tq1 eval complete; avg: {:?}", timer.elapsed(), timer_q1.elapsed()/1000); }
        q1.close();

        // Q2 testing:
        let timer_q2 = ::std::time::Instant::now();
        for round in 1001 .. 2001 {
            for _ in 0 .. worker_batch {
                q2.insert(rng3.gen_range(0, nodes));
            }
            q2.advance_to(round);
            q2.flush();
            while probe.less_than(q2.time()) { worker.step(); }
        }
        if index == 0 { println!("{:?}\tq2 eval complete; avg: {:?}", timer.elapsed(), timer_q2.elapsed()/1000); }
        q2.close();

        // Q3 testing:
        let timer_q3 = ::std::time::Instant::now();
        for round in 2001 .. 3001 {
            for _ in 0 .. worker_batch {
                q3.insert(rng3.gen_range(0, nodes));
            }
            q3.advance_to(round);
            q3.flush();
            while probe.less_than(q3.time()) { worker.step(); }
        }
        if index == 0 { println!("{:?}\tq3 eval complete; avg: {:?}", timer.elapsed(), timer_q3.elapsed()/1000); }
        q3.close();

        // Q4 testing:
        let timer_q4 = ::std::time::Instant::now();
        for round in 3001 .. 4001 {
            for _ in 0 .. worker_batch {
               q4.insert((rng3.gen_range(0, nodes), rng3.gen_range(0, nodes)));
            }
            q4.advance_to(round);
            q4.flush();
            while probe.less_than(q4.time()) { worker.step(); }
        }
        if index == 0 { println!("{:?}\tq4 eval complete; avg: {:?}", timer.elapsed(), timer_q4.elapsed()/1000); }
        q4.close();

    }).unwrap();
}

use differential_dataflow::trace::implementations::ord::OrdValSpine as DefaultValTrace;
use differential_dataflow::operators::arrange::TraceAgent;
use differential_dataflow::operators::arrange::Arranged;

type Arrange<G: Scope, K, V, R> = Arranged<G, K, V, R, TraceAgent<K, V, G::Timestamp, R, DefaultValTrace<K, V, G::Timestamp, R>>>;

// returns pairs (n, s) indicating node n can be reached from a root in s steps.
fn bidijkstra<G: Scope>(
    forward_graph: &Arrange<G, Node, Node, isize>,
    reverse_graph: &Arrange<G, Node, Node, isize>,
    goals: &Collection<G, (Node, Node)>) -> Collection<G, ((Node, Node), u32)>
where G::Timestamp: Lattice+Ord {

    goals.scope().scoped(|inner| {

        // Our plan is to start evolving distances from both sources and destinations.
        // The evolution from a source or destination should continue as long as there
        // is a corresponding destination or source that has not yet been reached.

        // forward and reverse (node, (root, dist))
        let forward = Variable::from(goals.map(|(x,_)| (x,(x,0))).enter(inner));
        let reverse = Variable::from(goals.map(|(_,y)| (y,(y,0))).enter(inner));

        let goals = goals.enter(inner);
        let forward_graph = forward_graph.enter(inner);
        let reverse_graph = reverse_graph.enter(inner);

        // Let's determine which (src, dst) pairs are ready to return.
        //
        //   done(src, dst) := forward(src, med), reverse(dst, med), goal(src, dst).
        //
        // This is a cyclic join, which should scare us a bunch.
        let reached =
        forward
            .join_map(&reverse, |_, &(src,d1), &(dst,d2)| ((src, dst), d1 + d2))
            .group(|_key, s, t| t.push((*s[0].0, 1)))
            .semijoin(&goals);

        let active =
        reached
            .negate()
            .map(|(srcdst,_)| srcdst)
            .concat(&goals)
            .consolidate();

        // Let's expand out forward queries that are active.
        let forward_active = active.map(|(x,_y)| x).distinct();
        let forward_next =
        forward
            .map(|(med, (src, dist))| (src, (med, dist)))
            .semijoin(&forward_active)
            .map(|(src, (med, dist))| (med, (src, dist)))
            .join_core(&forward_graph, |_med, &(src, dist), &next| Some((next, (src, dist+1))))
            // .join_map(&edges, |_med, &(src, dist), &next| (next, (src, dist+1)))
            .concat(&forward)
            .map(|(next, (src, dist))| ((next, src), dist))
            .group(|_key, s, t| t.push((*s[0].0, 1)))
            .map(|((next, src), dist)| (next, (src, dist)));

        forward.set(&forward_next);

        // Let's expand out reverse queries that are active.
        let reverse_active = active.map(|(_x,y)| y).distinct();
        let reverse_next =
        reverse
            .map(|(med, (rev, dist))| (rev, (med, dist)))
            .semijoin(&reverse_active)
            .map(|(rev, (med, dist))| (med, (rev, dist)))
            .join_core(&reverse_graph, |_med, &(rev, dist), &next| Some((next, (rev, dist+1))))
            // .join_map(&edges.map(|(x,y)| (y,x)), |_med, &(rev, dist), &next| (next, (rev, dist+1)))
            .concat(&reverse)
            .map(|(next, (rev, dist))| ((next, rev), dist))
            .group(|_key, s, t| t.push((*s[0].0, 1)))
            .map(|((next,rev), dist)| (next, (rev, dist)));

        reverse.set(&reverse_next);

        reached.leave()
    })
}<|endoftext|>