<commit_before>use super::{AddressNotFoundError, Decoder, InvalidDatabaseError, IoError,
            Reader};

use std::io::net::ip::IpAddr;
use std::from_str::FromStr;
use serialize::Decodable;

#[test]
fn test_decoder() {

    #[deriving(Decodable, Show, Eq)]
    struct MapXType {
        arrayX: ~[uint],
        utf8_stringX: StrBuf
    };

    #[deriving(Decodable, Show, Eq)]
    struct MapType {
        mapX: MapXType
    };

    #[deriving(Decodable, Show)]
    struct TestType {
        array:       ~[uint],
        boolean:     bool,
        bytes:       ~[u8],
        double:      f64,
        float:       f32,
        int32:       i32,
        map:         MapType,
        uint16:      u16,
        uint32:      u32,
        uint64:      u64,
        uint128:     ~[u8],
        utf8_string: StrBuf
    }

    let r = Reader::open("test-data/test-data/MaxMind-DB-test-decoder.mmdb").unwrap();
    let ip: IpAddr = FromStr::from_str("::1.1.1.0").unwrap();
    let raw_data = r.lookup(ip);

    let mut decoder = Decoder::new(raw_data.unwrap());
    let result: TestType = match Decodable::decode(&mut decoder) {
        Ok(v) => v,
        Err(e) => fail!("Decoding error: {}", e)
    };

    assert_eq!(result.array, ~[ 1u, 2u, 3u ]);
    assert_eq!(result.boolean, true);
    assert_eq!(result.bytes, ~[0u8, 0u8, 0u8, 42u8])
    assert_eq!(result.double, 42.123456);
    assert_eq!(result.float, 1.1);
    assert_eq!(result.int32, -268435456);

    assert_eq!(result.map, MapType{ mapX: MapXType{ arrayX: ~[7,8,9], utf8_stringX: "hello".to_strbuf()}});

    assert_eq!(result.uint16, 100);
    assert_eq!(result.uint32, 268435456);
    assert_eq!(result.uint64, 1152921504606846976);
    assert_eq!(result.uint128, ~[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);

    assert_eq!(result.utf8_string,  "unicode! ☯ - ♫".to_strbuf());
}

#[test]
fn test_broken_database() {
    let r = Reader::open("test-data/test-data/GeoIP2-City-Test-Broken-Double-Format.mmdb").unwrap();
    let ip: IpAddr = FromStr::from_str("2001:220::").unwrap();
    let result = r.lookup(ip);
    assert_eq!(result, Err(InvalidDatabaseError("double of size 2".to_strbuf())));
}

#[test]
fn test_missing_database() {
    let r = Reader::open("file-does-not-exist.mmdb");
    match r {
        Ok(_) => fail!("Received Reader when opening non-existent file"),
        Err(IoError(_)) => assert!(true),
        Err(_) => assert!(false)
    }
}

#[test]
fn test_non_database() {
    let r = Reader::open("README.md");
    match r {
        Ok(_) => fail!("Received Reader when opening a non-MMDB file"),
        Err(e) => assert_eq!(e, InvalidDatabaseError("Could not find MaxMind DB metadata in file.".to_strbuf()))

    }
}

#[test]
fn test_reader() {
    let sizes = [24u, 28, 32];
    for record_size in sizes.iter() {
        let versions = [4u, 6];
        for ip_version in versions.iter() {
            let filename = format!("test-data/test-data/MaxMind-DB-test-ipv{}-{}.mmdb",
                ip_version, record_size);
            let reader = Reader::open(filename).unwrap();

            check_metadata(&reader, *ip_version, *record_size);
            check_ip(&reader, *ip_version);
        }
    }
}

fn check_metadata(reader: &Reader, ip_version: uint, record_size: uint) {
    let metadata = &reader.metadata;

    assert_eq!(metadata.binary_format_major_version,  2u16)

    assert_eq!(metadata.binary_format_minor_version,  0u16)
    assert!(metadata.build_epoch >= 1397457605)
    assert_eq!(metadata.database_type, "Test".to_strbuf())

    assert_eq!(*metadata.description.find(&"en".to_strbuf()).unwrap(),
                   "Test Database".to_strbuf());
    assert_eq!(*metadata.description.find(&"zh".to_strbuf()).unwrap(),
                   "Test Database Chinese".to_strbuf());

    assert_eq!(metadata.ip_version,  ip_version as u16)
    assert_eq!(metadata.languages, ~["en".to_strbuf(), "zh".to_strbuf()])

    if ip_version == 4 {
        assert_eq!(metadata.node_count,  37)
    } else {
        assert_eq!(metadata.node_count,  160)
    }

    assert_eq!(metadata.record_size,  record_size as u16)
}

fn check_ip(reader: &Reader, ip_version: uint) {

    let subnets = match ip_version {
        6 =>   [["::1:ffff:ffff", "::1:ffff:ffff"],
                ["::2:0:0",  "::2:0:0"],
                ["::2:0:1",  "::2:0:0"],
                ["::2:0:33", "::2:0:0"],
                ["::2:0:39", "::2:0:0"],
                ["::2:0:40", "::2:0:40"],
                ["::2:0:41", "::2:0:40"],
                ["::2:0:49", "::2:0:40"],
                ["::2:0:50", "::2:0:50"],
                ["::2:0:52", "::2:0:50"],
                ["::2:0:57", "::2:0:50"],
                ["::2:0:58", "::2:0:58"],
                ["::2:0:59", "::2:0:58"]],
        _ =>   [["1.1.1.1", "1.1.1.1"],
                ["1.1.1.2", "1.1.1.2"],
                ["1.1.1.3", "1.1.1.2"],
                ["1.1.1.4", "1.1.1.4"],
                ["1.1.1.5",  "1.1.1.4"],
                ["1.1.1.6",  "1.1.1.4"],
                ["1.1.1.7",  "1.1.1.4"],
                ["1.1.1.8",  "1.1.1.8"],
                ["1.1.1.9",  "1.1.1.8"],
                ["1.1.1.15",  "1.1.1.8"],
                ["1.1.1.16",  "1.1.1.16"],
                ["1.1.1.17",  "1.1.1.16"],
                ["1.1.1.31",  "1.1.1.16"]]
    };

    #[deriving(Decodable, Show)]
    struct IpType  {
         ip: StrBuf,
    }

    for values in subnets.iter() {
        let ip: IpAddr = FromStr::from_str(values[0]).unwrap();
        let res = reader.lookup(ip).unwrap();

        let mut decoder = Decoder::new(res);
        let value: IpType =  match Decodable::decode(&mut decoder) {
            Ok(v) => v,
            Err(e) => fail!("Decoding error: {}", e)
        };
        assert_eq!(value.ip, values[1].to_strbuf());
    }

    let noRecord =  ["1.1.1.33", "255.254.253.123", "89fa::"];

    for &address in noRecord.iter() {
        let ip: IpAddr = FromStr::from_str(address).unwrap();
        match reader.lookup(ip) {
            Ok(v) => fail!("received an unexpected value: {}", v),
            Err(e) => assert_eq!(e, AddressNotFoundError("Address not found in database".to_strbuf()))
        }
    }
}
<commit_msg>Fix for more recent str/StrBuf changes<commit_after>use super::{AddressNotFoundError, Decoder, InvalidDatabaseError, IoError,
            Reader};

use std::io::net::ip::IpAddr;
use std::from_str::FromStr;
use serialize::Decodable;

#[test]
fn test_decoder() {

    #[deriving(Decodable, Show, Eq)]
    struct MapXType {
        arrayX: ~[uint],
        utf8_stringX: StrBuf
    };

    #[deriving(Decodable, Show, Eq)]
    struct MapType {
        mapX: MapXType
    };

    #[deriving(Decodable, Show)]
    struct TestType {
        array:       ~[uint],
        boolean:     bool,
        bytes:       ~[u8],
        double:      f64,
        float:       f32,
        int32:       i32,
        map:         MapType,
        uint16:      u16,
        uint32:      u32,
        uint64:      u64,
        uint128:     ~[u8],
        utf8_string: StrBuf
    }

    let r = Reader::open("test-data/test-data/MaxMind-DB-test-decoder.mmdb").unwrap();
    let ip: IpAddr = FromStr::from_str("::1.1.1.0").unwrap();
    let raw_data = r.lookup(ip);

    let mut decoder = Decoder::new(raw_data.unwrap());
    let result: TestType = match Decodable::decode(&mut decoder) {
        Ok(v) => v,
        Err(e) => fail!("Decoding error: {}", e)
    };

    assert_eq!(result.array, ~[ 1u, 2u, 3u ]);
    assert_eq!(result.boolean, true);
    assert_eq!(result.bytes, ~[0u8, 0u8, 0u8, 42u8])
    assert_eq!(result.double, 42.123456);
    assert_eq!(result.float, 1.1);
    assert_eq!(result.int32, -268435456);

    assert_eq!(result.map, MapType{ mapX: MapXType{ arrayX: ~[7,8,9], utf8_stringX: "hello".to_strbuf()}});

    assert_eq!(result.uint16, 100);
    assert_eq!(result.uint32, 268435456);
    assert_eq!(result.uint64, 1152921504606846976);
    assert_eq!(result.uint128, ~[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);

    assert_eq!(result.utf8_string,  "unicode! ☯ - ♫".to_strbuf());
}

#[test]
fn test_broken_database() {
    let r = Reader::open("test-data/test-data/GeoIP2-City-Test-Broken-Double-Format.mmdb").unwrap();
    let ip: IpAddr = FromStr::from_str("2001:220::").unwrap();
    let result = r.lookup(ip);
    assert_eq!(result, Err(InvalidDatabaseError("double of size 2".to_strbuf())));
}

#[test]
fn test_missing_database() {
    let r = Reader::open("file-does-not-exist.mmdb");
    match r {
        Ok(_) => fail!("Received Reader when opening non-existent file"),
        Err(IoError(_)) => assert!(true),
        Err(_) => assert!(false)
    }
}

#[test]
fn test_non_database() {
    let r = Reader::open("README.md");
    match r {
        Ok(_) => fail!("Received Reader when opening a non-MMDB file"),
        Err(e) => assert_eq!(e, InvalidDatabaseError("Could not find MaxMind DB metadata in file.".to_strbuf()))

    }
}

#[test]
fn test_reader() {
    let sizes = [24u, 28, 32];
    for record_size in sizes.iter() {
        let versions = [4u, 6];
        for ip_version in versions.iter() {
            let filename = format!("test-data/test-data/MaxMind-DB-test-ipv{}-{}.mmdb",
                ip_version, record_size);
            let reader = Reader::open(filename.as_slice()).unwrap();

            check_metadata(&reader, *ip_version, *record_size);
            check_ip(&reader, *ip_version);
        }
    }
}

fn check_metadata(reader: &Reader, ip_version: uint, record_size: uint) {
    let metadata = &reader.metadata;

    assert_eq!(metadata.binary_format_major_version,  2u16)

    assert_eq!(metadata.binary_format_minor_version,  0u16)
    assert!(metadata.build_epoch >= 1397457605)
    assert_eq!(metadata.database_type, "Test".to_strbuf())

    assert_eq!(*metadata.description.find(&"en".to_strbuf()).unwrap(),
                   "Test Database".to_strbuf());
    assert_eq!(*metadata.description.find(&"zh".to_strbuf()).unwrap(),
                   "Test Database Chinese".to_strbuf());

    assert_eq!(metadata.ip_version,  ip_version as u16)
    assert_eq!(metadata.languages, ~["en".to_strbuf(), "zh".to_strbuf()])

    if ip_version == 4 {
        assert_eq!(metadata.node_count,  37)
    } else {
        assert_eq!(metadata.node_count,  160)
    }

    assert_eq!(metadata.record_size,  record_size as u16)
}

fn check_ip(reader: &Reader, ip_version: uint) {

    let subnets = match ip_version {
        6 =>   [["::1:ffff:ffff", "::1:ffff:ffff"],
                ["::2:0:0",  "::2:0:0"],
                ["::2:0:1",  "::2:0:0"],
                ["::2:0:33", "::2:0:0"],
                ["::2:0:39", "::2:0:0"],
                ["::2:0:40", "::2:0:40"],
                ["::2:0:41", "::2:0:40"],
                ["::2:0:49", "::2:0:40"],
                ["::2:0:50", "::2:0:50"],
                ["::2:0:52", "::2:0:50"],
                ["::2:0:57", "::2:0:50"],
                ["::2:0:58", "::2:0:58"],
                ["::2:0:59", "::2:0:58"]],
        _ =>   [["1.1.1.1", "1.1.1.1"],
                ["1.1.1.2", "1.1.1.2"],
                ["1.1.1.3", "1.1.1.2"],
                ["1.1.1.4", "1.1.1.4"],
                ["1.1.1.5",  "1.1.1.4"],
                ["1.1.1.6",  "1.1.1.4"],
                ["1.1.1.7",  "1.1.1.4"],
                ["1.1.1.8",  "1.1.1.8"],
                ["1.1.1.9",  "1.1.1.8"],
                ["1.1.1.15",  "1.1.1.8"],
                ["1.1.1.16",  "1.1.1.16"],
                ["1.1.1.17",  "1.1.1.16"],
                ["1.1.1.31",  "1.1.1.16"]]
    };

    #[deriving(Decodable, Show)]
    struct IpType  {
         ip: StrBuf,
    }

    for values in subnets.iter() {
        let ip: IpAddr = FromStr::from_str(values[0]).unwrap();
        let res = reader.lookup(ip).unwrap();

        let mut decoder = Decoder::new(res);
        let value: IpType =  match Decodable::decode(&mut decoder) {
            Ok(v) => v,
            Err(e) => fail!("Decoding error: {}", e)
        };
        assert_eq!(value.ip, values[1].to_strbuf());
    }

    let noRecord =  ["1.1.1.33", "255.254.253.123", "89fa::"];

    for &address in noRecord.iter() {
        let ip: IpAddr = FromStr::from_str(address).unwrap();
        match reader.lookup(ip) {
            Ok(v) => fail!("received an unexpected value: {}", v),
            Err(e) => assert_eq!(e, AddressNotFoundError("Address not found in database".to_strbuf()))
        }
    }
}
<|endoftext|>


<commit_before>use internal::prelude::*;
use serde::de::{
    self,
    Deserialize,
    Deserializer,
    MapAccess,
    Visitor
};
use serde::ser::Serializer;
use super::super::prelude::*;
use std::{
    collections::HashMap,
    mem::transmute,
    fmt
};

/// Determines to what entity an action was used on.
#[derive(Debug)]
#[repr(u8)]
pub enum Target {
    Guild = 10,
    Channel = 20,
    User = 30,
    Role = 40,
    Invite = 50,
    Webhook = 60,
    Emoji = 70,
}

/// Determines the action that was done on a target.
#[derive(Debug)]
pub enum Action {
    GuildUpdate,
    Channel(ActionChannel),
    ChannelOverwrite(ActionChannelOverwrite),
    Member(ActionMember),
    Role(ActionRole),
    Invite(ActionInvite),
    Webhook(ActionWebhook),
    Emoji(ActionEmoji),
    MessageDelete,
}

impl Action {
    pub fn num(&self) -> u8 {
        use self::Action::*;

        match *self {
            GuildUpdate => 1,
            Action::Channel(ref x) => x.num(),
            Action::ChannelOverwrite(ref x) => x.num(),
            Action::Member(ref x) => x.num(),
            Action::Role(ref x) => x.num(),
            Action::Invite(ref x) => x.num(),
            Action::Webhook(ref x) => x.num(),
            Action::Emoji(ref x) => x.num(),
            Action::MessageDelete => 72,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionChannel {
    Create = 10,
    Update = 11,
    Delete = 12,
}

impl ActionChannel {
    pub fn num(&self) -> u8 {
        match *self {
            ActionChannel::Create => 10,
            ActionChannel::Update => 11,
            ActionChannel::Delete => 12,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionChannelOverwrite {
    Create = 13,
    Update = 14,
    Delete = 15,
}

impl ActionChannelOverwrite {
    pub fn num(&self) -> u8 {
        match *self {
            ActionChannelOverwrite::Create => 13,
            ActionChannelOverwrite::Update => 14,
            ActionChannelOverwrite::Delete => 15,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionMember {
    Kick = 20,
    Prune = 21,
    BanAdd = 22,
    BanRemove = 23,
    Update = 24,
    RoleUpdate = 25,
}

impl ActionMember {
    pub fn num(&self) -> u8 {
        match *self {
            ActionMember::Kick => 20,
            ActionMember::Prune => 21,
            ActionMember::BanAdd => 22,
            ActionMember::BanRemove => 23,
            ActionMember::Update => 24,
            ActionMember::RoleUpdate => 25,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionRole {
    Create = 30,
    Update = 31,
    Delete = 32,
}

impl ActionRole {
    pub fn num(&self) -> u8 {
        match *self {
            ActionRole::Create => 30,
            ActionRole::Update => 31,
            ActionRole::Delete => 32,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionInvite {
    Create = 40,
    Update = 41,
    Delete = 42,
}

impl ActionInvite {
    pub fn num(&self) -> u8 {
        match *self {
            ActionInvite::Create => 40,
            ActionInvite::Update => 41,
            ActionInvite::Delete => 42,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionWebhook {
    Create = 50,
    Update = 51,
    Delete = 52,
}

impl ActionWebhook {
    pub fn num(&self) -> u8 {
        match *self {
            ActionWebhook::Create => 50,
            ActionWebhook::Update => 51,
            ActionWebhook::Delete => 52,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionEmoji {
    Create = 60,
    Delete = 61,
    Update = 62,
}

impl ActionEmoji {
    pub fn num(&self) -> u8 {
        match *self {
            ActionEmoji::Create => 60,
            ActionEmoji::Update => 61,
            ActionEmoji::Delete => 62,
        }
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Change {
    #[serde(rename = "key")] pub name: String,
    // TODO: Change these to an actual type.
    #[serde(rename = "old_value")] pub old: String,
    #[serde(rename = "new_value")] pub new: String,
}

#[derive(Debug)]
pub struct AuditLogs {
    pub entries: HashMap<AuditLogEntryId, AuditLogEntry>,
    pub webhooks: Vec<Webhook>,
    pub users: Vec<User>,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct AuditLogEntry {
    /// Determines to what entity an [`action`] was used on.
    ///
    /// [`action`]: #structfield.action
    #[serde(with = "u64_handler")]
    pub target_id: u64,
    /// Determines what action was done on a [`target`]
    ///
    /// [`target`]: #structfield.target
    #[serde(
        with = "action_handler",
        rename = "action_type"
    )]
    pub action: Action,
    /// What was the reasoning by doing an action on a target? If there was one.
    pub reason: Option<String>,
    /// The user that did this action on a target.
    pub user_id: UserId,
    /// What changes were made.
    pub changes: Option<Vec<Change>>,
    /// The id of this entry.
    pub id: AuditLogEntryId,
    /// Some optional data assosiated with this entry.
    pub options: Option<Options>,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Options {
    /// Number of days after which inactive members were kicked.
    #[serde(with = "u64_handler")]
    pub delete_member_days: u64,
    /// Number of members removed by the prune
    #[serde(with = "u64_handler")]
    pub members_removed: u64,
    /// Channel in which the messages were deleted
    pub channel_id: ChannelId,
    /// Number of deleted messages.
    #[serde(with = "u64_handler")]
    pub count: u64,
    /// Id of the overwritten entity
    pub id: u64,
    /// Type of overwritten entity ("member" or "role").
    #[serde(rename = "type")] pub kind: String,
    /// Name of the role if type is "role"
    pub role_name: String,
}

mod u64_handler {
    use super::*;

    pub fn deserialize<'de, D: Deserializer<'de>>(des: D) -> StdResult<u64, D::Error> {
        struct U64Visitor;

        impl<'de> Visitor<'de> for U64Visitor {
            type Value = u64;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("an integer or a string with a valid number inside")
            }

            // NOTE: Serde internally delegates number types below `u64` to it.
            fn visit_u64<E: de::Error>(self, val: u64) -> StdResult<u64, E> {
                Ok(val)
            }

            fn visit_str<E: de::Error>(self, string: &str) -> StdResult<u64, E> {
                string.parse().map_err(|e| de::Error::custom(e))
            }
        }

        des.deserialize_any(U64Visitor)
    }

    pub fn serialize<S: Serializer>(num: &u64, s: S) -> StdResult<S::Ok, S::Error> {
        s.serialize_u64(*num)
    }
}

mod action_handler {
    use super::*;

    pub fn deserialize<'de, D: Deserializer<'de>>(de: D) -> StdResult<Action, D::Error> {
        struct ActionVisitor;

        impl<'de> Visitor<'de> for ActionVisitor {
            type Value = Action;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("an integer between 1 to 72")
            }

            // NOTE: Serde internally delegates number types below `u64` to it.
            fn visit_u64<E: de::Error>(self, value: u64) -> StdResult<Action, E> {
                let value = value as u8;

                Ok(match value {
                    1 => Action::GuildUpdate,
                    10...12 => Action::Channel(unsafe { transmute(value) }),
                    13...15 => Action::ChannelOverwrite(unsafe { transmute(value) }),
                    20...25 => Action::Member(unsafe { transmute(value) }),
                    30...32 => Action::Role(unsafe { transmute(value) }),
                    40...42 => Action::Invite(unsafe { transmute(value) }),
                    50...52 => Action::Webhook(unsafe { transmute(value) }),
                    60...62 => Action::Emoji(unsafe { transmute(value) }),
                    72 => Action::MessageDelete,
                    _ => return Err(E::custom(format!("Unexpected action number: {}", value))),
                })
            }
        }

        de.deserialize_any(ActionVisitor)
    }

    pub fn serialize<S: Serializer>(
        action: &Action,
        serializer: S,
    ) -> StdResult<S::Ok, S::Error> {
        serializer.serialize_u8(action.num())
    }
}
impl<'de> Deserialize<'de> for AuditLogs {
    fn deserialize<D: Deserializer<'de>>(de: D) -> StdResult<Self, D::Error> {
        #[derive(Deserialize)]
        #[serde(field_identifier)]
        enum Field {
            #[serde(rename = "audit_log_entries")] Entries,
            #[serde(rename = "webhooks")] Webhooks,
            #[serde(rename = "users")] Users,
        }

        struct EntriesVisitor;

        impl<'de> Visitor<'de> for EntriesVisitor {
            type Value = AuditLogs;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("audit log entries")
            }

            fn visit_map<V: MapAccess<'de>>(self, mut map: V) -> StdResult<AuditLogs, V::Error> {
                let mut audit_log_entries = None;
                let mut users = None;
                let mut webhooks = None;

                while let Some(field) = map.next_key()? {
                    match field {
                        Field::Entries => {
                            if audit_log_entries.is_some() {
                                return Err(de::Error::duplicate_field("entries"));
                            }

                            audit_log_entries = Some(map.next_value::<Vec<AuditLogEntry>>()?);
                        },
                        Field::Webhooks => {
                            if webhooks.is_some() {
                                return Err(de::Error::duplicate_field("webhooks"));
                            }

                            webhooks = Some(map.next_value::<Vec<Webhook>>()?);
                        },
                        Field::Users => {
                            if users.is_some() {
                                return Err(de::Error::duplicate_field("users"));
                            }

                            users = Some(map.next_value::<Vec<User>>()?);
                        },
                    }
                }

                Ok(AuditLogs {
                    entries: audit_log_entries
                        .unwrap()
                        .into_iter()
                        .map(|entry| (entry.id, entry))
                        .collect(),
                    webhooks: webhooks.unwrap(),
                    users: users.unwrap(),
                })
            }
        }

        const FIELD: &[&str] = &["audit_log_entries"];
        de.deserialize_struct("AuditLogs", FIELD, EntriesVisitor)
    }
}
<commit_msg>make `Options`'s fields optional (#305)<commit_after>use internal::prelude::*;
use serde::de::{
    self,
    Deserialize,
    Deserializer,
    MapAccess,
    Visitor
};
use serde::ser::{
    Serialize,
    Serializer
};
use super::super::prelude::*;
use std::{
    collections::HashMap,
    mem::transmute,
    fmt
};

/// Determines to what entity an action was used on.
#[derive(Debug)]
#[repr(u8)]
pub enum Target {
    Guild = 10,
    Channel = 20,
    User = 30,
    Role = 40,
    Invite = 50,
    Webhook = 60,
    Emoji = 70,
}

/// Determines the action that was done on a target.
#[derive(Debug)]
pub enum Action {
    GuildUpdate,
    Channel(ActionChannel),
    ChannelOverwrite(ActionChannelOverwrite),
    Member(ActionMember),
    Role(ActionRole),
    Invite(ActionInvite),
    Webhook(ActionWebhook),
    Emoji(ActionEmoji),
    MessageDelete,
}

impl Action {
    pub fn num(&self) -> u8 {
        use self::Action::*;

        match *self {
            GuildUpdate => 1,
            Action::Channel(ref x) => x.num(),
            Action::ChannelOverwrite(ref x) => x.num(),
            Action::Member(ref x) => x.num(),
            Action::Role(ref x) => x.num(),
            Action::Invite(ref x) => x.num(),
            Action::Webhook(ref x) => x.num(),
            Action::Emoji(ref x) => x.num(),
            Action::MessageDelete => 72,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionChannel {
    Create = 10,
    Update = 11,
    Delete = 12,
}

impl ActionChannel {
    pub fn num(&self) -> u8 {
        match *self {
            ActionChannel::Create => 10,
            ActionChannel::Update => 11,
            ActionChannel::Delete => 12,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionChannelOverwrite {
    Create = 13,
    Update = 14,
    Delete = 15,
}

impl ActionChannelOverwrite {
    pub fn num(&self) -> u8 {
        match *self {
            ActionChannelOverwrite::Create => 13,
            ActionChannelOverwrite::Update => 14,
            ActionChannelOverwrite::Delete => 15,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionMember {
    Kick = 20,
    Prune = 21,
    BanAdd = 22,
    BanRemove = 23,
    Update = 24,
    RoleUpdate = 25,
}

impl ActionMember {
    pub fn num(&self) -> u8 {
        match *self {
            ActionMember::Kick => 20,
            ActionMember::Prune => 21,
            ActionMember::BanAdd => 22,
            ActionMember::BanRemove => 23,
            ActionMember::Update => 24,
            ActionMember::RoleUpdate => 25,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionRole {
    Create = 30,
    Update = 31,
    Delete = 32,
}

impl ActionRole {
    pub fn num(&self) -> u8 {
        match *self {
            ActionRole::Create => 30,
            ActionRole::Update => 31,
            ActionRole::Delete => 32,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionInvite {
    Create = 40,
    Update = 41,
    Delete = 42,
}

impl ActionInvite {
    pub fn num(&self) -> u8 {
        match *self {
            ActionInvite::Create => 40,
            ActionInvite::Update => 41,
            ActionInvite::Delete => 42,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionWebhook {
    Create = 50,
    Update = 51,
    Delete = 52,
}

impl ActionWebhook {
    pub fn num(&self) -> u8 {
        match *self {
            ActionWebhook::Create => 50,
            ActionWebhook::Update => 51,
            ActionWebhook::Delete => 52,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionEmoji {
    Create = 60,
    Delete = 61,
    Update = 62,
}

impl ActionEmoji {
    pub fn num(&self) -> u8 {
        match *self {
            ActionEmoji::Create => 60,
            ActionEmoji::Update => 61,
            ActionEmoji::Delete => 62,
        }
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Change {
    #[serde(rename = "key")] pub name: String,
    // TODO: Change these to an actual type.
    #[serde(rename = "old_value")] pub old: String,
    #[serde(rename = "new_value")] pub new: String,
}

#[derive(Debug)]
pub struct AuditLogs {
    pub entries: HashMap<AuditLogEntryId, AuditLogEntry>,
    pub webhooks: Vec<Webhook>,
    pub users: Vec<User>,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct AuditLogEntry {
    /// Determines to what entity an [`action`] was used on.
    ///
    /// [`action`]: #structfield.action
    #[serde(with = "u64_handler")]
    pub target_id: u64,
    /// Determines what action was done on a [`target`]
    ///
    /// [`target`]: #structfield.target
    #[serde(
        with = "action_handler",
        rename = "action_type"
    )]
    pub action: Action,
    /// What was the reasoning by doing an action on a target? If there was one.
    pub reason: Option<String>,
    /// The user that did this action on a target.
    pub user_id: UserId,
    /// What changes were made.
    pub changes: Option<Vec<Change>>,
    /// The id of this entry.
    pub id: AuditLogEntryId,
    /// Some optional data assosiated with this entry.
    pub options: Option<Options>,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Options {
    /// Number of days after which inactive members were kicked.
    #[serde(default, with = "option_u64_handler")]
    pub delete_member_days: Option<u64>,
    /// Number of members removed by the prune
    #[serde(default, with = "option_u64_handler")]
    pub members_removed: Option<u64>,
    /// Channel in which the messages were deleted
    #[serde(default)]
    pub channel_id: Option<ChannelId>,
    /// Number of deleted messages.
    #[serde(default, with = "option_u64_handler")]
    pub count: Option<u64>,
    /// Id of the overwritten entity
    #[serde(default, with = "option_u64_handler")]
    pub id: Option<u64>,
    /// Type of overwritten entity ("member" or "role").
    #[serde(default, rename = "type")]
    pub kind: Option<String>,
    /// Name of the role if type is "role"
    #[serde(default)]
    pub role_name: Option<String>,
}

mod u64_handler {
    use super::*;

    pub fn deserialize<'de, D: Deserializer<'de>>(des: D) -> StdResult<u64, D::Error> {
        struct U64Visitor;

        impl<'de> Visitor<'de> for U64Visitor {
            type Value = u64;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("an integer or a string with a valid number inside")
            }

            // NOTE: Serde internally delegates number types below `u64` to it.
            fn visit_u64<E: de::Error>(self, val: u64) -> StdResult<u64, E> {
                Ok(val)
            }

            fn visit_str<E: de::Error>(self, string: &str) -> StdResult<u64, E> {
                string.parse().map_err(|e| de::Error::custom(e))
            }
        }

        des.deserialize_any(U64Visitor)
    }

    pub fn serialize<S: Serializer>(num: &u64, s: S) -> StdResult<S::Ok, S::Error> {
        s.serialize_u64(*num)
    }
}

mod option_u64_handler {
    use super::*;

    pub fn deserialize<'de, D: Deserializer<'de>>(des: D) -> StdResult<Option<u64>, D::Error> {
        struct OptionU64Visitor;

        impl<'de> Visitor<'de> for OptionU64Visitor {
            type Value = Option<u64>;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("an optional integer or a string with a valid number inside")
            }

            fn visit_some<D: Deserializer<'de>>(self, deserializer: D) -> StdResult<Self::Value, D::Error> {
                deserializer.deserialize_any(OptionU64Visitor)
            }

            fn visit_none<E: de::Error>(self) -> StdResult<Self::Value, E> {
                Ok(None)
            }

            fn visit_u64<E: de::Error>(self, val: u64) -> StdResult<Option<u64>, E> {
                Ok(Some(val))
            }

            fn visit_str<E: de::Error>(self, string: &str) -> StdResult<Option<u64>, E> {
                string.parse().map(Some).map_err(|e| de::Error::custom(e))
            }
        }

        des.deserialize_option(OptionU64Visitor)
    }

    pub fn serialize<S: Serializer>(num: &Option<u64>, s: S) -> StdResult<S::Ok, S::Error> {
        Option::serialize(num, s)
    }
}

mod action_handler {
    use super::*;

    pub fn deserialize<'de, D: Deserializer<'de>>(de: D) -> StdResult<Action, D::Error> {
        struct ActionVisitor;

        impl<'de> Visitor<'de> for ActionVisitor {
            type Value = Action;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("an integer between 1 to 72")
            }

            // NOTE: Serde internally delegates number types below `u64` to it.
            fn visit_u64<E: de::Error>(self, value: u64) -> StdResult<Action, E> {
                let value = value as u8;

                Ok(match value {
                    1 => Action::GuildUpdate,
                    10...12 => Action::Channel(unsafe { transmute(value) }),
                    13...15 => Action::ChannelOverwrite(unsafe { transmute(value) }),
                    20...25 => Action::Member(unsafe { transmute(value) }),
                    30...32 => Action::Role(unsafe { transmute(value) }),
                    40...42 => Action::Invite(unsafe { transmute(value) }),
                    50...52 => Action::Webhook(unsafe { transmute(value) }),
                    60...62 => Action::Emoji(unsafe { transmute(value) }),
                    72 => Action::MessageDelete,
                    _ => return Err(E::custom(format!("Unexpected action number: {}", value))),
                })
            }
        }

        de.deserialize_any(ActionVisitor)
    }

    pub fn serialize<S: Serializer>(
        action: &Action,
        serializer: S,
    ) -> StdResult<S::Ok, S::Error> {
        serializer.serialize_u8(action.num())
    }
}
impl<'de> Deserialize<'de> for AuditLogs {
    fn deserialize<D: Deserializer<'de>>(de: D) -> StdResult<Self, D::Error> {
        #[derive(Deserialize)]
        #[serde(field_identifier)]
        enum Field {
            #[serde(rename = "audit_log_entries")] Entries,
            #[serde(rename = "webhooks")] Webhooks,
            #[serde(rename = "users")] Users,
        }

        struct EntriesVisitor;

        impl<'de> Visitor<'de> for EntriesVisitor {
            type Value = AuditLogs;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("audit log entries")
            }

            fn visit_map<V: MapAccess<'de>>(self, mut map: V) -> StdResult<AuditLogs, V::Error> {
                let mut audit_log_entries = None;
                let mut users = None;
                let mut webhooks = None;

                while let Some(field) = map.next_key()? {
                    match field {
                        Field::Entries => {
                            if audit_log_entries.is_some() {
                                return Err(de::Error::duplicate_field("entries"));
                            }

                            audit_log_entries = Some(map.next_value::<Vec<AuditLogEntry>>()?);
                        },
                        Field::Webhooks => {
                            if webhooks.is_some() {
                                return Err(de::Error::duplicate_field("webhooks"));
                            }

                            webhooks = Some(map.next_value::<Vec<Webhook>>()?);
                        },
                        Field::Users => {
                            if users.is_some() {
                                return Err(de::Error::duplicate_field("users"));
                            }

                            users = Some(map.next_value::<Vec<User>>()?);
                        },
                    }
                }

                Ok(AuditLogs {
                    entries: audit_log_entries
                        .unwrap()
                        .into_iter()
                        .map(|entry| (entry.id, entry))
                        .collect(),
                    webhooks: webhooks.unwrap(),
                    users: users.unwrap(),
                })
            }
        }

        const FIELD: &[&str] = &["audit_log_entries"];
        de.deserialize_struct("AuditLogs", FIELD, EntriesVisitor)
    }
}
<|endoftext|>


<commit_before>use crate::prolog::machine::and_stack::*;
use crate::prolog::machine::machine_indices::*;

use std::ops::IndexMut;

type Trail = Vec<(Ref, HeapCellValue)>;

#[derive(Clone, Copy)]
pub enum AttrVarPolicy {
    DeepCopy,
    StripAttributes
}

pub(crate) trait CopierTarget: IndexMut<usize, Output = HeapCellValue> {
    fn threshold(&self) -> usize;
    fn push(&mut self, _: HeapCellValue);
    fn store(&self, _: Addr) -> Addr;
    fn deref(&self, _: Addr) -> Addr;
    fn stack(&mut self) -> &mut AndStack;
}

pub(crate)
fn copy_term<T: CopierTarget>(target: T, addr: Addr, attr_var_policy: AttrVarPolicy) {
    let mut copy_term_state = CopyTermState::new(target, attr_var_policy);
    copy_term_state.copy_term_impl(addr);
}

struct CopyTermState<T: CopierTarget> {
    trail: Trail,
    scan: usize,
    old_h: usize,
    target: T,
    attr_var_policy: AttrVarPolicy
}

impl<T: CopierTarget> CopyTermState<T> {
    fn new(target: T, attr_var_policy: AttrVarPolicy) -> Self {
        CopyTermState {
            trail: vec![],
            scan: 0,
            old_h: target.threshold(),
            target,
            attr_var_policy
        }
    }

    #[inline]
    fn value_at_scan(&mut self) -> &mut HeapCellValue {
        let scan = self.scan;
        &mut self.target[scan]
    }

    fn copied_list(&mut self, addr: usize) -> bool {
        if let HeapCellValue::Addr(Addr::Lis(addr)) = self.target[addr].clone() {
            if addr >= self.old_h {
                *self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(addr));
                self.scan += 1;
                return true;
            }
        }

        false
    }

    fn copy_list(&mut self, addr: usize) {
        if self.copied_list(addr) {
            return;
        }

        let threshold = self.target.threshold();
        *self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(threshold));

        let hcv = self.target[addr].clone();
        self.target.push(hcv);

        let hcv = self.target[addr + 1].clone();
        self.target.push(hcv);

        self.trail.push((Ref::HeapCell(addr), self.target[addr].clone()));
        self.target[addr] = HeapCellValue::Addr(Addr::Lis(threshold));

        self.scan += 1;
    }

    fn reinstantiate_var(&mut self, addr: Addr, frontier: usize) {
        match addr {
            Addr::HeapCell(h) => {
                self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(frontier));
                self.target[h] = HeapCellValue::Addr(Addr::HeapCell(frontier));
                self.trail.push((
                    Ref::HeapCell(h),
                    HeapCellValue::Addr(Addr::HeapCell(h)),
                ));
            }
            Addr::StackCell(fr, sc) => {
                self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(frontier));
                self.target.stack()[fr][sc] = Addr::HeapCell(frontier);
                self.trail.push((
                    Ref::StackCell(fr, sc),
                    HeapCellValue::Addr(Addr::StackCell(fr, sc)),
                ));
            }
            Addr::AttrVar(h) => {
                let threshold = if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
                    self.target.threshold()
                } else {
                    frontier
                };

                self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(threshold));
                self.target[h] = HeapCellValue::Addr(Addr::HeapCell(threshold));
                self.trail.push((
                    Ref::AttrVar(h),
                    HeapCellValue::Addr(Addr::AttrVar(h)),
                ));

                if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
                    self.target.push(HeapCellValue::Addr(Addr::AttrVar(threshold)));

                    let list_val = self.target[h + 1].clone();
                    self.target.push(list_val);
                }
            }
            _ => unreachable!()
        }
    }

    fn copy_var(&mut self, addr: Addr) {
        let rd = self.target.store(self.target.deref(addr.clone()));

        match rd.clone() {
            Addr::AttrVar(h) | Addr::HeapCell(h) if h >= self.old_h => {
                *self.value_at_scan() = HeapCellValue::Addr(rd);
                self.scan += 1;
            }
            _ if addr == rd => {
                self.reinstantiate_var(addr, self.scan);
                self.scan += 1;
            }
            _ => {
                *self.value_at_scan() = HeapCellValue::Addr(rd);
            }
        }
    }

    fn copy_structure(&mut self, addr: usize) {
        match self.target[addr].clone() {
            HeapCellValue::NamedStr(arity, name, fixity) => {
                let threshold = self.target.threshold();

                *self.value_at_scan() = HeapCellValue::Addr(Addr::Str(threshold));
                self.target[addr] = HeapCellValue::Addr(Addr::Str(threshold));

                self.trail.push((
                    Ref::HeapCell(addr),
                    HeapCellValue::NamedStr(arity, name.clone(), fixity.clone()),
                ));

                self.target.push(HeapCellValue::NamedStr(arity, name, fixity));

                for i in 0..arity {
                    let hcv = self.target[addr + 1 + i].clone();
                    self.target.push(hcv);
                }
            }
            HeapCellValue::Addr(Addr::Str(addr)) => {
                *self.value_at_scan() = HeapCellValue::Addr(Addr::Str(addr))
            }
            _ => {}
        }

        self.scan += 1;
    }

    fn copy_term_impl(&mut self, addr: Addr) {
        self.scan = self.target.threshold();
        self.target.push(HeapCellValue::Addr(addr));

        while self.scan < self.target.threshold() {
            match self.value_at_scan().clone() {
                HeapCellValue::NamedStr(..) => self.scan += 1,
                HeapCellValue::Addr(addr) => match addr {
                    Addr::Lis(addr) => self.copy_list(addr),
                    addr @ Addr::AttrVar(_)
                  | addr @ Addr::HeapCell(_)
                  | addr @ Addr::StackCell(..) => self.copy_var(addr),
                    Addr::Str(addr) => self.copy_structure(addr),
                    Addr::Con(_) | Addr::DBRef(_) => self.scan += 1,
                },
            }
        }

        self.unwind_trail();
    }

    fn unwind_trail(&mut self) {
        for (r, value) in self.trail.drain(0..) {
            match r {
                Ref::AttrVar(h) | Ref::HeapCell(h) => self.target[h] = value,
                Ref::StackCell(fr, sc) => self.target.stack()[fr][sc] = value.as_addr(0),
            }
        }
    }
}
<commit_msg>correct copying of cyclic lists in copier.rs<commit_after>use crate::prolog::machine::and_stack::*;
use crate::prolog::machine::machine_indices::*;

use std::ops::IndexMut;

type Trail = Vec<(Ref, HeapCellValue)>;

#[derive(Clone, Copy)]
pub enum AttrVarPolicy {
    DeepCopy,
    StripAttributes
}

pub(crate) trait CopierTarget: IndexMut<usize, Output = HeapCellValue> {
    fn threshold(&self) -> usize;
    fn push(&mut self, _: HeapCellValue);
    fn store(&self, _: Addr) -> Addr;
    fn deref(&self, _: Addr) -> Addr;
    fn stack(&mut self) -> &mut AndStack;
}

pub(crate)
fn copy_term<T: CopierTarget>(target: T, addr: Addr, attr_var_policy: AttrVarPolicy) {
    let mut copy_term_state = CopyTermState::new(target, attr_var_policy);
    copy_term_state.copy_term_impl(addr);
}

struct CopyTermState<T: CopierTarget> {
    trail: Trail,
    scan: usize,
    old_h: usize,
    target: T,
    attr_var_policy: AttrVarPolicy
}

impl<T: CopierTarget> CopyTermState<T> {
    fn new(target: T, attr_var_policy: AttrVarPolicy) -> Self {
        CopyTermState {
            trail: vec![],
            scan: 0,
            old_h: target.threshold(),
            target,
            attr_var_policy
        }
    }

    #[inline]
    fn value_at_scan(&mut self) -> &mut HeapCellValue {
        let scan = self.scan;
        &mut self.target[scan]
    }

    fn copied_list(&mut self, addr: usize) -> bool {
        match self.target[addr].clone() {
            HeapCellValue::Addr(Addr::Lis(addr)) | HeapCellValue::Addr(Addr::HeapCell(addr)) => {
                if addr >= self.old_h {
                    *self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(addr));
                    self.scan += 1;
                    return true;
                }
            }
            _ => {}
        };

        false
    }

    fn copy_list(&mut self, addr: usize) {
        if self.copied_list(addr) {
            return;
        }

        let threshold = self.target.threshold();
        *self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(threshold));

        let hcv = self.target[addr].clone();

        let ra = hcv.as_addr(threshold);
        let rd = self.target.store(self.target.deref(ra));

        self.target.push(hcv);

        let hcv = self.target[addr + 1].clone();
        self.target.push(hcv);

        match rd.clone() {
            Addr::AttrVar(h) | Addr::HeapCell(h) if h >= self.old_h => {
                self.target[threshold] = HeapCellValue::Addr(rd)
            }
            ra @ Addr::AttrVar(_) | ra @ Addr::HeapCell(..) | ra @ Addr::StackCell(..) => {
                if ra == rd {
                    self.reinstantiate_var(ra, threshold);
                } else {
                    self.target[threshold] = HeapCellValue::Addr(ra);
                }
            }
            _ => {
                self.trail.push((Ref::HeapCell(addr), self.target[addr].clone()));
                self.target[addr] = HeapCellValue::Addr(Addr::Lis(threshold))
            }
        };

        self.scan += 1;
    }

    fn reinstantiate_var(&mut self, addr: Addr, frontier: usize) {
        match addr {
            Addr::HeapCell(h) => {
                self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(frontier));
                self.target[h] = HeapCellValue::Addr(Addr::HeapCell(frontier));
                self.trail.push((
                    Ref::HeapCell(h),
                    HeapCellValue::Addr(Addr::HeapCell(h)),
                ));
            }
            Addr::StackCell(fr, sc) => {
                self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(frontier));
                self.target.stack()[fr][sc] = Addr::HeapCell(frontier);
                self.trail.push((
                    Ref::StackCell(fr, sc),
                    HeapCellValue::Addr(Addr::StackCell(fr, sc)),
                ));
            }
            Addr::AttrVar(h) => {
                let threshold = if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
                    self.target.threshold()
                } else {
                    frontier
                };

                self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(threshold));
                self.target[h] = HeapCellValue::Addr(Addr::HeapCell(threshold));
                self.trail.push((
                    Ref::AttrVar(h),
                    HeapCellValue::Addr(Addr::AttrVar(h)),
                ));

                if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
                    self.target.push(HeapCellValue::Addr(Addr::AttrVar(threshold)));

                    let list_val = self.target[h + 1].clone();
                    self.target.push(list_val);
                }
            }
            _ => unreachable!()
        }
    }

    fn copy_var(&mut self, addr: Addr) {
        let rd = self.target.store(self.target.deref(addr.clone()));

        match rd.clone() {
            Addr::AttrVar(h) | Addr::HeapCell(h) if h >= self.old_h => {
                *self.value_at_scan() = HeapCellValue::Addr(rd);
                self.scan += 1;
            }
            _ if addr == rd => {
                self.reinstantiate_var(addr, self.scan);
                self.scan += 1;
            }
            _ => {
                *self.value_at_scan() = HeapCellValue::Addr(rd);
            }
        }
    }

    fn copy_structure(&mut self, addr: usize) {
        match self.target[addr].clone() {
            HeapCellValue::NamedStr(arity, name, fixity) => {
                let threshold = self.target.threshold();

                *self.value_at_scan() = HeapCellValue::Addr(Addr::Str(threshold));
                self.target[addr] = HeapCellValue::Addr(Addr::Str(threshold));

                self.trail.push((
                    Ref::HeapCell(addr),
                    HeapCellValue::NamedStr(arity, name.clone(), fixity.clone()),
                ));

                self.target.push(HeapCellValue::NamedStr(arity, name, fixity));

                for i in 0..arity {
                    let hcv = self.target[addr + 1 + i].clone();
                    self.target.push(hcv);
                }
            }
            HeapCellValue::Addr(Addr::Str(addr)) => {
                *self.value_at_scan() = HeapCellValue::Addr(Addr::Str(addr))
            }
            _ => {}
        }

        self.scan += 1;
    }

    fn copy_term_impl(&mut self, addr: Addr) {
        self.scan = self.target.threshold();
        self.target.push(HeapCellValue::Addr(addr));

        while self.scan < self.target.threshold() {
            match self.value_at_scan().clone() {
                HeapCellValue::NamedStr(..) => self.scan += 1,
                HeapCellValue::Addr(addr) => match addr {
                    Addr::Lis(addr) => self.copy_list(addr),
                    addr @ Addr::AttrVar(_)
                  | addr @ Addr::HeapCell(_)
                  | addr @ Addr::StackCell(..) => self.copy_var(addr),
                    Addr::Str(addr) => self.copy_structure(addr),
                    Addr::Con(_) | Addr::DBRef(_) => self.scan += 1,
                },
            }
        }

        self.unwind_trail();
    }

    fn unwind_trail(&mut self) {
        for (r, value) in self.trail.drain(0..) {
            match r {
                Ref::AttrVar(h) | Ref::HeapCell(h) => self.target[h] = value,
                Ref::StackCell(fr, sc) => self.target.stack()[fr][sc] = value.as_addr(0),
            }
        }
    }
}
<|endoftext|>


<commit_before>#![feature(test)] // compiletest_rs requires this attribute
#![feature(once_cell)]

use compiletest_rs as compiletest;
use compiletest_rs::common::Mode as TestMode;

use std::env::{self, remove_var, set_var, var_os};
use std::ffi::{OsStr, OsString};
use std::fs;
use std::io;
use std::path::{Path, PathBuf};

mod cargo;

// whether to run internal tests or not
const RUN_INTERNAL_TESTS: bool = cfg!(feature = "internal-lints");

fn host_lib() -> PathBuf {
    option_env!("HOST_LIBS").map_or(cargo::CARGO_TARGET_DIR.join(env!("PROFILE")), PathBuf::from)
}

fn clippy_driver_path() -> PathBuf {
    option_env!("CLIPPY_DRIVER_PATH").map_or(cargo::TARGET_LIB.join("clippy-driver"), PathBuf::from)
}

// When we'll want to use `extern crate ..` for a dependency that is used
// both by the crate and the compiler itself, we can't simply pass -L flags
// as we'll get a duplicate matching versions. Instead, disambiguate with
// `--extern dep=path`.
// See https://github.com/rust-lang/rust-clippy/issues/4015.
//
// FIXME: We cannot use `cargo build --message-format=json` to resolve to dependency files.
//        Because it would force-rebuild if the options passed to `build` command is not the same
//        as what we manually pass to `cargo` invocation
fn third_party_crates() -> String {
    use std::collections::HashMap;
    static CRATES: &[&str] = &["serde", "serde_derive", "regex", "clippy_lints", "syn", "quote"];
    let dep_dir = cargo::TARGET_LIB.join("deps");
    let mut crates: HashMap<&str, PathBuf> = HashMap::with_capacity(CRATES.len());
    for entry in fs::read_dir(dep_dir).unwrap() {
        let path = match entry {
            Ok(entry) => entry.path(),
            Err(_) => continue,
        };
        if let Some(name) = path.file_name().and_then(OsStr::to_str) {
            for dep in CRATES {
                if name.starts_with(&format!("lib{}-", dep))
                    && name.rsplit('.').next().map(|ext| ext.eq_ignore_ascii_case("rlib")) == Some(true)
                {
                    if let Some(old) = crates.insert(dep, path.clone()) {
                        // Check which action should be done in order to remove compiled deps.
                        // If pre-installed version of compiler is used, `cargo clean` will do.
                        // Otherwise (for bootstrapped compiler), the dependencies directory
                        // must be removed manually.
                        let suggested_action = if std::env::var_os("RUSTC_BOOTSTRAP").is_some() {
                            "remove the stageN-tools directory"
                        } else {
                            "run `cargo clean`"
                        };

                        panic!(
                            "\n---------------------------------------------------\n\n \
                            Found multiple rlibs for crate `{}`: `{:?}` and `{:?}`.\n \
                            Probably, you need to {} before running tests again.\n \
                            \nFor details on that error see https://github.com/rust-lang/rust-clippy/issues/7343 \
                            \n---------------------------------------------------\n",
                            dep, old, path, suggested_action
                        );
                    }
                    break;
                }
            }
        }
    }

    let v: Vec<_> = crates
        .into_iter()
        .map(|(dep, path)| format!("--extern {}={}", dep, path.display()))
        .collect();
    v.join(" ")
}

fn default_config() -> compiletest::Config {
    let mut config = compiletest::Config::default();

    if let Ok(filters) = env::var("TESTNAME") {
        config.filters = filters.split(',').map(std::string::ToString::to_string).collect();
    }

    if let Some(path) = option_env!("RUSTC_LIB_PATH") {
        let path = PathBuf::from(path);
        config.run_lib_path = path.clone();
        config.compile_lib_path = path;
    }

    config.target_rustcflags = Some(format!(
        "--emit=metadata -L {0} -L {1} -Dwarnings -Zui-testing {2}",
        host_lib().join("deps").display(),
        cargo::TARGET_LIB.join("deps").display(),
        third_party_crates(),
    ));

    config.build_base = host_lib().join("test_build_base");
    config.rustc_path = clippy_driver_path();
    config
}

fn run_ui(cfg: &mut compiletest::Config) {
    cfg.mode = TestMode::Ui;
    cfg.src_base = Path::new("tests").join("ui");
    // use tests/clippy.toml
    let _g = VarGuard::set("CARGO_MANIFEST_DIR", std::fs::canonicalize("tests").unwrap());
    compiletest::run_tests(cfg);
}

fn run_internal_tests(cfg: &mut compiletest::Config) {
    // only run internal tests with the internal-tests feature
    if !RUN_INTERNAL_TESTS {
        return;
    }
    cfg.mode = TestMode::Ui;
    cfg.src_base = Path::new("tests").join("ui-internal");
    compiletest::run_tests(cfg);
}

fn run_ui_toml(config: &mut compiletest::Config) {
    fn run_tests(config: &compiletest::Config, mut tests: Vec<tester::TestDescAndFn>) -> Result<bool, io::Error> {
        let mut result = true;
        let opts = compiletest::test_opts(config);
        for dir in fs::read_dir(&config.src_base)? {
            let dir = dir?;
            if !dir.file_type()?.is_dir() {
                continue;
            }
            let dir_path = dir.path();
            let _g = VarGuard::set("CARGO_MANIFEST_DIR", &dir_path);
            for file in fs::read_dir(&dir_path)? {
                let file = file?;
                let file_path = file.path();
                if file.file_type()?.is_dir() {
                    continue;
                }
                if file_path.extension() != Some(OsStr::new("rs")) {
                    continue;
                }
                let paths = compiletest::common::TestPaths {
                    file: file_path,
                    base: config.src_base.clone(),
                    relative_dir: dir_path.file_name().unwrap().into(),
                };
                let test_name = compiletest::make_test_name(config, &paths);
                let index = tests
                    .iter()
                    .position(|test| test.desc.name == test_name)
                    .expect("The test should be in there");
                result &= tester::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
            }
        }
        Ok(result)
    }

    config.mode = TestMode::Ui;
    config.src_base = Path::new("tests").join("ui-toml").canonicalize().unwrap();

    let tests = compiletest::make_tests(config);

    let res = run_tests(config, tests);
    match res {
        Ok(true) => {},
        Ok(false) => panic!("Some tests failed"),
        Err(e) => {
            panic!("I/O failure during tests: {:?}", e);
        },
    }
}

fn run_ui_cargo(config: &mut compiletest::Config) {
    fn run_tests(
        config: &compiletest::Config,
        filters: &[String],
        mut tests: Vec<tester::TestDescAndFn>,
    ) -> Result<bool, io::Error> {
        let mut result = true;
        let opts = compiletest::test_opts(config);

        for dir in fs::read_dir(&config.src_base)? {
            let dir = dir?;
            if !dir.file_type()?.is_dir() {
                continue;
            }

            // Use the filter if provided
            let dir_path = dir.path();
            for filter in filters {
                if !dir_path.ends_with(filter) {
                    continue;
                }
            }

            for case in fs::read_dir(&dir_path)? {
                let case = case?;
                if !case.file_type()?.is_dir() {
                    continue;
                }

                let src_path = case.path().join("src");

                // When switching between branches, if the previous branch had a test
                // that the current branch does not have, the directory is not removed
                // because an ignored Cargo.lock file exists.
                if !src_path.exists() {
                    continue;
                }

                env::set_current_dir(&src_path)?;
                for file in fs::read_dir(&src_path)? {
                    let file = file?;
                    if file.file_type()?.is_dir() {
                        continue;
                    }

                    // Search for the main file to avoid running a test for each file in the project
                    let file_path = file.path();
                    match file_path.file_name().and_then(OsStr::to_str) {
                        Some("main.rs") => {},
                        _ => continue,
                    }
                    let _g = VarGuard::set("CLIPPY_CONF_DIR", case.path());
                    let paths = compiletest::common::TestPaths {
                        file: file_path,
                        base: config.src_base.clone(),
                        relative_dir: src_path.strip_prefix(&config.src_base).unwrap().into(),
                    };
                    let test_name = compiletest::make_test_name(config, &paths);
                    let index = tests
                        .iter()
                        .position(|test| test.desc.name == test_name)
                        .expect("The test should be in there");
                    result &= tester::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
                }
            }
        }
        Ok(result)
    }

    if cargo::is_rustc_test_suite() {
        return;
    }

    config.mode = TestMode::Ui;
    config.src_base = Path::new("tests").join("ui-cargo").canonicalize().unwrap();

    let tests = compiletest::make_tests(config);

    let current_dir = env::current_dir().unwrap();
    let res = run_tests(config, &config.filters, tests);
    env::set_current_dir(current_dir).unwrap();

    match res {
        Ok(true) => {},
        Ok(false) => panic!("Some tests failed"),
        Err(e) => {
            panic!("I/O failure during tests: {:?}", e);
        },
    }
}

fn prepare_env() {
    set_var("CLIPPY_DISABLE_DOCS_LINKS", "true");
    set_var("__CLIPPY_INTERNAL_TESTS", "true");
    //set_var("RUST_BACKTRACE", "0");
}

#[test]
fn compile_test() {
    prepare_env();
    let mut config = default_config();
    run_ui(&mut config);
    run_ui_toml(&mut config);
    run_ui_cargo(&mut config);
    run_internal_tests(&mut config);
}

/// Restores an env var on drop
#[must_use]
struct VarGuard {
    key: &'static str,
    value: Option<OsString>,
}

impl VarGuard {
    fn set(key: &'static str, val: impl AsRef<OsStr>) -> Self {
        let value = var_os(key);
        set_var(key, val);
        Self { key, value }
    }
}

impl Drop for VarGuard {
    fn drop(&mut self) {
        match self.value.as_deref() {
            None => remove_var(self.key),
            Some(value) => set_var(self.key, value),
        }
    }
}
<commit_msg>Add clippy_utils and if_chain to extern crate list<commit_after>#![feature(test)] // compiletest_rs requires this attribute
#![feature(once_cell)]

use compiletest_rs as compiletest;
use compiletest_rs::common::Mode as TestMode;

use std::env::{self, remove_var, set_var, var_os};
use std::ffi::{OsStr, OsString};
use std::fs;
use std::io;
use std::path::{Path, PathBuf};

mod cargo;

// whether to run internal tests or not
const RUN_INTERNAL_TESTS: bool = cfg!(feature = "internal-lints");

fn host_lib() -> PathBuf {
    option_env!("HOST_LIBS").map_or(cargo::CARGO_TARGET_DIR.join(env!("PROFILE")), PathBuf::from)
}

fn clippy_driver_path() -> PathBuf {
    option_env!("CLIPPY_DRIVER_PATH").map_or(cargo::TARGET_LIB.join("clippy-driver"), PathBuf::from)
}

// When we'll want to use `extern crate ..` for a dependency that is used
// both by the crate and the compiler itself, we can't simply pass -L flags
// as we'll get a duplicate matching versions. Instead, disambiguate with
// `--extern dep=path`.
// See https://github.com/rust-lang/rust-clippy/issues/4015.
//
// FIXME: We cannot use `cargo build --message-format=json` to resolve to dependency files.
//        Because it would force-rebuild if the options passed to `build` command is not the same
//        as what we manually pass to `cargo` invocation
fn third_party_crates() -> String {
    use std::collections::HashMap;
    static CRATES: &[&str] = &[
        "clippy_lints",
        "clippy_utils",
        "if_chain",
        "quote",
        "regex",
        "serde",
        "serde_derive",
        "syn",
    ];
    let dep_dir = cargo::TARGET_LIB.join("deps");
    let mut crates: HashMap<&str, PathBuf> = HashMap::with_capacity(CRATES.len());
    for entry in fs::read_dir(dep_dir).unwrap() {
        let path = match entry {
            Ok(entry) => entry.path(),
            Err(_) => continue,
        };
        if let Some(name) = path.file_name().and_then(OsStr::to_str) {
            for dep in CRATES {
                if name.starts_with(&format!("lib{}-", dep))
                    && name.rsplit('.').next().map(|ext| ext.eq_ignore_ascii_case("rlib")) == Some(true)
                {
                    if let Some(old) = crates.insert(dep, path.clone()) {
                        // Check which action should be done in order to remove compiled deps.
                        // If pre-installed version of compiler is used, `cargo clean` will do.
                        // Otherwise (for bootstrapped compiler), the dependencies directory
                        // must be removed manually.
                        let suggested_action = if std::env::var_os("RUSTC_BOOTSTRAP").is_some() {
                            "remove the stageN-tools directory"
                        } else {
                            "run `cargo clean`"
                        };

                        panic!(
                            "\n---------------------------------------------------\n\n \
                            Found multiple rlibs for crate `{}`: `{:?}` and `{:?}`.\n \
                            Probably, you need to {} before running tests again.\n \
                            \nFor details on that error see https://github.com/rust-lang/rust-clippy/issues/7343 \
                            \n---------------------------------------------------\n",
                            dep, old, path, suggested_action
                        );
                    }
                    break;
                }
            }
        }
    }

    let v: Vec<_> = crates
        .into_iter()
        .map(|(dep, path)| format!("--extern {}={}", dep, path.display()))
        .collect();
    v.join(" ")
}

fn default_config() -> compiletest::Config {
    let mut config = compiletest::Config::default();

    if let Ok(filters) = env::var("TESTNAME") {
        config.filters = filters.split(',').map(std::string::ToString::to_string).collect();
    }

    if let Some(path) = option_env!("RUSTC_LIB_PATH") {
        let path = PathBuf::from(path);
        config.run_lib_path = path.clone();
        config.compile_lib_path = path;
    }

    config.target_rustcflags = Some(format!(
        "--emit=metadata -L {0} -L {1} -Dwarnings -Zui-testing {2}",
        host_lib().join("deps").display(),
        cargo::TARGET_LIB.join("deps").display(),
        third_party_crates(),
    ));

    config.build_base = host_lib().join("test_build_base");
    config.rustc_path = clippy_driver_path();
    config
}

fn run_ui(cfg: &mut compiletest::Config) {
    cfg.mode = TestMode::Ui;
    cfg.src_base = Path::new("tests").join("ui");
    // use tests/clippy.toml
    let _g = VarGuard::set("CARGO_MANIFEST_DIR", std::fs::canonicalize("tests").unwrap());
    compiletest::run_tests(cfg);
}

fn run_internal_tests(cfg: &mut compiletest::Config) {
    // only run internal tests with the internal-tests feature
    if !RUN_INTERNAL_TESTS {
        return;
    }
    cfg.mode = TestMode::Ui;
    cfg.src_base = Path::new("tests").join("ui-internal");
    compiletest::run_tests(cfg);
}

fn run_ui_toml(config: &mut compiletest::Config) {
    fn run_tests(config: &compiletest::Config, mut tests: Vec<tester::TestDescAndFn>) -> Result<bool, io::Error> {
        let mut result = true;
        let opts = compiletest::test_opts(config);
        for dir in fs::read_dir(&config.src_base)? {
            let dir = dir?;
            if !dir.file_type()?.is_dir() {
                continue;
            }
            let dir_path = dir.path();
            let _g = VarGuard::set("CARGO_MANIFEST_DIR", &dir_path);
            for file in fs::read_dir(&dir_path)? {
                let file = file?;
                let file_path = file.path();
                if file.file_type()?.is_dir() {
                    continue;
                }
                if file_path.extension() != Some(OsStr::new("rs")) {
                    continue;
                }
                let paths = compiletest::common::TestPaths {
                    file: file_path,
                    base: config.src_base.clone(),
                    relative_dir: dir_path.file_name().unwrap().into(),
                };
                let test_name = compiletest::make_test_name(config, &paths);
                let index = tests
                    .iter()
                    .position(|test| test.desc.name == test_name)
                    .expect("The test should be in there");
                result &= tester::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
            }
        }
        Ok(result)
    }

    config.mode = TestMode::Ui;
    config.src_base = Path::new("tests").join("ui-toml").canonicalize().unwrap();

    let tests = compiletest::make_tests(config);

    let res = run_tests(config, tests);
    match res {
        Ok(true) => {},
        Ok(false) => panic!("Some tests failed"),
        Err(e) => {
            panic!("I/O failure during tests: {:?}", e);
        },
    }
}

fn run_ui_cargo(config: &mut compiletest::Config) {
    fn run_tests(
        config: &compiletest::Config,
        filters: &[String],
        mut tests: Vec<tester::TestDescAndFn>,
    ) -> Result<bool, io::Error> {
        let mut result = true;
        let opts = compiletest::test_opts(config);

        for dir in fs::read_dir(&config.src_base)? {
            let dir = dir?;
            if !dir.file_type()?.is_dir() {
                continue;
            }

            // Use the filter if provided
            let dir_path = dir.path();
            for filter in filters {
                if !dir_path.ends_with(filter) {
                    continue;
                }
            }

            for case in fs::read_dir(&dir_path)? {
                let case = case?;
                if !case.file_type()?.is_dir() {
                    continue;
                }

                let src_path = case.path().join("src");

                // When switching between branches, if the previous branch had a test
                // that the current branch does not have, the directory is not removed
                // because an ignored Cargo.lock file exists.
                if !src_path.exists() {
                    continue;
                }

                env::set_current_dir(&src_path)?;
                for file in fs::read_dir(&src_path)? {
                    let file = file?;
                    if file.file_type()?.is_dir() {
                        continue;
                    }

                    // Search for the main file to avoid running a test for each file in the project
                    let file_path = file.path();
                    match file_path.file_name().and_then(OsStr::to_str) {
                        Some("main.rs") => {},
                        _ => continue,
                    }
                    let _g = VarGuard::set("CLIPPY_CONF_DIR", case.path());
                    let paths = compiletest::common::TestPaths {
                        file: file_path,
                        base: config.src_base.clone(),
                        relative_dir: src_path.strip_prefix(&config.src_base).unwrap().into(),
                    };
                    let test_name = compiletest::make_test_name(config, &paths);
                    let index = tests
                        .iter()
                        .position(|test| test.desc.name == test_name)
                        .expect("The test should be in there");
                    result &= tester::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
                }
            }
        }
        Ok(result)
    }

    if cargo::is_rustc_test_suite() {
        return;
    }

    config.mode = TestMode::Ui;
    config.src_base = Path::new("tests").join("ui-cargo").canonicalize().unwrap();

    let tests = compiletest::make_tests(config);

    let current_dir = env::current_dir().unwrap();
    let res = run_tests(config, &config.filters, tests);
    env::set_current_dir(current_dir).unwrap();

    match res {
        Ok(true) => {},
        Ok(false) => panic!("Some tests failed"),
        Err(e) => {
            panic!("I/O failure during tests: {:?}", e);
        },
    }
}

fn prepare_env() {
    set_var("CLIPPY_DISABLE_DOCS_LINKS", "true");
    set_var("__CLIPPY_INTERNAL_TESTS", "true");
    //set_var("RUST_BACKTRACE", "0");
}

#[test]
fn compile_test() {
    prepare_env();
    let mut config = default_config();
    run_ui(&mut config);
    run_ui_toml(&mut config);
    run_ui_cargo(&mut config);
    run_internal_tests(&mut config);
}

/// Restores an env var on drop
#[must_use]
struct VarGuard {
    key: &'static str,
    value: Option<OsString>,
}

impl VarGuard {
    fn set(key: &'static str, val: impl AsRef<OsStr>) -> Self {
        let value = var_os(key);
        set_var(key, val);
        Self { key, value }
    }
}

impl Drop for VarGuard {
    fn drop(&mut self) {
        match self.value.as_deref() {
            None => remove_var(self.key),
            Some(value) => set_var(self.key, value),
        }
    }
}
<|endoftext|>


<commit_before>extern crate compiletest_rs as compiletest;

use std::path::PathBuf;

fn run_mode(mode: &'static str) {
    let mut config = compiletest::default_config();
    let cfg_mode = mode.parse().ok().expect("Invalid mode");
    config.target_rustcflags = Some("-L target/debug/".to_string());

    config.mode = cfg_mode;
    config.src_base = PathBuf::from(format!("tests/{}", mode));

    compiletest::run_tests(&config);
}

#[test]
fn compile_test() {
    run_mode("compile-fail");
}
<commit_msg>extended compile-test.rs to actually observe TESTNAME environment variable and filter tests if available<commit_after>extern crate compiletest_rs as compiletest;

use std::path::PathBuf;
use std::env::var;

fn run_mode(mode: &'static str) {
    let mut config = compiletest::default_config();

    let cfg_mode = mode.parse().ok().expect("Invalid mode");
    config.target_rustcflags = Some("-L target/debug/".to_owned());
	if let Ok(name) = var::<&str>("TESTNAME") {
		let s : String = name.to_owned();
		config.filter = Some(s)
	}

    config.mode = cfg_mode;
    config.src_base = PathBuf::from(format!("tests/{}", mode));

    compiletest::run_tests(&config);
}

#[test]
fn compile_test() {
    run_mode("compile-fail");
}
<|endoftext|>


<commit_before>//! The `select` macro.

use proc_macro_hack::proc_macro_hack;

#[doc(hidden)]
#[macro_export]
macro_rules! document_select_macro {
    ($item:item) => {
        /// Polls multiple futures and streams simultaneously, executing the branch
        /// for the future that finishes first. If multiple futures are ready,
        /// one will be pseudo-randomly selected at runtime. Futures directly
        /// passed to `select!` must be `Unpin` and implement `FusedFuture`.
        ///
        /// If an expression which yields a `Future` is passed to `select!`
        /// (e.g. an `async fn` call) instead of a `Future` by name the `Unpin`
        /// requirement is relaxed, since the macro will pin the resulting `Future`
        /// on the stack. However the `Future` returned by the expression must
        /// still implement `FusedFuture`. This difference is presented
        ///
        /// Futures and streams which are not already fused can be fused using the
        /// `.fuse()` method. Note, though, that fusing a future or stream directly
        /// in the call to `select!` will not be enough to prevent it from being
        /// polled after completion if the `select!` call is in a loop, so when
        /// `select!`ing in a loop, users should take care to `fuse()` outside of
        /// the loop.
        ///
        /// `select!` can be used as an expression and will return the return
        /// value of the selected branch. For this reason the return type of every
        /// branch in a `select!` must be the same.
        ///
        /// This macro is only usable inside of async functions, closures, and blocks.
        /// It is also gated behind the `async-await` feature of this library, which is
        /// _not_ activated by default.
        ///
        /// # Examples
        ///
        /// ```
        /// # futures::executor::block_on(async {
        /// use futures::future;
        /// use futures::select;
        /// let mut a = future::ready(4);
        /// let mut b = future::pending::<()>();
        ///
        /// let res = select! {
        ///     a_res = a => a_res + 1,
        ///     _ = b => 0,
        /// };
        /// assert_eq!(res, 5);
        /// # });
        /// ```
        ///
        /// ```
        /// # futures::executor::block_on(async {
        /// use futures::future;
        /// use futures::stream::{self, StreamExt};
        /// use futures::select;
        /// let mut st = stream::iter(vec![2]).fuse();
        /// let mut fut = future::pending::<()>();
        ///
        /// select! {
        ///     x = st.next() => assert_eq!(Some(2), x),
        ///     _ = fut => panic!(),
        /// };
        /// # });
        /// ```
        ///
        /// As described earlier, `select` can directly select on expressions
        /// which return `Future`s - even if those do not implement `Unpin`:
        ///
        /// ```
        /// # futures::executor::block_on(async {
        /// use futures::future::FutureExt;
        /// use futures::select;
        ///
        /// // Calling the following async fn returns a Future which does not
        /// // implement Unpin
        /// async fn async_identity_fn(arg: usize) -> usize {
        ///     arg
        /// }
        ///
        /// let res = select! {
        ///     a_res = async_identity_fn(62).fuse() => a_res + 1,
        ///     b_res = async_identity_fn(13).fuse() => b_res,
        /// };
        /// assert!(res == 63 || res == 12);
        /// # });
        /// ```
        ///
        /// If a similar async function is called outside of `select` to produce
        /// a `Future`, the `Future` must be pinned in order to be able to pass
        /// it to `select`. This can be achieved via `Box::pin` for pinning a
        /// `Future` on the heap or the `pin_mut!` macro for pinning a `Future`
        /// on the stack.
        ///
        /// ```
        /// # futures::executor::block_on(async {
        /// use futures::future::FutureExt;
        /// use futures::select;
        /// use pin_utils::pin_mut;
        ///
        /// // Calling the following async fn returns a Future which does not
        /// // implement Unpin
        /// async fn async_identity_fn(arg: usize) -> usize {
        ///     arg
        /// }
        ///
        /// let fut_1 = async_identity_fn(1).fuse();
        /// let fut_2 = async_identity_fn(2).fuse();
        /// let mut fut_1 = Box::pin(fut_1); // Pins the Future on the heap
        /// pin_mut!(fut_2); // Pins the Future on the stack
        ///
        /// let res = select! {
        ///     a_res = fut_1 => a_res,
        ///     b_res = fut_2 => b_res,
        /// };
        /// assert!(res == 1 || res == 2);
        /// # });
        /// ```
        ///
        /// `select` also accepts a `complete` branch and a `default` branch.
        /// `complete` will run if all futures and streams have already been
        /// exhausted. `default` will run if no futures or streams are
        /// immediately ready. `complete` takes priority over `default` in
        /// the case where all futures have completed.
        /// A motivating use-case for passing `Future`s by name as well as for
        /// `complete` blocks is to call `select!` in a loop, which is
        /// demonstrated in the following example:
        ///
        /// ```
        /// # futures::executor::block_on(async {
        /// use futures::future;
        /// use futures::select;
        /// let mut a_fut = future::ready(4);
        /// let mut b_fut = future::ready(6);
        /// let mut total = 0;
        ///
        /// loop {
        ///     select! {
        ///         a = a_fut => total += a,
        ///         b = b_fut => total += b,
        ///         complete => break,
        ///         default => panic!(), // never runs (futures run first, then complete)
        ///     };
        /// }
        /// assert_eq!(total, 10);
        /// # });
        /// ```
        ///
        /// Note that the futures that have been matched over can still be mutated
        /// from inside the `select!` block's branches. This can be used to implement
        /// more complex behavior such as timer resets or writing into the head of
        /// a stream.
        $item
    }
}

document_select_macro! {
    #[proc_macro_hack(support_nested)]
    pub use futures_macro::select;
}
<commit_msg>select! warning on recursion limit<commit_after>//! The `select` macro.

use proc_macro_hack::proc_macro_hack;

#[doc(hidden)]
#[macro_export]
macro_rules! document_select_macro {
    ($item:item) => {
        /// Polls multiple futures and streams simultaneously, executing the branch
        /// for the future that finishes first. If multiple futures are ready,
        /// one will be pseudo-randomly selected at runtime. Futures directly
        /// passed to `select!` must be `Unpin` and implement `FusedFuture`.
        ///
        /// If an expression which yields a `Future` is passed to `select!`
        /// (e.g. an `async fn` call) instead of a `Future` by name the `Unpin`
        /// requirement is relaxed, since the macro will pin the resulting `Future`
        /// on the stack. However the `Future` returned by the expression must
        /// still implement `FusedFuture`. This difference is presented
        ///
        /// Futures and streams which are not already fused can be fused using the
        /// `.fuse()` method. Note, though, that fusing a future or stream directly
        /// in the call to `select!` will not be enough to prevent it from being
        /// polled after completion if the `select!` call is in a loop, so when
        /// `select!`ing in a loop, users should take care to `fuse()` outside of
        /// the loop.
        ///
        /// `select!` can be used as an expression and will return the return
        /// value of the selected branch. For this reason the return type of every
        /// branch in a `select!` must be the same.
        ///
        /// This macro is only usable inside of async functions, closures, and blocks.
        /// It is also gated behind the `async-await` feature of this library, which is
        /// _not_ activated by default.
        ///
        /// **Warning**: `select!` relies on `proc-macro-hack`, and may require to set the
        /// compiler's recursion limit very high, e.g. `#![recursion_limit="1024"]`.
        ///
        /// # Examples
        ///
        /// ```
        /// # futures::executor::block_on(async {
        /// use futures::future;
        /// use futures::select;
        /// let mut a = future::ready(4);
        /// let mut b = future::pending::<()>();
        ///
        /// let res = select! {
        ///     a_res = a => a_res + 1,
        ///     _ = b => 0,
        /// };
        /// assert_eq!(res, 5);
        /// # });
        /// ```
        ///
        /// ```
        /// # futures::executor::block_on(async {
        /// use futures::future;
        /// use futures::stream::{self, StreamExt};
        /// use futures::select;
        /// let mut st = stream::iter(vec![2]).fuse();
        /// let mut fut = future::pending::<()>();
        ///
        /// select! {
        ///     x = st.next() => assert_eq!(Some(2), x),
        ///     _ = fut => panic!(),
        /// };
        /// # });
        /// ```
        ///
        /// As described earlier, `select` can directly select on expressions
        /// which return `Future`s - even if those do not implement `Unpin`:
        ///
        /// ```
        /// # futures::executor::block_on(async {
        /// use futures::future::FutureExt;
        /// use futures::select;
        ///
        /// // Calling the following async fn returns a Future which does not
        /// // implement Unpin
        /// async fn async_identity_fn(arg: usize) -> usize {
        ///     arg
        /// }
        ///
        /// let res = select! {
        ///     a_res = async_identity_fn(62).fuse() => a_res + 1,
        ///     b_res = async_identity_fn(13).fuse() => b_res,
        /// };
        /// assert!(res == 63 || res == 12);
        /// # });
        /// ```
        ///
        /// If a similar async function is called outside of `select` to produce
        /// a `Future`, the `Future` must be pinned in order to be able to pass
        /// it to `select`. This can be achieved via `Box::pin` for pinning a
        /// `Future` on the heap or the `pin_mut!` macro for pinning a `Future`
        /// on the stack.
        ///
        /// ```
        /// # futures::executor::block_on(async {
        /// use futures::future::FutureExt;
        /// use futures::select;
        /// use pin_utils::pin_mut;
        ///
        /// // Calling the following async fn returns a Future which does not
        /// // implement Unpin
        /// async fn async_identity_fn(arg: usize) -> usize {
        ///     arg
        /// }
        ///
        /// let fut_1 = async_identity_fn(1).fuse();
        /// let fut_2 = async_identity_fn(2).fuse();
        /// let mut fut_1 = Box::pin(fut_1); // Pins the Future on the heap
        /// pin_mut!(fut_2); // Pins the Future on the stack
        ///
        /// let res = select! {
        ///     a_res = fut_1 => a_res,
        ///     b_res = fut_2 => b_res,
        /// };
        /// assert!(res == 1 || res == 2);
        /// # });
        /// ```
        ///
        /// `select` also accepts a `complete` branch and a `default` branch.
        /// `complete` will run if all futures and streams have already been
        /// exhausted. `default` will run if no futures or streams are
        /// immediately ready. `complete` takes priority over `default` in
        /// the case where all futures have completed.
        /// A motivating use-case for passing `Future`s by name as well as for
        /// `complete` blocks is to call `select!` in a loop, which is
        /// demonstrated in the following example:
        ///
        /// ```
        /// # futures::executor::block_on(async {
        /// use futures::future;
        /// use futures::select;
        /// let mut a_fut = future::ready(4);
        /// let mut b_fut = future::ready(6);
        /// let mut total = 0;
        ///
        /// loop {
        ///     select! {
        ///         a = a_fut => total += a,
        ///         b = b_fut => total += b,
        ///         complete => break,
        ///         default => panic!(), // never runs (futures run first, then complete)
        ///     };
        /// }
        /// assert_eq!(total, 10);
        /// # });
        /// ```
        ///
        /// Note that the futures that have been matched over can still be mutated
        /// from inside the `select!` block's branches. This can be used to implement
        /// more complex behavior such as timer resets or writing into the head of
        /// a stream.
        $item
    }
}

document_select_macro! {
    #[proc_macro_hack(support_nested)]
    pub use futures_macro::select;
}
<|endoftext|>


<commit_before>use nalgebra::{Vector3, Repeat, Point3, FloatPoint, BaseFloat, ApproxEq};
use num::Zero;
use std::ops::AddAssign;
use std::ops::MulAssign;

/// Represents result of a steering behaviour computation. User can aggregate
/// more than one behaviour result into single acceleration struct.
pub struct SteeringAcceleration<T: BaseFloat + AddAssign + MulAssign + Copy + ApproxEq<T>> {
    /// linear acceleration component
    pub linear: Vector3<T>,
    /// angular acceleration component
    pub angular: T,
}

impl<T: BaseFloat + AddAssign + MulAssign + Copy + ApproxEq<T>> SteeringAcceleration<T> {
    /// Creates a steering acceleration struct using given linear and angular components
    fn new(linear_acceleration: Vector3<T>, angular_acceleration: T) -> SteeringAcceleration<T> {
        SteeringAcceleration {
            linear: linear_acceleration,
            angular: angular_acceleration,
        }
    }

    /// Tests whether both linear and angular acceleration compenents are zero
    fn is_zero(self: &Self) -> bool {
        self.angular.is_zero() && self.linear.is_zero()
    }

    /// Sets both compononents to zero
    fn set_zero(self: &mut Self) {
        self.angular = T::zero();
        self.linear = Vector3::zero();
    }

    ///
    fn add(self: &mut Self, other: SteeringAcceleration<T>) -> &mut Self {
        self.angular = self.angular + other.angular;
        self.linear += other.linear;
        self
    }

    ///
    fn scl(self: &mut Self, scale: T) -> &mut Self {
        self.angular = self.angular * scale;
        self.linear *= Vector3::repeat(scale);
        self
    }

    ///
    fn mulAdd(self : &mut Self, other : SteeringAcceleration<T>, scale : T)-> &mut Self{
        self.angular = self.angular + (other.angular * scale);
        self.linear += other.linear * Vector3::repeat(scale);
        self
    }

    ///
    fn calculate_square_magnitude(self :  &Self)->T{
        self.linear.as_point().distance_squared(&Vector3::zero().to_point()) + self.angular * self.angular
    }

    ///
    fn calculate_magnitude(self : &Self)->T {
        self.calculate_square_magnitude().sqrt()
    }

}
<commit_msg>steering acceleration calculator trait added<commit_after>use nalgebra::{Vector3, Repeat, Point3, FloatPoint, BaseFloat, ApproxEq};
use num::Zero;
use std::ops::AddAssign;
use std::ops::MulAssign;

/// Represents result of a steering behaviour computation. User can aggregate
/// more than one behaviour result into single acceleration struct.
pub struct SteeringAcceleration<T: BaseFloat + ApproxEq<T>> {
    /// linear acceleration component
    pub linear: Vector3<T>,
    /// angular acceleration component
    pub angular: T,
}

impl<T: BaseFloat + ApproxEq<T>> SteeringAcceleration<T> {
    /// Creates a steering acceleration struct using given linear and angular components
    fn new(linear_acceleration: Vector3<T>, angular_acceleration: T) -> SteeringAcceleration<T> {
        SteeringAcceleration {
            linear: linear_acceleration,
            angular: angular_acceleration,
        }
    }

    /// Tests whether both linear and angular acceleration compenents are zero
    fn is_zero(self: &Self) -> bool {
        self.angular.is_zero() && self.linear.is_zero()
    }

    /// Sets both compononents to zero
    fn set_zero(self: &mut Self) -> &mut Self {
        self.angular = T::zero();
        self.linear = Vector3::zero();
        self
    }

    ///
    fn add(self: &mut Self, other: SteeringAcceleration<T>) -> &mut Self {
        self.angular = self.angular + other.angular;
        self.linear += other.linear;
        self
    }

    ///
    fn scl(self: &mut Self, scale: T) -> &mut Self {
        self.angular = self.angular * scale;
        self.linear *= Vector3::repeat(scale);
        self
    }

    ///
    fn mulAdd(self: &mut Self, other: SteeringAcceleration<T>, scale: T) -> &mut Self {
        self.angular = self.angular + (other.angular * scale);
        self.linear += other.linear * Vector3::repeat(scale);
        self
    }

    ///
    fn calculate_square_magnitude(self: &Self) -> T {
        self.linear.as_point().distance_squared(&Vector3::zero().to_point()) +
        self.angular * self.angular
    }

    ///
    fn calculate_magnitude(self: &Self) -> T {
        self.calculate_square_magnitude().sqrt()
    }
}

pub trait SteeringAccelerationCalculator<T: BaseFloat + ApproxEq<T>> {
    fn calculate_steering<'a>(self: &mut Self,
                              steering_acceleration: &'a mut SteeringAcceleration<T>)
                              -> &'a mut SteeringAcceleration<T> {
        if self.is_enabled() {
            self.calculate_real_steering(steering_acceleration)
        } else {
            steering_acceleration.set_zero()
        }
    }
    fn calculate_real_steering<'a>(self: &mut Self,
                                   steering_acceleration: &'a mut SteeringAcceleration<T>)
                                   -> &'a mut SteeringAcceleration<T>;
    fn is_enabled(self: &Self) -> bool;
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Chef Software Inc. and/or applicable contributors
//
// 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.

extern crate env_logger;
extern crate habitat_core as core;
extern crate habitat_launcher as launcher;

use std::env;
use std::process;

use launcher::server;

fn main() {
    env_logger::init();

    let args: Vec<String> = env::args().skip(1).collect();
    set_global_logging_options(&args);

    if let Err(err) = server::run(args) {
        println!("{}", err);
        process::exit(1);
    }
}

/// In order to ensure that log output from the Launcher itself
/// behaves the same as the Supervisor, we'll eavesdrop on the
/// arguments being passed to the Supervisor in order to configure
/// ourselves.
fn set_global_logging_options(args: &Vec<String>) {
    // Yeah, this is pretty weird, but it comes out of how the
    // hab-launch, hab, and hab-sup binaries interact.
    //
    // These flags are defined with CLAP on `hab`, so they can be
    // passed through `hab-launch` (and intercepted here), before
    // being passed on to `hab-sup`, where they are _also_ defined.
    //
    // What a tangled web we weave!

    // Note that each of these options has only one form, so we don't
    // have to check for long _and_ short options, for example.
    if args.contains(&String::from("--no-color")) {
        core::output::set_no_color(true);
    }
    if args.contains(&String::from("--json-logging")) {
        core::output::set_json(true);
    }
    if args.contains(&String::from("-v")) {
        core::output::set_verbose(true);
    }
}
<commit_msg>Make environment-variable-based logging work in launcher<commit_after>// Copyright (c) 2017 Chef Software Inc. and/or applicable contributors
//
// 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.

extern crate env_logger;
extern crate habitat_core as core;
extern crate habitat_launcher as launcher;
#[macro_use]
extern crate log;

use std::env;
use std::process;

use launcher::server;

fn main() {
    env_logger::init();

    let args: Vec<String> = env::args().skip(1).collect();
    set_global_logging_options(&args);

    if let Err(err) = server::run(args) {
        println!("{}", err);
        process::exit(1);
    }
}

/// In order to ensure that log output from the Launcher itself
/// behaves the same as the Supervisor, we'll eavesdrop on the
/// arguments being passed to the Supervisor in order to configure
/// ourselves.
fn set_global_logging_options(args: &Vec<String>) {
    // Yeah, this is pretty weird, but it comes out of how the
    // hab-launch, hab, and hab-sup binaries interact.
    //
    // These flags are defined with CLAP on `hab`, so they can be
    // passed through `hab-launch` (and intercepted here), before
    // being passed on to `hab-sup`, where they are _also_ defined.
    //
    // What a tangled web we weave!

    // Note that each of these options has only one form, so we don't
    // have to check for long _and_ short options, for example.
    if args.contains(&String::from("--no-color")) {
        core::output::set_no_color(true);
    }
    if args.contains(&String::from("--json-logging")) {
        core::output::set_json(true);
    }
    if args.contains(&String::from("-v")) {
        core::output::set_verbose(true);
    }
}
<|endoftext|>